Hello everyone. Please tell me how I can transfer columns and types as variables to the “java snippet” node. I can’t pass columns as variables.
Hi @Nuke_Attokurov , one of the limitations of the flow variable mechanism for Java Snippet and some other nodes is that there is no way to dynamically create a varying number of input columns purely by specifying them on the flow variables tab.
If you have a fixed set of input columns, you must create them first manually to make a “placeholder”
Once that is done, you can then dynamically set the types etc for each
But even if you do that, I’m not sure this will be of use, because the Java code, being a statically typed language is going to be expecting input variables to be of a given type (class).
When I’m working with a java snippet, for example in a component where the user dynamically chooses columns from the table and the Java Snippet needs to be able to work with whichever columns have been chosen, I adopt the approach of writing the snippet to work with columns X, Y and Z, and then I temporarily rename the columns in the input table to X,Y and Z and then rename them back after the snippet, so I make the data table match the snippet rather than the other way round. I don’t know if that is an option for you.
What is your use case for dynamically creating the input columns for the snippet?
Hello, thanks for the reply. It is a pity that it is not possible to automatically pass the input parameters to the node.
I found a way to pass a class to a JAVA snippet node without involving a jar file. Just by passing the necessary script there through variables.
Now I had to pass the input parameter data there as well, but I don’t think it’s impossible.
You could pass in JSON which is probably as flexible and dynamic as it gets - serialize your table structure to a JSON, and pass this as single column or flow variable to the Java node.
Could you show me an example of how this can be done? I mean by the variables that I first specify in java snippet explicitly as an input parameter. Next, how do I specify the type and name of the column in the variables?
Oh, please could you share the details?
Hi @Nuke_Attokurov , to be honest the more I think about passing the columns using any kind of dynamic columns the more problematic it becomes. I’ve not tried doing it and I think it would be overly complicated with probably a poor outcome.
I much prefer @qqilihq 's suggestion and I attach a possible implementation of that. It’s actually reasonably straightforward because the ability to pack all the columns in a row into a single piece of JSON is readily available in the Columns to JSON node, and then we need some methods in the Java Snippet to do the unpacking of columns on request so you can then use them:
My table is a simple demo:
I want a java snippet to accept each row as json, and from it return me the message telling me what each person’s age is next birthday (i.e. requiring age to be included in a simple calculation: age + 1)
Being lazy, I got chatGPT to write a selection of unpacking methods to my specification:
// Your custom imports:
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
private static Object extractFieldFromJson(String json, String fieldName, Class<?> fieldType) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(json);
JsonNode fieldNode = rootNode.get(fieldName);
if (fieldNode != null) {
return convertToType(fieldNode, fieldType);
} else {
throw new IllegalArgumentException("Field with name '" + fieldName + "' not found in the JSON.");
}
}
public static String getStringField(String json, String fieldName) throws Exception {
Object fieldValue = extractFieldFromJson(json, fieldName, String.class);
return (String) fieldValue;
}
public static Integer getIntegerField(String json, String fieldName) throws Exception {
Object fieldValue = extractFieldFromJson(json, fieldName, Integer.class);
return (Integer) fieldValue;
}
public static Double getDoubleField(String json, String fieldName) throws Exception {
Object fieldValue = extractFieldFromJson(json, fieldName, Double.class);
return (Double) fieldValue;
}
public static Long getLongField(String json, String fieldName) throws Exception {
Object fieldValue = extractFieldFromJson(json, fieldName, Long.class);
return (Long) fieldValue;
}
public static Date getDateField(String json, String fieldName) throws Exception {
Object fieldValue = extractFieldFromJson(json, fieldName, Date.class);
return (Date) fieldValue;
}
public static LocalDateTime getLocalDateTimeField(String json, String fieldName) throws Exception {
Object fieldValue = extractFieldFromJson(json, fieldName, LocalDateTime.class);
return (LocalDateTime) fieldValue;
}
private static Object convertToType(JsonNode node, Class<?> fieldType) {
if (fieldType == String.class) {
return node.asText();
} else if (fieldType == Integer.class) {
return node.asInt();
} else if (fieldType == Double.class) {
return node.asDouble();
} else if (fieldType == Long.class) {
return node.asLong();
} else if (fieldType == Date.class) {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
return dateFormat.parse(node.asText());
} catch (ParseException e) {
throw new IllegalArgumentException("Error parsing date: " + e.getMessage());
}
} else if (fieldType == LocalDateTime.class) {
return LocalDateTime.parse(node.asText());
} else {
throw new IllegalArgumentException("Unsupported data type: " + fieldType.getSimpleName());
}
}
You’d need to add more if there are other datatypes to be covered.
All of the above would just be pasted complete into whatever other code you are using.
Then in the main section of the code, we unpack
// Enter your code here:
// collect the json to a string
String json=c_JSON.toString();
// define variables for the columns
String name;
Integer age;
// unpack the different columns from the json
try{
name=getStringField(json, "name");
age=getIntegerField(json,"age");
}
catch (Exception ex)
{
throw new Abort("Unable to continue: "+ex);
}
// do the processing...
out_message = "The person named " +name +" is " + ( age + 1) +" at next birthday";
As you can see, it doesn’t matter what columns we have in the table, as we just pass the single JSON value to java snippet and it handles the rest.
Of course there are improvements that could be made such as bundling that code up into a jar to be included whenever it is needed, and maybe there is a simpler way to unpack the fields already available that I am not aware of, but hopefully this gives some ideas.
pass row as json to java snippet and unpack the row from it.knwf (76.6 KB)
I should also mention that the snippet uses the following fasterxml.jackson bundles:
Colleagues, thank you very much. I still managed to make java code that, depending on the task, accepts as many columns as needed, as well as java code that also dynamically changes dynamically and rearranges several classes in java. As for the dynamic transfer of columns and column types, @qqilihq was right! The transfer. columns can be solved through the json code, too, is not very big.
This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.