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));
+  }
+}

Reply via email to