This is an automated email from the ASF dual-hosted git repository.

bamaer 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 19e9ce7bbe UDJC test pipeline should have info and output transforms, 
fixes #4584 (#8586)
19e9ce7bbe is described below

commit 19e9ce7bbe99bca7171607b0bbcdffe52df9b92e
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Fri Sep 25 11:54:28 2026 +0200

    UDJC test pipeline should have info and output transforms, fixes #4584 
(#8586)
---
 .../UserDefinedJavaClassDialog.java                | 107 +--------
 .../UserDefinedJavaClassTestPipeline.java          | 239 +++++++++++++++++++++
 .../UserDefinedJavaClassTestPipelineTest.java      | 214 ++++++++++++++++++
 3 files changed, 464 insertions(+), 96 deletions(-)

diff --git 
a/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassDialog.java
 
b/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassDialog.java
index 2e922c1169..b698329d37 100644
--- 
a/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassDialog.java
+++ 
b/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassDialog.java
@@ -17,11 +17,9 @@
 
 package org.apache.hop.pipeline.transforms.userdefinedjavaclass;
 
-import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Date;
 import java.util.EnumMap;
 import java.util.List;
 import java.util.Map;
@@ -29,8 +27,6 @@ import org.apache.hop.core.Const;
 import org.apache.hop.core.Props;
 import org.apache.hop.core.exception.HopException;
 import org.apache.hop.core.exception.HopXmlException;
-import org.apache.hop.core.plugins.PluginRegistry;
-import org.apache.hop.core.plugins.TransformPluginType;
 import org.apache.hop.core.row.IRowMeta;
 import org.apache.hop.core.row.IValueMeta;
 import org.apache.hop.core.row.value.ValueMetaFactory;
@@ -38,11 +34,9 @@ import org.apache.hop.core.util.Utils;
 import org.apache.hop.core.variables.IVariables;
 import org.apache.hop.i18n.BaseMessages;
 import org.apache.hop.pipeline.Pipeline;
-import org.apache.hop.pipeline.PipelineHopMeta;
 import org.apache.hop.pipeline.PipelineMeta;
 import org.apache.hop.pipeline.transform.TransformMeta;
 import org.apache.hop.pipeline.transforms.janino.JaninoMeta;
-import org.apache.hop.pipeline.transforms.rowgenerator.GeneratorField;
 import org.apache.hop.pipeline.transforms.rowgenerator.RowGeneratorMeta;
 import 
org.apache.hop.pipeline.transforms.userdefinedjavaclass.UserDefinedJavaClassCodeSnippets.Category;
 import 
org.apache.hop.pipeline.transforms.userdefinedjavaclass.UserDefinedJavaClassCodeSnippets.Snippet;
@@ -1305,7 +1299,6 @@ public class UserDefinedJavaClassDialog extends 
BaseTransformDialog {
   }
 
   private boolean test() {
-    PluginRegistry registry = PluginRegistry.getInstance();
     String scriptTransformName = wTransformName.getText();
 
     if (!checkForTransformClass()) {
@@ -1340,8 +1333,10 @@ public class UserDefinedJavaClassDialog extends 
BaseTransformDialog {
         return false;
       }
 
-      // What fields are coming into the transform?
-      IRowMeta rowMeta = pipelineMeta.getPrevTransformFields(variables, 
transformName).clone();
+      // What fields are coming into the transform over the main input?
+      IRowMeta rowMeta =
+          UserDefinedJavaClassTestPipeline.getMainInputFields(
+              variables, pipelineMeta, transformName, udjcMeta);
       if (rowMeta != null) {
         // Create a new RowGenerator transform to generate rows for the test
         // data...
@@ -1349,101 +1344,21 @@ public class UserDefinedJavaClassDialog extends 
BaseTransformDialog {
         // Otherwise he/she has to key in the same test data all the
         // time
         if (genMeta == null) {
-          genMeta = new RowGeneratorMeta();
-          genMeta.setRowLimit("10");
-          for (int i = 0; i < rowMeta.size(); i++) {
-            IValueMeta valueMeta = rowMeta.getValueMeta(i);
-            if (valueMeta.isStorageBinaryString()) {
-              valueMeta.setStorageType(IValueMeta.STORAGE_TYPE_NORMAL);
-            }
-            GeneratorField field = new GeneratorField();
-            field.setName(valueMeta.getName());
-            field.setType(valueMeta.getTypeDesc());
-            field.setLength(valueMeta.getLength());
-            field.setPrecision(valueMeta.getPrecision());
-            field.setCurrency(valueMeta.getCurrencySymbol());
-            field.setDecimal(valueMeta.getDecimalSymbol());
-            field.setGroup(valueMeta.getGroupingSymbol());
-
-            String string = null;
-            switch (valueMeta.getType()) {
-              case IValueMeta.TYPE_DATE:
-                field.setFormat("yyyy/MM/dd HH:mm:ss");
-                valueMeta.setConversionMask(field.getFormat());
-                string = valueMeta.getString(new Date());
-                break;
-              case IValueMeta.TYPE_STRING:
-                string = "test value test value";
-                break;
-              case IValueMeta.TYPE_INTEGER:
-                field.setFormat("#");
-                valueMeta.setConversionMask(field.getFormat());
-                string = valueMeta.getString(0L);
-                break;
-              case IValueMeta.TYPE_NUMBER:
-                field.setFormat("#.#");
-                valueMeta.setConversionMask(field.getFormat());
-                string = valueMeta.getString(0.0D);
-                break;
-              case IValueMeta.TYPE_BIGNUMBER:
-                field.setFormat("#.#");
-                valueMeta.setConversionMask(field.getFormat());
-                string = valueMeta.getString(BigDecimal.ZERO);
-                break;
-              case IValueMeta.TYPE_BOOLEAN:
-                string = valueMeta.getString(Boolean.TRUE);
-                break;
-              case IValueMeta.TYPE_BINARY:
-                string =
-                    valueMeta.getString(
-                        new byte[] {
-                          65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
-                        });
-                break;
-              default:
-                break;
-            }
-
-            field.setValue(string);
-            genMeta.getFields().add(field);
-          }
+          genMeta = 
UserDefinedJavaClassTestPipeline.createTestDataGenerator(rowMeta);
         }
-        TransformMeta genTransform =
-            new TransformMeta(
-                registry.getPluginId(TransformPluginType.class, genMeta),
-                "## TEST DATA ##",
-                genMeta);
-        genTransform.setLocation(50, 50);
-
-        TransformMeta scriptTransform =
-            new TransformMeta(
-                registry.getPluginId(TransformPluginType.class, udjcMeta),
-                Const.NVL(scriptTransformName, "## SCRIPT ##"),
-                udjcMeta);
-        scriptTransformName = scriptTransform.getName();
-        scriptTransform.setLocation(150, 50);
-
-        // Create a hop between both transforms...
-        //
-        PipelineHopMeta hop = new PipelineHopMeta(genTransform, 
scriptTransform);
-
-        // Generate a new test pipeline...
-        //
-        PipelineMeta pipelineMeta = new PipelineMeta();
-        pipelineMeta.setName(wTransformName.getText() + " - PREVIEW");
-        pipelineMeta.addTransform(genTransform);
-        pipelineMeta.addTransform(scriptTransform);
-        pipelineMeta.addPipelineHop(hop);
+        scriptTransformName = Const.NVL(scriptTransformName, "## SCRIPT ##");
+        PipelineMeta testPipelineMeta =
+            UserDefinedJavaClassTestPipeline.build(
+                variables, pipelineMeta, scriptTransformName, udjcMeta, 
genMeta);
+        testPipelineMeta.setName(wTransformName.getText() + " - PREVIEW");
 
-        // OK, now we ask the user to edit this dialog...
-        //
         // Now run this pipeline and grab the results...
         //
         PipelinePreviewProgressDialog progressDialog =
             new PipelinePreviewProgressDialog(
                 shell,
                 variables,
-                pipelineMeta,
+                testPipelineMeta,
                 new String[] {
                   scriptTransformName,
                 },
diff --git 
a/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassTestPipeline.java
 
b/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassTestPipeline.java
new file mode 100644
index 0000000000..9a0b1eb518
--- /dev/null
+++ 
b/plugins/transforms/janino/src/main/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassTestPipeline.java
@@ -0,0 +1,239 @@
+/*
+ * 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.pipeline.transforms.userdefinedjavaclass;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.exception.HopValueException;
+import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.plugins.TransformPluginType;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.util.Utils;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.pipeline.PipelineHopMeta;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.pipeline.transforms.dummy.DummyMeta;
+import org.apache.hop.pipeline.transforms.rowgenerator.GeneratorField;
+import org.apache.hop.pipeline.transforms.rowgenerator.RowGeneratorMeta;
+
+/**
+ * Builds the throwaway pipeline behind the "Test class" button of the User 
Defined Java Class
+ * dialog: generated test data for the main input, and stand-ins for the info 
and target transforms
+ * the class reads from and writes to by name.
+ */
+public final class UserDefinedJavaClassTestPipeline {
+  public static final String TEST_DATA_TRANSFORM_NAME = "## TEST DATA ##";
+
+  private UserDefinedJavaClassTestPipeline() {}
+
+  /**
+   * @param variables the variables to resolve the source pipeline's fields 
with
+   * @param sourcePipelineMeta the pipeline the transform lives in, used to 
derive field layouts
+   * @param scriptTransformName the name of the transform under test
+   * @param udjcMeta the metadata of the transform under test, as currently 
edited
+   * @param mainGenMeta the test data generator for the main input
+   * @return the test pipeline
+   */
+  public static PipelineMeta build(
+      IVariables variables,
+      PipelineMeta sourcePipelineMeta,
+      String scriptTransformName,
+      UserDefinedJavaClassMeta udjcMeta,
+      RowGeneratorMeta mainGenMeta)
+      throws HopTransformException {
+    PluginRegistry registry = PluginRegistry.getInstance();
+
+    TransformMeta genTransform =
+        new TransformMeta(
+            registry.getPluginId(TransformPluginType.class, mainGenMeta),
+            TEST_DATA_TRANSFORM_NAME,
+            mainGenMeta);
+    genTransform.setLocation(50, 50);
+
+    TransformMeta scriptTransform =
+        new TransformMeta(
+            registry.getPluginId(TransformPluginType.class, udjcMeta),
+            scriptTransformName,
+            udjcMeta);
+    scriptTransform.setLocation(250, 50);
+
+    PipelineMeta testPipelineMeta = new PipelineMeta();
+    testPipelineMeta.addTransform(genTransform);
+    testPipelineMeta.addTransform(scriptTransform);
+    testPipelineMeta.addPipelineHop(new PipelineHopMeta(genTransform, 
scriptTransform));
+
+    // The class can read from info transforms and write to target transforms 
by name.
+    // Those don't exist in the test pipeline, so stand in for them: generated 
test data
+    // for every info transform, a dummy for every target transform.
+    //
+    int y = 150;
+    for (InfoTransformDefinition infoDefinition : 
udjcMeta.getInfoTransformDefinitions()) {
+      String infoTransformName = infoDefinition.getTransformName();
+      if (Utils.isEmpty(infoTransformName)
+          || testPipelineMeta.findTransform(infoTransformName) != null) {
+        continue;
+      }
+      IRowMeta infoRowMeta = sourcePipelineMeta.getTransformFields(variables, 
infoTransformName);
+      RowGeneratorMeta infoGenMeta =
+          createTestDataGenerator(infoRowMeta == null ? new RowMeta() : 
infoRowMeta.clone());
+      TransformMeta infoTransform =
+          new TransformMeta(
+              registry.getPluginId(TransformPluginType.class, infoGenMeta),
+              infoTransformName,
+              infoGenMeta);
+      infoTransform.setLocation(50, y);
+      y += 100;
+      testPipelineMeta.addTransform(infoTransform);
+      testPipelineMeta.addPipelineHop(new PipelineHopMeta(infoTransform, 
scriptTransform));
+    }
+    y = 150;
+    for (TargetTransformDefinition targetDefinition : 
udjcMeta.getTargetTransformDefinitions()) {
+      String targetTransformName = targetDefinition.transformName;
+      if (Utils.isEmpty(targetTransformName)
+          || testPipelineMeta.findTransform(targetTransformName) != null) {
+        continue;
+      }
+      DummyMeta dummyMeta = new DummyMeta();
+      TransformMeta targetTransform =
+          new TransformMeta(
+              registry.getPluginId(TransformPluginType.class, dummyMeta),
+              targetTransformName,
+              dummyMeta);
+      targetTransform.setLocation(450, y);
+      y += 100;
+      testPipelineMeta.addTransform(targetTransform);
+      testPipelineMeta.addPipelineHop(new PipelineHopMeta(scriptTransform, 
targetTransform));
+    }
+
+    // Point the info and target definitions at the stand-ins so the info hops 
are
+    // recognised as such and the class finds its row sets.
+    //
+    udjcMeta.searchInfoAndTargetTransforms(testPipelineMeta.getTransforms());
+
+    return testPipelineMeta;
+  }
+
+  /**
+   * The fields entering the transform over its main input, leaving out the 
info transforms
+   * configured in the given (possibly not yet saved) metadata.
+   */
+  public static IRowMeta getMainInputFields(
+      IVariables variables,
+      PipelineMeta pipelineMeta,
+      String transformName,
+      UserDefinedJavaClassMeta udjcMeta)
+      throws HopTransformException {
+    TransformMeta thisTransform = pipelineMeta.findTransform(transformName);
+    if (thisTransform == null) {
+      return null;
+    }
+    List<String> infoTransformNames = new ArrayList<>();
+    for (InfoTransformDefinition infoDefinition : 
udjcMeta.getInfoTransformDefinitions()) {
+      infoTransformNames.add(Const.NVL(infoDefinition.getTransformName(), ""));
+    }
+
+    IRowMeta rowMeta = new RowMeta();
+    for (TransformMeta prevTransform : 
pipelineMeta.findPreviousTransforms(thisTransform, true)) {
+      if (Const.indexOfString(prevTransform.getName(), infoTransformNames) >= 
0) {
+        continue;
+      }
+      IRowMeta prevRowMeta =
+          pipelineMeta.getTransformFields(variables, prevTransform, 
thisTransform, null);
+      for (IValueMeta valueMeta : prevRowMeta.getValueMetaList()) {
+        if (rowMeta.searchValueMeta(valueMeta.getName()) == null) {
+          rowMeta.addValueMeta(valueMeta.clone());
+        }
+      }
+    }
+    return rowMeta;
+  }
+
+  /** A row generator producing 10 rows of test values for the given fields. */
+  public static RowGeneratorMeta createTestDataGenerator(IRowMeta rowMeta) {
+    RowGeneratorMeta generatorMeta = new RowGeneratorMeta();
+    generatorMeta.setRowLimit("10");
+    for (int i = 0; i < rowMeta.size(); i++) {
+      IValueMeta valueMeta = rowMeta.getValueMeta(i);
+      if (valueMeta.isStorageBinaryString()) {
+        valueMeta.setStorageType(IValueMeta.STORAGE_TYPE_NORMAL);
+      }
+      GeneratorField field = new GeneratorField();
+      field.setName(valueMeta.getName());
+      field.setType(valueMeta.getTypeDesc());
+      field.setLength(valueMeta.getLength());
+      field.setPrecision(valueMeta.getPrecision());
+      field.setCurrency(valueMeta.getCurrencySymbol());
+      field.setDecimal(valueMeta.getDecimalSymbol());
+      field.setGroup(valueMeta.getGroupingSymbol());
+
+      String string = null;
+      try {
+        switch (valueMeta.getType()) {
+          case IValueMeta.TYPE_DATE:
+            field.setFormat("yyyy/MM/dd HH:mm:ss");
+            valueMeta.setConversionMask(field.getFormat());
+            string = valueMeta.getString(new Date());
+            break;
+          case IValueMeta.TYPE_STRING:
+            string = "test value test value";
+            break;
+          case IValueMeta.TYPE_INTEGER:
+            field.setFormat("#");
+            valueMeta.setConversionMask(field.getFormat());
+            string = valueMeta.getString(0L);
+            break;
+          case IValueMeta.TYPE_NUMBER:
+            field.setFormat("#.#");
+            valueMeta.setConversionMask(field.getFormat());
+            string = valueMeta.getString(0.0D);
+            break;
+          case IValueMeta.TYPE_BIGNUMBER:
+            field.setFormat("#.#");
+            valueMeta.setConversionMask(field.getFormat());
+            string = valueMeta.getString(BigDecimal.ZERO);
+            break;
+          case IValueMeta.TYPE_BOOLEAN:
+            string = valueMeta.getString(Boolean.TRUE);
+            break;
+          case IValueMeta.TYPE_BINARY:
+            string =
+                valueMeta.getString(
+                    new byte[] {
+                      65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+                    });
+            break;
+          default:
+            break;
+        }
+      } catch (HopValueException e) {
+        // Leave the test value empty
+      }
+
+      field.setValue(string);
+      generatorMeta.getFields().add(field);
+    }
+    return generatorMeta;
+  }
+}
diff --git 
a/plugins/transforms/janino/src/test/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassTestPipelineTest.java
 
b/plugins/transforms/janino/src/test/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassTestPipelineTest.java
new file mode 100644
index 0000000000..9001083b73
--- /dev/null
+++ 
b/plugins/transforms/janino/src/test/java/org/apache/hop/pipeline/transforms/userdefinedjavaclass/UserDefinedJavaClassTestPipelineTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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.pipeline.transforms.userdefinedjavaclass;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.hop.core.HopEnvironment;
+import org.apache.hop.core.exception.HopTransformException;
+import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.plugins.TransformPluginType;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.IValueMeta;
+import org.apache.hop.core.variables.IVariables;
+import org.apache.hop.core.variables.Variables;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
+import org.apache.hop.pipeline.PipelineHopMeta;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.engines.local.LocalPipelineEngine;
+import org.apache.hop.pipeline.transform.ITransform;
+import org.apache.hop.pipeline.transform.RowAdapter;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.pipeline.transforms.dummy.DummyMeta;
+import org.apache.hop.pipeline.transforms.rowgenerator.GeneratorField;
+import org.apache.hop.pipeline.transforms.rowgenerator.RowGeneratorMeta;
+import 
org.apache.hop.pipeline.transforms.userdefinedjavaclass.UserDefinedJavaClassDef.ClassType;
+import 
org.apache.hop.pipeline.transforms.userdefinedjavaclass.UserDefinedJavaClassMeta.FieldInfo;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+/**
+ * The "Test class" button runs the class in a throwaway pipeline. A class 
reading from an info
+ * transform or writing to a target transform must find those there too 
(#4584).
+ */
+class UserDefinedJavaClassTestPipelineTest {
+
+  @RegisterExtension
+  static RestoreHopEngineEnvironmentExtension env = new 
RestoreHopEngineEnvironmentExtension();
+
+  private static final String UDJC_NAME = "udjc";
+  private static final String INFO_NAME = "lookup";
+  private static final String TARGET_NAME = "out";
+
+  private static final String CLASS_SOURCE =
+      """
+      private long infoRows;
+
+      public boolean processRow() throws HopException {
+        if (first) {
+          first = false;
+          IRowSet info = findInfoRowSet("info");
+          while (getRowFrom(info) != null) {
+            infoRows++;
+          }
+          // Throws when the target transform can't be found
+          findTargetRowSet("target");
+        }
+        Object[] r = getRow();
+        if (r == null) {
+          setOutputDone();
+          return false;
+        }
+        r = createOutputRow(r, data.outputRowMeta.size());
+        get(Fields.Out, "info_rows").setValue(r, Long.valueOf(infoRows));
+        putRow(data.outputRowMeta, r);
+        return true;
+      }
+      """;
+
+  private final IVariables variables = new Variables();
+  private PipelineMeta sourcePipelineMeta;
+  private UserDefinedJavaClassMeta udjcMeta;
+
+  @BeforeAll
+  static void initEnvironment() throws Exception {
+    HopEnvironment.init();
+  }
+
+  @BeforeEach
+  void setUp() throws Exception {
+    udjcMeta = new UserDefinedJavaClassMeta();
+    udjcMeta.replaceDefinitions(
+        List.of(new UserDefinedJavaClassDef(ClassType.TRANSFORM_CLASS, 
"Processor", CLASS_SOURCE)));
+    udjcMeta.setFieldInfo(
+        new ArrayList<>(List.of(new FieldInfo("info_rows", 
IValueMeta.TYPE_INTEGER, -1, -1))));
+
+    InfoTransformDefinition infoDefinition = new InfoTransformDefinition();
+    infoDefinition.setTag("info");
+    infoDefinition.setTransformName(INFO_NAME);
+    udjcMeta.getInfoTransformDefinitions().add(infoDefinition);
+
+    TargetTransformDefinition targetDefinition = new 
TargetTransformDefinition();
+    targetDefinition.tag = "target";
+    targetDefinition.transformName = TARGET_NAME;
+    udjcMeta.getTargetTransformDefinitions().add(targetDefinition);
+
+    // The pipeline the transform lives in: main input, info input and target 
output.
+    //
+    sourcePipelineMeta = new PipelineMeta();
+    TransformMeta main =
+        addTransform(generator(field("id", "Integer", "1"), field("name", 
"String", "x")), "main");
+    TransformMeta lookup =
+        addTransform(
+            generator(field("key", "String", "k"), field("value", "Integer", 
"2")), INFO_NAME);
+    TransformMeta udjc = addTransform(udjcMeta, UDJC_NAME);
+    TransformMeta out = addTransform(new DummyMeta(), TARGET_NAME);
+    sourcePipelineMeta.addPipelineHop(new PipelineHopMeta(main, udjc));
+    sourcePipelineMeta.addPipelineHop(new PipelineHopMeta(lookup, udjc));
+    sourcePipelineMeta.addPipelineHop(new PipelineHopMeta(udjc, out));
+    udjcMeta.searchInfoAndTargetTransforms(sourcePipelineMeta.getTransforms());
+
+    udjcMeta.cookClasses();
+    assertTrue(udjcMeta.getCookErrors().isEmpty(), () -> 
udjcMeta.getCookErrors().toString());
+  }
+
+  @Test
+  void mainInputFieldsLeaveOutInfoTransforms() throws Exception {
+    IRowMeta rowMeta =
+        UserDefinedJavaClassTestPipeline.getMainInputFields(
+            variables, sourcePipelineMeta, UDJC_NAME, udjcMeta);
+
+    assertEquals(List.of("id", "name"), List.of(rowMeta.getFieldNames()));
+  }
+
+  @Test
+  void testPipelineProvidesInfoAndTargetTransforms() throws Exception {
+    IRowMeta mainRowMeta =
+        UserDefinedJavaClassTestPipeline.getMainInputFields(
+            variables, sourcePipelineMeta, UDJC_NAME, udjcMeta);
+    RowGeneratorMeta mainGenMeta =
+        UserDefinedJavaClassTestPipeline.createTestDataGenerator(mainRowMeta);
+
+    PipelineMeta testPipelineMeta =
+        UserDefinedJavaClassTestPipeline.build(
+            variables, sourcePipelineMeta, UDJC_NAME, udjcMeta, mainGenMeta);
+
+    TransformMeta infoStandIn = testPipelineMeta.findTransform(INFO_NAME);
+    assertNotNull(infoStandIn);
+    assertNotNull(testPipelineMeta.findTransform(TARGET_NAME));
+    assertEquals(
+        List.of("key", "value"),
+        List.of(testPipelineMeta.getTransformFields(variables, 
infoStandIn).getFieldNames()));
+
+    LocalPipelineEngine pipeline = new LocalPipelineEngine(testPipelineMeta);
+    pipeline.prepareExecution();
+    List<Object[]> rows = new ArrayList<>();
+    List<IRowMeta> rowMetas = new ArrayList<>();
+    ITransform udjc = pipeline.getTransform(UDJC_NAME, 0);
+    udjc.addRowListener(
+        new RowAdapter() {
+          @Override
+          public void rowWrittenEvent(IRowMeta rowMeta, Object[] row) {
+            rowMetas.add(rowMeta);
+            rows.add(row);
+          }
+        });
+    pipeline.startThreads();
+    pipeline.waitUntilFinished();
+
+    assertEquals(0, pipeline.getErrors());
+    assertEquals(10, rows.size());
+    int infoRowsIndex = rowMetas.get(0).indexOfValue("info_rows");
+    for (Object[] row : rows) {
+      assertEquals(10L, row[infoRowsIndex]);
+    }
+    assertEquals(10, pipeline.getTransform(TARGET_NAME, 0).getLinesRead());
+  }
+
+  private TransformMeta addTransform(
+      org.apache.hop.pipeline.transform.ITransformMeta meta, String name)
+      throws HopTransformException {
+    String pluginId = 
PluginRegistry.getInstance().getPluginId(TransformPluginType.class, meta);
+    TransformMeta transformMeta = new TransformMeta(pluginId, name, meta);
+    sourcePipelineMeta.addTransform(transformMeta);
+    return transformMeta;
+  }
+
+  private static RowGeneratorMeta generator(GeneratorField... fields) {
+    RowGeneratorMeta meta = new RowGeneratorMeta();
+    meta.setRowLimit("5");
+    meta.getFields().addAll(List.of(fields));
+    return meta;
+  }
+
+  private static GeneratorField field(String name, String type, String value) {
+    GeneratorField field = new GeneratorField();
+    field.setName(name);
+    field.setType(type);
+    field.setLength(-1);
+    field.setPrecision(-1);
+    field.setValue(value);
+    return field;
+  }
+}

Reply via email to