Do not input private or sensitive data. View Qlik Privacy & Cookie Policy.
Skip to main content

Announcements
Join us in Toronto Sept 9th for Qlik's AI Reality Tour! Register Now
cancel
Showing results for 
Search instead for 
Did you mean: 
PDavane
Contributor
Contributor

Parsing code from parameter file through content

code_parser=System.out.println("Complex Java code to be passed through parameter file".toUpperCase())

I want to pass code in standard talend jobs as a filter from parameter file through Context which can be changed later on as per business need. This Java String has to be converted into executable code in Talend.

Labels (4)
1 Solution

Accepted Solutions
Anonymous
Not applicable

I'll be honest, I am not sure why you would want to do this, but I was fascinated to see if I could. There is a big problem with compiling code that uses classes that do not exist. So this has to be done in such a way that class specifics (of the class you want to compile at runtime) are minimised.

 

The job I wrote to do this look like this.....

0695b00000Hst0vAAB.png 

The tFixedFlowInput is where I am supplying the code for this example. The code is just passed in as a String. The code is being written to a file that I am calling myCode.java using the tFileOutputRaw. That's pretty simple enough. FYI the code that I am passing to the file looks like this.....

 

public class MyCode {

String data1;

String data2;

public MyCode(String data1, String data2){ 

this.data1 = data1;

this.data2 = data2;

}

public String toString(){

return data1 + " " + data2 + " how are you?";

}

}

 

It is added to the tFixedFlowInput as such (note the escaped quotes as quotes are used in Java to denote a String)....

 

"public class MyCode {String data1;String data2;public MyCode(String data1, String data2){ this.data1 = data1;this.data2 = data2;}public String toString(){return data1 + \" \" + data2 + \" how are you?\";}}"

 

The next step is to compile the file that we have just created and run it. FYI I found the basis of this code here ....

https://www.netjstech.com/2016/10/how-to-compile-java-program-at-runtime.html

 

I set up the tJavaFlex to have a single column output. This is called "class_data". This is printed using the tLogRow.

 

The code in the tJavaFlex can be seen below with notes....

 

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

// Code to compile - Supplied to the tFileOutputRaw above

int result = compiler.run(null, null, null, "/Users/richardhall/Documents/MyCode.java");

// Path of the class

File classesDir = new File("/Users/richardhall/Documents");

// Load and instantiate compiled class.

URLClassLoader classLoader;

 

try {

  

 // Loading the class 

  classLoader = URLClassLoader.newInstance(new URL[] { classesDir.toURI().toURL() });

     

    Class<?> clazz = Class.forName("MyCode", true, classLoader);

     

    //The following is a hack to get this to be of any use. What I am doing here is

    //using the constructor of the class that I have created in the previous subjob to

    //act as the only way of receiving variables. 

     

Class[] cArg = new Class[2]; //Our constructor has 2 arguments

cArg[0] = String.class; //First argument is of *object* type String

cArg[1] = String.class; //Second argument is of *object* type String

 

 

String s1 = "Hello";

String s2 = "World";

 

//The following code instantiates the new class and immediately calls the toString() method

//This is because at compile time, this class we are building does not exist. So I have only access to

//methods that exist on the base Object class. The toString() method has been overridden to return 

//the result.

row2.class_data = clazz.getDeclaredConstructor(cArg).newInstance(s1, s2).toString();

     

     

} catch (MalformedURLException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

} catch (ClassNotFoundException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

} catch (IllegalAccessException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

} catch (InstantiationException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

 

 

With this code in place, you can modify the Java code used by the tFixedFlowInput and get a different result. To start with the code is initially concatenating the first constructor param String with the second, then adding " how are you?". If you have put together this job to try this out, the first Java class is below.....

 

"public class MyCode {String data1;String data2;public MyCode(String data1, String data2){ this.data1 = data1;this.data2 = data2;}public String toString(){return data1 + \" \" + data2 + \" how are you?\";}}"

 

......to test this with another Java class, just replace what is in the tFixedFlowInput with this....

 

"public class MyCode {String data1;String data2;public MyCode(String data1, String data2){ this.data1 = data1;this.data2 = data2;}public String toString(){return data1 + \" \" + data2 + \" did you see how this worked?\";}}"

 

As I said, I can't see a great many uses for this. It would be easier to alter the flow of code in a different way. But if you really want to do this and have a use case that maybe I am not thinking of, you can try something like this.

 

View solution in original post

3 Replies
Anonymous
Not applicable

I'll be honest, I am not sure why you would want to do this, but I was fascinated to see if I could. There is a big problem with compiling code that uses classes that do not exist. So this has to be done in such a way that class specifics (of the class you want to compile at runtime) are minimised.

 

The job I wrote to do this look like this.....

0695b00000Hst0vAAB.png 

The tFixedFlowInput is where I am supplying the code for this example. The code is just passed in as a String. The code is being written to a file that I am calling myCode.java using the tFileOutputRaw. That's pretty simple enough. FYI the code that I am passing to the file looks like this.....

 

public class MyCode {

String data1;

String data2;

public MyCode(String data1, String data2){ 

this.data1 = data1;

this.data2 = data2;

}

public String toString(){

return data1 + " " + data2 + " how are you?";

}

}

 

It is added to the tFixedFlowInput as such (note the escaped quotes as quotes are used in Java to denote a String)....

 

"public class MyCode {String data1;String data2;public MyCode(String data1, String data2){ this.data1 = data1;this.data2 = data2;}public String toString(){return data1 + \" \" + data2 + \" how are you?\";}}"

 

The next step is to compile the file that we have just created and run it. FYI I found the basis of this code here ....

https://www.netjstech.com/2016/10/how-to-compile-java-program-at-runtime.html

 

I set up the tJavaFlex to have a single column output. This is called "class_data". This is printed using the tLogRow.

 

The code in the tJavaFlex can be seen below with notes....

 

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

// Code to compile - Supplied to the tFileOutputRaw above

int result = compiler.run(null, null, null, "/Users/richardhall/Documents/MyCode.java");

// Path of the class

File classesDir = new File("/Users/richardhall/Documents");

// Load and instantiate compiled class.

URLClassLoader classLoader;

 

try {

  

 // Loading the class 

  classLoader = URLClassLoader.newInstance(new URL[] { classesDir.toURI().toURL() });

     

    Class<?> clazz = Class.forName("MyCode", true, classLoader);

     

    //The following is a hack to get this to be of any use. What I am doing here is

    //using the constructor of the class that I have created in the previous subjob to

    //act as the only way of receiving variables. 

     

Class[] cArg = new Class[2]; //Our constructor has 2 arguments

cArg[0] = String.class; //First argument is of *object* type String

cArg[1] = String.class; //Second argument is of *object* type String

 

 

String s1 = "Hello";

String s2 = "World";

 

//The following code instantiates the new class and immediately calls the toString() method

//This is because at compile time, this class we are building does not exist. So I have only access to

//methods that exist on the base Object class. The toString() method has been overridden to return 

//the result.

row2.class_data = clazz.getDeclaredConstructor(cArg).newInstance(s1, s2).toString();

     

     

} catch (MalformedURLException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

} catch (ClassNotFoundException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

} catch (IllegalAccessException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

} catch (InstantiationException e) {

  // TODO Auto-generated catch block

  e.printStackTrace();

 

 

With this code in place, you can modify the Java code used by the tFixedFlowInput and get a different result. To start with the code is initially concatenating the first constructor param String with the second, then adding " how are you?". If you have put together this job to try this out, the first Java class is below.....

 

"public class MyCode {String data1;String data2;public MyCode(String data1, String data2){ this.data1 = data1;this.data2 = data2;}public String toString(){return data1 + \" \" + data2 + \" how are you?\";}}"

 

......to test this with another Java class, just replace what is in the tFixedFlowInput with this....

 

"public class MyCode {String data1;String data2;public MyCode(String data1, String data2){ this.data1 = data1;this.data2 = data2;}public String toString(){return data1 + \" \" + data2 + \" did you see how this worked?\";}}"

 

As I said, I can't see a great many uses for this. It would be easier to alter the flow of code in a different way. But if you really want to do this and have a use case that maybe I am not thinking of, you can try something like this.

 

PDavane
Contributor
Contributor
Author

Hello rhall. Thank you for the help. Can you please attach zipped export of this job.

Anonymous
Not applicable

Hi @Pooja D​, apologies but I am afraid I do not have this job anymore. I wrote it and threw it away. However, all of the information you need is included in the post.