I need to configure some attribute in ScriptEngine- or ScriptContext-level, to be used in Java methods.
So, how to get a reference to that ScriptContext in order to retrieve the value?
Example: setting the attribute:
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("param1", "paramValue", ScriptContext.ENGINE_SCOPE);
engine.put("MyWindow", engine.eval("Java.type(\"" + MyWindow.class.getName() + "\")"));
engine.eval("print(new MyWindow().test());");
}
MyWindow implementation: how to get that attribute?
public class MyWindow {
public String test() {
// how to get 'param1' value here
return "in test";
}
}
Pass it in:
engine.eval("print(new MyWindow().test(param1));");
// ^^^^^^
// vvvvvvvvvvvvv
public String test(String param1) {
// how to get 'param1' value here
return "in test";
}
Update
If you have code with a call stack like javaMethod1 -> JavaScript -> javaMethod2, and you want a value from javaMethod1 to be available to javaMethod2, without changing the JavaScript to pass it on, use a ThreadLocal.
Since your code is in main you could just use a static directly, but I'm assuming your context is more complex. The code below works even in multi-threaded contexts. The ThreadLocal can be stored anywhere, it just has to be static and available to both java methods.
public static void main(String[] args) throws Exception {
MyWindow.param1.set("paramValue");
try {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval("var MyWindow = Java.type(\"" + MyWindow.class.getName() + "\");" +
"print(new MyWindow().test());");
} finally {
MyWindow.param1.remove();
}
}
public class MyWindow {
public static final ThreadLocal<String> param1 = new ThreadLocal<>();
public String test() {
String value = param1.get();
return "in test: param1 = " + value;
}
}
Related
Here is a small sample:
public class LocalClassSample {
public static void main(String[] args) {
class Utils {
public void printHello(String name) {
System.out.println("Hello " + name);
}
public String outHello(String name) {
return "hello " + name;
}
}
Utils util = new Utils();
util.printHello("World");
}
}
I put a break point at the last line. I am able to view util in the Variables window...
I try to view the same variable in the expressions window...it is unable to evaluate:
Update:
Even tried inspecting the variable in the Display View...it does not evaluate:
Expression eval a java expression like 'util.printHello("World")'
and return the result ("Hello World"). 'util' is not an 'expression' but just a variable name, if you want to inspect it, use the Variables view or the Inspect command.
Why does not jsr-223 evaluate string when is a attribute of a object?
Simple class with only one String attribute:
public class EvalJSR223Bean {
public String evalFnt;
}
Simple evaluation using text and object, and when is used the object, Rhino does not execute eval. But if I concatenate empty javascript string to object property, Rhino eval.
public static void main(String[] args) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
engine.eval("function f2() {println('EXECUTED!!!!!')}; function f1(source) { return eval(source); };");
String evalFnt = "(function(){f2();return '0';})();";
engine.put("evalFnt", evalFnt);
engine.eval("f1(evalFnt);"); // f2 is executed.
EvalJSR223Bean bean = new EvalJSR223Bean();
bean.evalFnt = evalFnt;
engine.put("bean1", bean.evalFnt);
engine.eval("f1(bean1.evalFnt);"); // Why does NOT executed f2 ?!!.
engine.put("bean", bean);
engine.eval("f1(bean.evalFnt);"); // Why does NOT executed f2 ?!!.
engine.put("bean", bean);
engine.eval("f1( ''+bean.evalFnt );"); // And if I concatenate a string, f2 is executed!!!
}
eval ignores the string if the string is not of type "string":
eval(new String('console.log("foo");'));
So this is likely a consequence of how Rhino treats the property as being of type "object". When you put a string into the engine, it must convert it to the value type.
This code:
import javax.script.*;
public class ScriptDemo {
public static class Bar {
public String bar = "bar";
}
public static void main(String[] args) throws ScriptException {
ScriptEngine engine =
new ScriptEngineManager().getEngineByName("JavaScript");
engine.put("foo", "foo");
engine.put("bar", new Bar());
engine.eval("println(typeof foo);");
engine.eval("println(typeof bar.bar);");
engine.eval("println(typeof String(bar.bar));");
engine.eval("println(typeof new String(bar.bar));");
}
}
Output:
string
object
string
object
What I want to do is access a variable stored in one class with a string.
For example I have
public class Values {
public static boolean enabled;
}
And then in a different part of the project I have the object and a string with the fields name. How do I get and set the value of the field?
If you have the name as a string, you should use reflection:
import java.lang.reflect.Field;
public class Values {
public static boolean enabled = false;
public static void main(String[] args) throws Exception {
Values v = new Values();
Field field = v.getClass().getField("enabled");
field.set( v, true );
System.out.println( field.get(v) );
}
}
Values.enabled = true;
or
Values.enabled = false;
Alternatively, you can create a static getter and setter for the Values class and call those static methods instead.
#Maricio Linhares's answer is very good; however, note that reflection is pretty slow. If you are doing this a lot you might have performance problems. An alternative might be to use a map. The code would follow as
public class Values {
public static Map<string,bool> variableMap;
public static void main(String[] args) throws Exception {
// adding a 'variable'
variableMap = new YourFavoriteMapImplementation();
variableMap.put("enabled",true);
// accessing the 'variables' value
bool val = variableMap.get("enabled");
System.out.println(val);
}
}
i'm totally new to java. i 'm try to create my first program & i get this error.
E:\java>javac Robot.java
Robot.java:16: error: illegal start of expression
public String CreateNew (); {
^
Robot.java:16: error: ';' expected
public String CreateNew (); {
^
2 errors
below is my program.
public class Robot {
public static void main(String args[]){
String model;
/*int year;*/
String status;
public String CreateNew () {
Robot optimus;
optimus = new Robot();
optimus.model="Autobot";
/*optimus.year="2008";*/
optimus.status="active";
return (optimus.model);
}
}
}
You're trying to define a method (CreateNew) within a method (main), which you cannot do in Java. Move it out of the main; and as model and status appear to be instance variables (not method variables), move them as well:
public class Robot {
// Member variables
String model;
/*int year;*/
String status;
// main method
public static void main(String args[]){
// Presumably more stuff here
}
// Further method
public String CreateNew () {
Robot optimus;
optimus = new Robot();
optimus.model="Autobot";
/*optimus.year="2008";*/
optimus.status="active";
return (optimus.model);
}
}
Based on its content, you may want CreateNew to be static (so it can be called via Robot.CreateNew rather than via a Robot instance). Like this:
public class Robot {
// Member variables
String model;
/*int year;*/
String status;
// main method
public static void main(String args[]){
// Presumably more stuff here
}
// Further method
public static String CreateNew () {
// ^----------------------------- here's the change
Robot optimus;
optimus = new Robot();
optimus.model="Autobot";
/*optimus.year="2008";*/
optimus.status="active";
return (optimus.model);
}
}
Used as
String theModel = Robot.CreateNew();
...although it's unclear to me why you want to create a Robot instance and then throw it away and just return the model instance member's value.
Somewhat off-topic, but the overwhelming convention in Java is that method names (static or instance) start with a lower-case letter, e.g. createNew rather than CreateNew.
You didn't close your main method before you create the CreateNew() one. In fact I don't think you meant to have a main method in your Robot class, you should have only one main method for your whole program. And your CreateNew should be a constructor:
public class Robot {
String model;
/*int year;*/
String status;
public Robot () {
this.model="Autobot";
this.status="active";
}
}
}
and then in another class that contains your main method (or it could be in the same class too):
public class OtherClass {
public static void main(String[] args) {
Robot optimus = new Robot(); // here you create an instance of your robot.
}
}
then you can have a second constructor that takes in parameter the model and status like that:
public Robot (String m, Status s) {
this.model=m;
this.status=s;
}
and finally in your main:
Robot prime = new Robot("aName", "aStatus");
Not sure if the title makes sense, but I am trying to return a Success message from a class that receives a linkedhashmap, however eclipse is giving me error when I try to compile the files, offering
Remove arguments to match 'logFile()'
Create constructor 'logFile(Map<String, String>)'
How do set it up to send a Map and revieve a String?
thx
Art
Code corrected as per #Jeff Storey below with error suppression for eclipse
calling class
eventLog.put(stringA,stringB);
logFile logStuff = new logFile();
successRtn = logFile.Process(eventLog);
// Do Stuff with SuccessRtn
logFile class
public class logFile {
static String Success = "Fail";
public static String Process(Map<String, String> eventlog){
// Do Stuff
Success = "Yeh!"
return Success;
}
public static void main(String[] args){
#SuppressWarnings("static-access")
String result = new logFile().Procces(eventLog);
System.out.println("result = " + result);
}
The main method is a special method whose signature must public static void main(String[] args) when being used as an entry point to your application. Create a second method that does the actual work, like this:
public class LogFile {
public String process(Map<String,String> eventLog) {
// do stuff
return success;
}
public void main(String[] args) {
// eventLog will probably be read from a filepath passed into the args
String result = new LogFile().process(eventLog);
System.out.println("result = " + result);
}
}
Note that a lot of your naming conventions are also non standard. Classes should begin with a capital letter and variables should begin with a lower case.