I am working on a project that requires that a Java class be called from a piece of Javascript that was executed by a separate piece of Java code. It did originally work in Java 7.51 but it needs to work in Java 1.6.0_27 as well but fails with a function importclass must be called with a class error message.
The two JARs were generated through Eclipse Indigo using the Export > JAR command.
I created a simple MCVE as below to demonstrate the problem. The stack trace from executing with the following command line...
java -cp Sanity.jar;SanityCheck.jar -jar SanityCheck.jar
...is the following:
javax.script.ScriptException: sun.org.mozilla.javascript.internal.EvaluatorException: Function importClass must be called with a class; had "[JavaPackage com.sanity.Sanity]" instead. (<Unknown source>#1) in <Unknown source> at line number 1
at com.sun.script.javascript.RhinoScriptEngine.eval(Unknown Source)
at com.sun.script.javascript.RhinoScriptEngine.eval(Unknown Source)
at javax.script.AbstractScriptEngine.eval(Unknown Source)
at com.sanity.SanityCheck.<init>(SanityCheck.java:22)
at com.sanity.SanityCheck.main(SanityCheck.java:52)
Exception in thread "main" java.lang.NullPointerException
at com.sanity.SanityCheck.invoke(SanityCheck.java:31)
at com.sanity.SanityCheck.main(SanityCheck.java:53)
Can anyone see where I am going wrong here?
Sanity.java (in its own JAR of the same name)
package com.sanity;
public class Sanity {
public Sanity() {}
public void doCheck() {
System.out.println("Sanity Check Passed!");
}
}
SanityCheck.java (in its own JAR of the same name)
package com.sanity;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class SanityCheck {
private Invocable invoker;
public SanityCheck(String script) {
try {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
engine.eval(script);
invoker = (Invocable) engine;
} catch (ScriptException e) {
e.printStackTrace();
}
}
public void invoke() {
try {
invoker.invokeFunction("run");
} catch (ScriptException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
StringBuilder builder = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("Sanity.js")));
String line = null;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
reader.close();
SanityCheck check = new SanityCheck(builder.toString());
check.invoke();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Sanity.js
importClass(Packages.com.sanity.Sanity);
function run() {
var sanObj = new Sanity();
sanObj.doCheck();
}
I have good news: the problem has nothing to do with your Java or JavaScript code. It has to do with the effect of the command:
java -cp [...] -jar <jar-file>
When executing that command, the -cp argument is ignored, and the <jar-file> is used as the entire classpath.
From the Java 6 documentation for the -jar option to the java tool:
When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.
So a version of your command that would work is:
java -cp Sanity.jar;SanityCheck.jar com.sanity.SanityCheck
I reproduced your example with the following directory structure, without modifying your code:
Sanity.js
com/
sanity/
Sanity.java
SanityCheck.java
... and then ran the following command from the top-level directory:
$ /usr/lib/jvm/java-1.6.0-openjdk-amd64/bin/javac com/sanity/*.java && /usr/lib/jvm/java-1.6.0-openjdk-amd64/bin/java -classpath . com.sanity.SanityCheck
... and got
Sanity Check Passed!
The error was down to the JAR file that was being called from the Javascript was compiled against Java 7, not Java 6. A quick test trying to run a main method in Eclipse soon revealed this.
A quick recompilation of the JAR file and now it works.
Related
I have a JAVA function like this in a .jar.
I want to call this function in R, but I am not being able to use the "main" method. Does anyone know how to call this "main" method using rJAVA to produce results?
I have read in a place that I need to create a separate static method in the JAVA code to access it, is that true?
public class CountJTrees
{
public static void main(String[] args)
{
try
{
Network<String,Object> g = Graphs.read();
try
{
JTree<String> jjt = new JTree<String>(g);
System.out.println(jjt.enumerate());
}
catch(GraphNotDecomposableException e)
{
System.out.println(0);
}
}
catch (Exception e)
{
System.err.println("Caught CountJTrees.main()");
e.printStackTrace();
}
}
}
Let's say you have structure like this:
.
|-- Manifest.txt
`-- src
`-- somepackage
`-- StringTest.java
and file StringTest.java contains:
package somepackage;
public class StringTest {
public String changeString(String str) {
return "I have changed the string: " + str;
}
public static void main(String [] arg) {
System.out.println(new StringTest().changeString("Hello"));
}
}
You can easily build JAR file. With Manifest.txt file
Manifest-Version: 1.0
Main-Class: somepackage.StringTest
following way:
> jar cfm test.jar Manifest.txt -C target somepackage/StringTest.class
# execute JAR - just to test it works as expected
> java -jar test.jar
I have changed the string: Hello
Once your JAR is working as expected, you can run it in R
> export CLASSPATH=./test.jar
> R
R version 3.6.1 (2019-07-05) -- "Action of the Toes"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin15.6.0 (64-bit)
...
...
...
> library(rJava)
> .jinit()
> obj <- .jnew("somepackage.StringTest")
> s <- .jcall(obj, returnSig="V", method="main", c("Hello", "Hello") )
I have changed the string: Hello
>
Hi I'm still newbie to Selenium/Scripting/Java and I'me still at the stage of hacking together code from elsewhere to get stuff work( tutorials and recorders mainly)
Anyway Im trying to write a script to check a particular 'element' is present (I will want to the the reverse as well) I can get the script to pass correctly when it finds the 'element' but if change the element details so I know it should fail (as it don't exist) TestNG still pass's the test but gives a configuration fail ?
I presume I'm missing something to cover the fail aspect of the test but no sure how to go about it, every time I try I and get it to run into this.
package Links;
import org.testng.annotations.*;
import static org.testng.Assert.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class TestArea {
private WebDriver driver;
private StringBuffer verificationErrors = new StringBuffer();
#BeforeClass(alwaysRun = true)
public void setUp() throws Exception {
System.setProperty("webdriver.gecko.driver", "C:\\Automation\\SeleniumFiles\\Browser Drivers\\geckodriver.exe");
driver = new FirefoxDriver();
}
#Test
public void Example() throws Exception {
driver.get(
"http://MyWebsite");
try {
assertTrue(isElementPresent(
By.xpath("The Element I want look for ")));
} catch (Error e) {
verificationErrors.append(e.toString());
}
}
// -------------------------------------------------------------------------------------
#AfterClass(alwaysRun = true)
public void tearDown() throws Exception {
driver.quit();
String verificationErrorString = verificationErrors.toString();
if (!"".equals(verificationErrorString)) {
fail(verificationErrorString);
}
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
An example of a "passed" test but with a failed configuration.
FAILED CONFIGURATION: #AfterClass tearDown java.lang.AssertionError:
java.lang.AssertionError: expected [true] but found [false] at
org.testng.Assert.fail(Assert.java:96) at
Links.TestArea.tearDown(TestArea.java:39) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at
java.lang.reflect.Method.invoke(Unknown Source) at
org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
at
org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:59)
at
org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:455)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:222)
at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:142)
at
org.testng.internal.TestMethodWorker.invokeAfterClassMethods(TestMethodWorker.java:214)
at
org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:648) at
org.testng.TestRunner.run(TestRunner.java:505) at
org.testng.SuiteRunner.runTest(SuiteRunner.java:455) at
org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450) at
org.testng.SuiteRunner.privateRun(SuiteRunner.java:415) at
org.testng.SuiteRunner.run(SuiteRunner.java:364) at
org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at
org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84) at
org.testng.TestNG.runSuitesSequentially(TestNG.java:1208) at
org.testng.TestNG.runSuitesLocally(TestNG.java:1137) at
org.testng.TestNG.runSuites(TestNG.java:1049) at
org.testng.TestNG.run(TestNG.java:1017) at
org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:114)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77)
PASSED: Example
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
Configuration Failures: 1, Skips: 0
=============================================== Default suite Total tests run: 1, Failures: 0, Skips: 0 Configuration Failures: 1, Skips:
0
I don't get the configuration issue when the test can find the element.
Thanks very much in advance
There are a few issues in your test code.
TestNG by default fails a #Test method when :
An assertion fails
test method raises an Exception.
So you don't need to wrap assertTrue() call within a try..catch block. If you would like to run through all assertions and have the test method fail at the end, you should be using something called as Soft Assertion in TestNG.
Below is a cleaned-up version of your test code.
import org.testng.annotations.*;
import static org.testng.Assert.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
public class TestArea {
private WebDriver driver;
#BeforeClass(alwaysRun = true)
public void setUp() throws Exception {
System.setProperty("webdriver.gecko.driver", "C:\\Automation\\SeleniumFiles\\Browser Drivers\\geckodriver.exe");
driver = new FirefoxDriver();
}
#Test
public void Example() throws Exception {
driver.get( "http://MyWebsite");
assertTrue(isElementPresent( By.xpath("The Element I want look for ")));
}
#AfterClass(alwaysRun = true)
public void tearDown() throws Exception {
driver.quit();
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
}
I want to retrieve data from a website using Nashorn script engine
I have the java code where I can retrieve data from a sample website template.
Now I want to call that java file from java script file.
following is the code:
JAVA CODE(Nsample.java):
package sample;
import java.net.*;
import java.io.*;
public class Nsample
{
public static void main(String[] args)
{
String output = getUrlContents("https://freewebsitetemplates.com/");
System.out.println(output);
}
public static String getUrlContents(String theUrl)
{
StringBuilder content = new StringBuilder();
try
{
URL url = new URL(theUrl);
URLConnection urlConnection = url.openConnection();
BufferedReader bufferedReader = new BufferedReader(new
InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null)
{
content.append(line + "\n");
}
bufferedReader.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return content.toString();
}
}
JAVASCRIPT code:(sample.js)
var n = Java.type('C.JavaFolder.sample.Nsample');
var result = n.getUrlContents("https://freewebsitetemplates.com/");
print(result);
I'm trying to compile javascript code using command prompt but it is showing CLASSNOTFOUNDEXCEPTION.
The command was jjs sample.js.Im assuming I did some mistake in Java.type() function.
Can anyone solve this?
This line is the problematic line:
var n = Java.type('C.JavaFolder.sample.Nsample');
Java.type accepts fully qualified java type name. Based on your Java code, your package seems to be "sample" and class name is "Nsample". So the fully qualified class name would be "sample.Nsample".
You should compile your Java classes and specify the directory in -classpath option (of jjs tool or your java application if you use javax.script API with nashorn).
Instead of calling Java from JavaScript , I tried to call JavaScript from java and worked well.
I created some functions in JavaScript and invoked those functions from Java code.
Following is the code.Hope this helps.
Test.java:
import javax.script.*;
import java.io.*;
import java.util.*;
public class Test{
public static void main(String[] args) throws Exception{
ScriptEngine engine = new ScriptEngineManager().getEngineByName("Nashorn");
engine.eval(new FileReader("test.js"));
Invocable invoke = (Invocable)engine;
Object res = invoke.invokeFunction("httpGet","https://www.javaworld.com");
System.out.println(res);
}
}
test.js:
var httpGet = function(theUrl){
var con = new java.net.URL(theUrl).openConnection();
con.requestMethod = "GET";
return asResponse(con);
}
function asResponse(con){
var d = read(con.inputStream);
return d;
}
function read(inputStream){
var inReader = new java.io.BufferedReader(new
java.io.InputStreamReader(inputStream));
var inputLine;
var response = new java.lang.StringBuffer();
while ((inputLine = inReader.readLine()) != null) {
response.append(inputLine);
}
inReader.close();
return response.toString();
}
when I try to run child process and put to it stdin some text it throws error.
here is code of child process:
import java.io.Console;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("started");
Console console = System.console();
while (true) {
String s = console.readLine();
System.out.println("Your sentence:" + s);
}
}
}
code of script which run this process:
var spawn = require('child_process').spawn;
var child = spawn('java', ['HelloWorld', 'HelloWorld.class']);
child.stdin.setEncoding('utf-8');
child.stdout.pipe(process.stdout);
child.stdin.write("tratata\n");
// child.stdin.end();
it throws:
events.js:161
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at exports._errnoException (util.js:1028:11)
at Pipe.onread (net.js:572:26)
notice, when I uncomment line with child.stdin.end(); it only ends whithout any reaction
The one thing you need to make the script work was to add:
process.stdin.pipe(child.stdin);
If you added this before the child.stdin.write, that would solve half the problem. The other half had to do with the Java side. If the java program is not launched from a console by typing java HelloWorld, then Console will return null thus you will get a NullPointerException if you tried to use Console.readLine. To fix, this use BufferedReader instead.
Change your script to this:
const spawn = require('child_process').spawn;
const child = spawn('java', ['HelloWorld'], {
stdio: ['pipe', process.stdout, process.stderr]
});
process.stdin.pipe(child.stdin);
setTimeout(() => {
child.stdin.write('tratata\n');
}, 1000);
Then change your java code to this:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class HelloWorld {
public static void main(String[] args) throws IOException {
System.out.println("started");
try(BufferedReader console = new BufferedReader(new InputStreamReader(System.in))) {
for (String line = console.readLine(); line != null; line = console.readLine()) {
System.out.printf("Your sentence: %s\n", line);
}
}
}
}
See:
NodeJS Spawn Command
System.console() returns null
Title says it all. I am wondering if i can display javascript console.log in eclipse console rather than web browser's dev console?
Just found an article regarding this.
This is How it works(For Window 7).
Install Node.js javascript engine at Node.js
Open your Eclipse, in the menu
Run->External Tools->External Tools Configuration
Create new launch configuration under program category.
Set
Location : C:\WINDOWS\system32\cmd.exe
Working Directory : C:\WINDOWS\system32
Argument : /c "node ${resource_loc}"
Now create new environment variable 'node' refers to node.exe file(wherever you installed)
All done.
Redirect javascript console.logs, in Java console
Here is my solution to get javascript console messages in Java (with SWT browser)
create shell SWT and SWT browser see: Shell + Browser
create custom function SWT see: call Java from JavaScript
Add listener on error events in javascript see: mdn event error
Override console object in javascript and call custom java function (2.)
Here is my example snippet:
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.BrowserFunction;
import org.eclipse.swt.browser.LocationAdapter;
import org.eclipse.swt.browser.LocationEvent;
import org.eclipse.swt.browser.ProgressListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class Snippet307d3 {
public static final Shell createShell() {
final var display = new Display();
final var shell = new Shell(display);
shell.setText("Snippet DEBUG");
shell.setLayout(new FillLayout());
shell.setBounds(10, 10, 300, 200);
return shell;
}
public static final Browser createBrowser(Shell shell) {
try {
return new Browser(shell, SWT.NONE);
} catch (final SWTError e) {
System.out.println("Could not instantiate Browser: " + e.getMessage());
shell.getDisplay().dispose();
System.exit(-1);
return null;
}
}
public static final void runShell(Shell shell) {
shell.open();
final var display = shell.getDisplay();
while (!shell.isDisposed())
if (!display.readAndDispatch())
display.sleep();
display.dispose();
}
public static void main(String[] args) {
// -> Create shell
final var shell = createShell();
// -> Create browser
final var browser = createBrowser(shell);
browser.setJavascriptEnabled(true);
// -> set HTML or use setUrl
browser.setText(createHTML());
// browser.setUrl(URL_DOCUMENT_HTML_TEST);
// -> Create custom function
final BrowserFunction function = new CustomFunction(browser, "theJavaFunctionDebugInEclipse");
// -> Register function for cleanup
browser.addProgressListener(ProgressListener.completedAdapter(event -> {
browser.addLocationListener(new LocationAdapter() {
#Override
public void changed(LocationEvent event) {
browser.removeLocationListener(this);
System.out.println("left java function-aware page, so disposed CustomFunction");
function.dispose();
}
});
}));
// -> 6) Start shell
runShell(shell);
}
private static class CustomFunction extends BrowserFunction {
public CustomFunction(Browser browser, String name) {
super(browser, name);
}
#Override
public Object function(Object[] arguments) {
for (final Object v : arguments)
if (v != null)
System.out.println(v.toString());
return new Object();
}
}
private static String createHTML() {
return """
<!DOCTYPE>
<html lang='en'>
<head>
<title>DEBUG SWT</title>
<script>
const console = {
log : function(args) {
try {
theJavaFunctionDebugInEclipse('redirect > ' + args);
} catch (_e) {
return;
}
},
error : function(args) {
this.log(args);
},
exception : function(args) {
this.log(args);
},
debug : function(args) {
this.log(args);
},
trace : function(args) {
this.log(args);
},
info : function(args) {
this.log(args);
}
};
window.addEventListener('error', function(e) {
console.log(e.type + ' : ' + e.message);
console.log(e);
});
</script>
</head>
<body>
<input id=button type='button' value='Push to Invoke Java'
onclick='function1();'>
<p>
<a href='http://www.eclipse.org'>go to eclipse.org</a>
</p>
<script>
// bad char sequence .. send error
eeeee
function function1() {
let result;
try {
// Call bad function java .. send log
result = badFunctionJava(12, false, null, [ 3.6,
[ 'swt', true ] ], 'eclipse');
} catch (e) {
console.log('a error occurred: ' + e.message);
return;
}
}
</script>
</body>
</html>
""";
}
}
Further to #ringord's answer here, these would be the commands for your External Tools Configuration on Linux:
Location : /home/<user>/.nvm/versions/node/<version>/bin/node (or wherever you installed node)
Working Directory : /home/<user>
Arguments : ${container_loc}/${resource_name}