Cannot access java.lang.String in script run in Rhino - java

I have problems accessing Java classes in JavaScript. Calling a code snippet
var String = Java.type("java.lang.String");
from Java via javax.script.ScriptEngine, yields follwing Error
Exception in thread "main" javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "Java" is not defined. (path/to/string.js#1) in path/to/string.js at line number 1
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:156)
at main.JsTest.main(JsTest.java:55)
Using non-Java classes in the script works fine, e.g. var value = a + b, where a and b are defined in a javax.script.ScriptContext.
This is the Java class that executes the script.
JsTest.java
public class JsTest
{
public static void main(String[] args) throws Exception
{
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine se = sem.getEngineByExtension("js");
String script = "path/to/string.js";
File scriptFile = new File(script);
FileReader fr = new FileReader(scriptFile);
se.put(ScriptEngine.FILENAME, script);
ScriptContext sc = new SimpleScriptContext();
se.eval(fr, sc);
}
}

I have no idea where your Java.type is coming from, but the official documentation uses Packages.java or just java.
So your line should probably look like
var String = Packages.java.lang.String;

Related

Send parms to python script form java with jython

Hello I want to pass argument to python script in Java with Jython i have this code:
public static void pyCode(String argumentOne) throws FileNotFoundException, ScriptException {
StringWriter writer = new StringWriter(); //ouput will be stored here
ScriptEngineManager manager = new ScriptEngineManager();
ScriptContext context = new SimpleScriptContext();
context.setWriter(writer); //configures output redirection
ScriptEngine engine = manager.getEngineByName("python");
engine.eval(new FileReader("main.py"), context);
System.out.println(writer.toString());
}
I need to execute the python script like main.py arg1 or to pass the String input to the main.py file with will be used in the file.
I just found Jython and I can't see proper example in the documentation.

Run a python function with arguments from java using jython

I want to execute a Python function which is located in one of my python projects from java by using jython. https://smartbear.com/blog/test-and-monitor/embedding-jython-in-java-applications/ is giving the sample code for the purpose. But in my scenario I got the following exception.
Exception in thread "main" Traceback (most recent call last): File
"", line 1, in ImportError: No module named
JythonTestModule
My scenario is as follows.
I have created a python module inside my python project(pythonDev) by using PyCharm(JythonTestModule.py) which contains the following function.
def square(value):
return value*value
Then I created a sample java class in my java project(javaDev) and called the python module.
public static void main(String[] args) throws PyException{
PythonInterpreter pi = new PythonInterpreter();
pi.exec("from JythonTestModule import square");
pi.set("integer", new PyInteger(42));
pi.exec("result = square(integer)");
pi.exec("print(result)");
PyInteger result = (PyInteger)pi.get("result");
System.out.println("result: "+ result.asInt());
PyFunction pf = (PyFunction)pi.get("square");
System.out.println(pf.__call__(new PyInteger(5)));
}
After running this java method the aforementioned exception is generated by the java program. I want to know what is the problem with this menioned code segments.
As from the suggestions from the above comments section of this question, I have developed the solution to my question. Following code segment will demonstrate that. In this solution I have set the python.path as the directory path to my module file.
public static void main(String[] args) throws PyException{
Properties properties = new Properties();
properties.setProperty("python.path", "/path/to/the/module/directory");
PythonInterpreter.initialize(System.getProperties(), properties, new String[]{""});
PythonInterpreter pi = new PythonInterpreter();
pi.exec("from JythonTestModule import square");
pi.set("integer", new PyInteger(42));
pi.exec("result = square(integer)");
pi.exec("print(result)");
PyInteger result = (PyInteger)pi.get("result");
System.out.println("result: "+ result.asInt());
PyFunction pf = (PyFunction)pi.get("square");
System.out.println(pf.__call__(new PyInteger(5)));
}
If you want to use multiple modules from the Jython, add the python.path as the parent directory path of all the modules in order to detect all the modules.

How to use Apache Commons CLI to parse the property file and --help option?

I have a property file which is like this -
hostName=machineA.domain.host.com
emailFrom=tester#host.com
emailTo=world#host.com
emailCc=hello#host.com
And now I am reading the above property file from my Java program as shown below. I am parsing the above property file manual way as of now -
public class FileReaderTask {
private static String hostName;
private static String emailFrom;
private static String emailTo;
private static String emailCc;
private static final String configFileName = "config.properties";
private static final Properties prop = new Properties();
public static void main(String[] args) {
readConfig(arguments);
// use the above variables here
System.out.println(hostName);
System.out.println(emailFrom);
System.out.println(emailTo);
System.out.println(emailCc);
}
private static void readConfig(String[] args) throws FileNotFoundException, IOException {
if (!TestUtils.isEmpty(args) && args.length != 0) {
prop.load(new FileInputStream(args[0]));
} else {
prop.load(FileReaderTask.class.getClassLoader().getResourceAsStream(configFileName));
}
StringBuilder sb = new StringBuilder();
for (String arg : args) {
sb.append(arg).append("\n");
}
String commandlineProperties = sb.toString();
if (!commandlineProperties.isEmpty()) {
// read, and overwrite, properties from the commandline...
prop.load(new StringReader(commandlineProperties));
}
hostName = prop.getProperty("hostName").trim();
emailFrom = prop.getProperty("emailFrom").trim();
emailTo = prop.getProperty("emailTo").trim();
emailCc = prop.getProperty("emailCc").trim();
}
}
Most of the time, I will be running my above program through command line as a runnable jar like this -
java -jar abc.jar config.properties
java -jar abc.jar config.properties hostName=machineB.domain.host.com
My question is-
Is there any way to add --help option while running the abc.jar that can tell us more about how to run the jar file and what does each property means and how to use them? I have seen --help while running most of the C++ executable or Unix stuff so not sure how we can do the same thing in Java?
Do I need to use CommandLine parser like Commons CLI for this in Java to achieve this and instead of doing manual parsing, I should use Commons CLI to parse the file as well? If yes, then can anyone provide an example how would I do that in my scenario?
In the long run if you plan to add other options in the future then commons-cli is surely a fairly good fit as it makes it easy to add new options and manual parsing quickly becomes complicated.
Take a look at the official examples, they provide a good overview of what the library can do.
Your specific case would probably lead to something like the following:
// create Options object
Options options = new Options();
Option help = new Option( "h", "help", false, "print this message" );
options.addOption(help);
CommandLineParser parser = new PosixParser();
CommandLine cmd = parser.parse( options, args);
if(cmd.hasOption("help") || cmd.getArgList().isEmpty()) {
// automatically generate the help statement
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp( "cli-test [options] <property-file>", options );
return;
}
// do your thing...
System.out.println("Had properties " + cmd.getArgList());

Calling custom script function with ScriptEngine from Java

I have same custom functions with the same names on different script files written in python, groovy and javascript. User can choose one of the scripts that want to use. I want to call functions from these scripts in generic way.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("python");
Bindings bindings = engine.createBindings();
engine.eval(new FileReader("C:/Users/Cgr/Desktop/CustomPython.py");
Invocable inv = (Invocable) engine;
System.out.println(inv.invokeFunction("customConcatFunc", "str1", "str2"));
With this way I can call my functions even change ScriptEngineManager parameter as "javascript" or "groovy" with changing reader files with "CustomJs.js" or "Customgroovy.groovy".
However, I wonder that is there a way to call functions without using invokeFunction like below:
First, evaluate script and put the result on binding then calling function on this object.
bindings.put("x", "str1");
bindings.put("y", "str2");
bindings.put("script", engine.eval(new FileReader("C:/Users/Cgr/Desktop/CustomgrPython.py")));
engine.eval("script.customConcatFunc(x,y)", bindings);
So, this is the most generic way for me if there is way like this or are there any other suggestions?
The method below might be helpful avoiding call invokeFunction:
#Test
public void test60_ScriptEngineTest()
throws URISyntaxException, ScriptException, NoSuchMethodException, FileNotFoundException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("groovy");
Compilable compilable = (Compilable) engine;
Bindings bindings = engine.createBindings();
URL url=getClass().getResource("/data-encoder-dir/testFunc.groovy");
File script =new File(url.toURI());
Reader reader = new FileReader(script);
CompiledScript compiledScript = compilable.compile(reader);
bindings.put("x", 5011);
String result = (String) compiledScript.eval(bindings);
assertEquals(result, "5011");
}
a groovy file attached (in /data-encoder-dir/testFunc.groovy):
public String testFunc(Integer bd) {
return bd.toString();
}
testFunc(x)
PS: I'm using groovy, the javascript scenario or other java script engine compatible would follow the same route.

Aspose with RJB (Ruby Java Bridge) is not working

I have a code in Java that opens a excel template by aspose library (it runs perfectly):
import com.aspose.cells.*;
import java.io.*;
public class test
{
public static void main(String[] args) throws Exception
{
System.setProperty("java.awt.headless", "true");
FileInputStream fstream = new FileInputStream("/home/vmlellis/Testes/aspose-cells/template.xlsx");
Workbook workbook = new Workbook(fstream);
workbook.save("final.xlsx");
}
}
After I run this on Ruby with RJB (Ruby Java Bridge):
require 'rjb'
#RJM Loading
JARS = Dir.glob('./jars/*.jar').join(':')
print JARS
Rjb::load(JARS, ['-Xmx512M'])
system = Rjb::import('java.lang.System')
file_input = Rjb::import('java.io.File')
file_input_stream = Rjb::import('java.io.FileInputStream')
workbook = Rjb::import('com.aspose.cells.Workbook')
system.setProperty("java.awt.headless", "true")
file_path = "/home/vmlellis/Testes/aspose-cells/template.xlsx"
file = file_input.new(file_path)
fin = file_input_stream.new(file)
wb = workbook.new(fin)
I get this error:
test.rb:57:in `new': Can't find file: java.io.FileInputStream#693a317a. (FileNotFoundException)
from aspose-test.rb:57:in `<main>'
Why? I run the same code... but in Ruby is not working! How do I fix this?
Update:
In documentation there is the the initializer: Workbook(java.io.InputStreamstream)... but it's not working in RJB. (How is this possible?)
Your program should have worked, but I could not find any reason why it didn't and I am looking into it.
Now the alternate approaches.
Approach 1
Use Workbook(String) constructor instead of Workbook(FileInputStream). This worked flawlessly at my end. The sample code is
require 'rjb'
#RJM Loading
JARS = Dir.glob('/home/saqib/cellslib/*.jar').join(':')
print JARS
Rjb::load(JARS, ['-Xmx512M'])
system = Rjb::import('java.lang.System')
workbook = Rjb::import('com.aspose.cells.Workbook')
system.setProperty("java.awt.headless", "true")
file_path = "/home/saqib/rjb/template.xlsx"
save_path = "/home/saqib/rjb/final.xlsx"
wb = workbook.new(file_path)
wb.save(save_path)
Approach 2
Write a new Java class library. Write all your Aspose.Cells related code in it. Expose very simple and basic methods that needs to be called from Ruby (RJB).
Why?
It is easy to write program in native Java language. If you use RJB, you need to perform a lot of code conversions
It is easy to debug and test in Java.
Usage of RJB will only be limited to calling methods from your own Java library. The RJB code will be small and basic.
Similar Example using own library
Create a new Java project, lets say "cellstest". Add a new public class in it.
package cellstest;
import com.aspose.cells.Workbook;
public class AsposeCellsUtil
{
public String doSomeOpOnWorkbook(String inFile, String outFile)
{
String result = "";
try
{
// Load the workbook
Workbook wb = new Workbook(inFile);
// Do some operation with this workbook
// ..................
// Save the workbook
wb.save(outFile);
// everything ok.
result = "ok";
}
catch(Exception ex)
{
// Return the exception to calling program
result = ex.toString();
}
return result;
}
}
Like this, add as many methods as you like, for each operation.
Build the project and copy the "cellstest.jar" in same folder where you copied Aspose.Cells jar files. You can return a String from your methods and check the return value in Ruby program for success or error code. The Ruby program will now be like
require 'rjb'
#RJM Loading
JARS = Dir.glob('/home/saqib/cellslib/*.jar').join(':')
print JARS
Rjb::load(JARS, ['-Xmx512M'])
system = Rjb::import('java.lang.System')
AsposeCellsUtil = Rjb::import('cellstest.AsposeCellsUtil')
system.setProperty("java.awt.headless", "true")
file_path = "/home/saqib/rjb/template.xlsx"
save_path = "/home/saqib/rjb/final.xlsx"
# initialize instance
asposeCellsUtil = AsposeCellsUtil.new()
# call methods
result = asposeCellsUtil.doSomeOpOnWorkbook(file_path, save_path)
puts result
PS. I work for Aspose as Developer Evangelist.
In your Java code, you pass a file name string into FileInputStream() constructor:
FileInputStream fstream = new FileInputStream("/home/vmlellis/Testes/aspose-cells/template.xlsx");
In your Ruby code, you pass a file object:
file = file_input.new(file_path)
fin = file_input_stream.new(file)
Have you tried to do the same thing as in Java?
fin = file_input_stream.new(file_path)

Categories