This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new 893280fb0a fix NPE when invalid file in text file input, fixes #7314
(#7315)
893280fb0a is described below
commit 893280fb0ad7b91d4d193398e751bcfd56e50554
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Fri Jun 19 11:50:42 2026 +0200
fix NPE when invalid file in text file input, fixes #7314 (#7315)
---
.../fileinput/text/TextFileInputDialog.java | 25 ++++++-
.../common/GetFieldsSampleDataDialog.java | 15 ++--
.../common/ICsvInputAwareTransformDialog.java | 6 ++
.../common/ICsvInputAwareTransformDialogTest.java | 81 ++++++++++++++++++++++
4 files changed, 120 insertions(+), 7 deletions(-)
diff --git
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java
index cfaae494d7..a3a199fce1 100644
---
a/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java
+++
b/plugins/transforms/textfile/src/main/java/org/apache/hop/pipeline/transforms/fileinput/text/TextFileInputDialog.java
@@ -121,6 +121,8 @@ public class TextFileInputDialog extends BaseTransformDialog
public static final String CONST_SYSTEM_DIALOG_ERROR_TITLE =
"System.Dialog.Error.Title";
public static final String CONST_SYSTEM_BUTTON_BROWSE =
"System.Button.Browse";
public static final String CONST_SYSTEM_LABEL_EXTENSION =
"System.Label.Extension";
+ public static final String
TEXT_FILE_INPUT_DIALOG_NO_VALID_FILE_DIALOG_MESSAGE =
+ "TextFileInputDialog.NoValidFile.DialogMessage";
private CTabFolder wTabFolder;
@@ -2620,6 +2622,22 @@ public class TextFileInputDialog extends
BaseTransformDialog
private void get() {
if (wFiletype.getText().equalsIgnoreCase("CSV")) {
+ TextFileInputMeta oneMeta = new TextFileInputMeta();
+ getInfo(oneMeta, true);
+ try {
+ if (oneMeta.getFileInputList(variables).nrOfFiles() == 0) {
+ MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
+ mb.setMessage(
+ BaseMessages.getString(PKG,
TEXT_FILE_INPUT_DIALOG_NO_VALID_FILE_DIALOG_MESSAGE));
+ mb.setText(BaseMessages.getString(PKG,
CONST_SYSTEM_DIALOG_ERROR_TITLE));
+ mb.open();
+ return;
+ }
+ } catch (Exception e) {
+ displayErrorDialog(
+ new HopException(e),
"TextFileInputDialog.ErrorGettingData.DialogMessage");
+ return;
+ }
getFields();
}
}
@@ -2805,7 +2823,8 @@ public class TextFileInputDialog extends
BaseTransformDialog
}
} else {
MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
- mb.setMessage(BaseMessages.getString(PKG,
"TextFileInputDialog.NoValidFile.DialogMessage"));
+ mb.setMessage(
+ BaseMessages.getString(PKG,
TEXT_FILE_INPUT_DIALOG_NO_VALID_FILE_DIALOG_MESSAGE));
mb.setText(BaseMessages.getString(PKG,
CONST_SYSTEM_DIALOG_ERROR_TITLE));
mb.open();
}
@@ -3316,6 +3335,10 @@ public class TextFileInputDialog extends
BaseTransformDialog
CompressionInputStream inputStream = null;
try {
FileObject fileObject = meta.getHeaderFileObject(variables);
+ if (fileObject == null) {
+ logError(BaseMessages.getString(PKG,
TEXT_FILE_INPUT_DIALOG_NO_VALID_FILE_DIALOG_MESSAGE));
+ return null;
+ }
fileInputStream = HopVfs.getInputStream(fileObject);
ICompressionProvider provider =
CompressionProviderFactory.getInstance()
diff --git
a/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/GetFieldsSampleDataDialog.java
b/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/GetFieldsSampleDataDialog.java
index cc28b5be4c..ebdee08e4c 100644
---
a/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/GetFieldsSampleDataDialog.java
+++
b/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/GetFieldsSampleDataDialog.java
@@ -56,24 +56,27 @@ public class GetFieldsSampleDataDialog extends
EnterNumberDialog {
@Override
protected void ok() {
+ final boolean showSample;
try {
samples = Integer.parseInt(wNumber.getText());
- handleOk(samples);
- dispose();
+ showSample = wCheckbox != null && wCheckbox.getSelection();
} catch (Exception e) {
MessageBox mb = new MessageBox(getParent(), SWT.OK | SWT.ICON_ERROR);
mb.setMessage(BaseMessages.getString(PKG, "Dialog.Error.EnterInteger"));
mb.setText(BaseMessages.getString(PKG, "Dialog.Error.Header"));
mb.open();
wNumber.selectAll();
+ return;
}
+ dispose();
+ handleOk(samples, showSample);
}
- protected void handleOk(final int samples) {
+ protected void handleOk(final int samples, final boolean showSample) {
if (samples >= 0) {
String message =
parentDialog.loadFields(parentDialog.getPopulatedMeta(), samples,
reloadAllFields);
- if (wCheckbox != null && wCheckbox.getSelection()) {
+ if (showSample) {
if (StringUtils.isNotBlank(message)) {
final EnterTextDialog etd =
new EnterTextDialog(
@@ -87,8 +90,8 @@ public class GetFieldsSampleDataDialog extends
EnterNumberDialog {
etd.setModal();
etd.open();
} else {
-
- MessageBox box = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
+ // This dialog has already been disposed, so parent the message to
the transform dialog.
+ MessageBox box = new MessageBox(parentDialog.getShell(), SWT.OK |
SWT.ICON_ERROR);
box.setText(BaseMessages.getString(PKG,
"System.Dialog.Error.Title"));
box.setMessage(
BaseMessages.getString(PKG,
"GetFieldsSampleDataDialog.ScanResults.Error.Message"));
diff --git
a/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialog.java
b/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialog.java
index 507dbd1b44..57e681b61c 100644
---
a/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialog.java
+++
b/ui/src/main/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialog.java
@@ -135,6 +135,9 @@ public interface ICsvInputAwareTransformDialog {
*/
default InputStreamReader getReader(
final ICsvInputAwareMeta meta, final InputStream inputStream) {
+ if (inputStream == null) {
+ return null;
+ }
InputStreamReader reader = null;
try {
String realEncoding = getVariables().resolve(meta.getEncoding());
@@ -163,6 +166,9 @@ public interface ICsvInputAwareTransformDialog {
default String loadFieldsImpl(final ICsvInputAwareMeta meta, final int
samples) {
InputStream inputStream = getInputStream(meta);
+ if (inputStream == null) {
+ return null;
+ }
try {
final InputStreamReader reader = getReader(meta, inputStream);
final ICsvInputAwareImportProgressDialog pd =
diff --git
a/ui/src/test/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialogTest.java
b/ui/src/test/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialogTest.java
new file mode 100644
index 0000000000..5d4b0f84f6
--- /dev/null
+++
b/ui/src/test/java/org/apache/hop/ui/pipeline/transform/common/ICsvInputAwareTransformDialogTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hop.ui.pipeline.transform.common;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.transforms.common.ICsvInputAwareMeta;
+import org.junit.jupiter.api.Test;
+
+class ICsvInputAwareTransformDialogTest {
+
+ /**
+ * Minimal implementation that simulates a file which cannot be opened (e.g.
it does not exist),
+ * in which case {@link #getInputStream(ICsvInputAwareMeta)} returns null.
+ */
+ private static class NoFileDialog implements ICsvInputAwareTransformDialog {
+ @Override
+ public InputStream getInputStream(final ICsvInputAwareMeta meta) {
+ return null; // file does not exist / cannot be read
+ }
+
+ @Override
+ public ICsvInputAwareImportProgressDialog getCsvImportProgressDialog(
+ final ICsvInputAwareMeta meta, final int samples, final
InputStreamReader reader) {
+ throw new AssertionError("should not be reached when there is no input
stream");
+ }
+
+ @Override
+ public LogChannel getLogChannel() {
+ return null;
+ }
+
+ @Override
+ public PipelineMeta getPipelineMeta() {
+ return null;
+ }
+
+ @Override
+ public IVariables getVariables() {
+ return new Variables();
+ }
+ }
+
+ /** A null input stream (missing file) must yield a null reader, not a
NullPointerException. */
+ @Test
+ void getReaderReturnsNullForNullInputStream() {
+ final NoFileDialog dlg = new NoFileDialog();
+ assertNull(dlg.getReader(null, null));
+ }
+
+ /**
+ * When the file cannot be opened, loading fields must return cleanly (null)
instead of throwing a
+ * NullPointerException while building the reader or closing the (null)
input stream.
+ */
+ @Test
+ void loadFieldsImplReturnsNullWhenFileCannotBeOpened() {
+ final NoFileDialog dlg = new NoFileDialog();
+ assertNull(dlg.loadFieldsImpl((ICsvInputAwareMeta) null, 100));
+ }
+}