Java: Връщане на обект от javascript на ScriptEngine

Опитвам се да оценя javascript в Java, като използвам ScriptEngine клас. Ето кратък пример за това, което се опитвам да направя:

import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;

public class Test {
    public static void main(String[] args) {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("js"); //Creates a ScriptEngine
        Object obj = engine.eval("var obj = { value: 1 }; return obj; "); // Evals the creation of a simple object
        System.out.println(obj.value); // I get an invalid token error when trying to print a property of the object
    }
}

Почти съм сигурен, че това трябва да работи... но съм объркан и ще приема всяка помощ, която мога да получа.


person hjk321    schedule 26.06.2016    source източник
comment
Работи ли, ако изпуснете return obj;? Изявленията за връщане трябва да са във функции, но тогава не знам как този клас оценява JS кода.   -  person    schedule 26.06.2016
comment
И аз не съм много сигурен как работи; Току-що видях няколко примера и документацията. Получавам същата грешка при пропускане.   -  person hjk321    schedule 26.06.2016
comment
Вероятно поради оператора var, който няма да върне самия обект. Само обектът, увит в скоби, може да работи. Скобите ще са необходими за валидна програма.   -  person    schedule 26.06.2016
comment
@squint OP има грешка при компилиране (грешката с невалиден токен, спомената в коментара към оператора println()), а не грешка по време на изпълнение. Вижте моя отговор защо.   -  person Andreas    schedule 26.06.2016
comment
@Andreas: Знам, вижте първия ми коментар. Просто казвам, че нито var obj = { value: 1 };, нито { value: 1 }; вероятно биха работили, защото нито един оператор сам по себе си не произвежда обект, докато ({value: 1}) би могъл.   -  person    schedule 26.06.2016


Отговори (1)


Забележка: Следното е за Java 8, използвайки Двигател Nashorn.

Първо, за да накарате кода да се компилира, премахнете .value от оператора println(). obj е деклариран като тип Object, а Object няма поле value.

След като направите това, получавате следното изключение при изпълнение на кода:

Exception in thread "main" javax.script.ScriptException: <eval>:1:25 Invalid return statement
var obj = { value: 1 };  return obj; 
                         ^ in <eval> at line number 1 at column number 25

Това е така, защото нямате функция, така че не можете да извикате return. Върнатата стойност на скрипта е стойността на последния израз, така че просто кажете obj.

Сега ще се стартира и ще отпечата [object Object]. За да видите какъв тип обект сте върнали, променете на println(obj.getClass().getName()). Това ще отпечата jdk.nashorn.api.scripting.ScriptObjectMirror< /a>. Свързах се с javadoc за ваше удобство.

ScriptObjectMirror внедрява Bindings което от своя страна имплементира Map<String, Object>, така че можете да извикате get("value").

Работният код е:

import javax.script.*;

public class Test {
    public static void main(String[] args) throws ScriptException {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
        Bindings obj = (Bindings)engine.eval("var obj = { value: 1 };  obj; ");
        Integer value = (Integer)obj.get("value");
        System.out.println(value); // prints: 1
    }
}

АКТУАЛИЗАЦИЯ

Целият смисъл беше да се създаде обект с функции, възможно ли е това с този двигател? Няма обект Function.

Пример за това как да направите това:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

import jdk.nashorn.api.scripting.ScriptObjectMirror;

public class Test {
    public static void main(String[] args) throws Exception {
        String script = "var f = {\n" +
                        "  value: 0,\n" +
                        "  add: function(n) {\n" +
                        "    this.value += n;\n" +
                        "    return this.value;\n" +
                        "  }\n" +
                        "};\n" +
                        "f; // return object to Java\n";
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
        ScriptObjectMirror obj = (ScriptObjectMirror)engine.eval(script);
        System.out.println("obj.value = " + obj.getMember("value"));
        System.out.println("obj.add(5): " + obj.callMember("add", 5));
        System.out.println("obj.add(-3): " + obj.callMember("add", -3));
        System.out.println("obj.value = " + obj.getMember("value"));
    }
}

ИЗХОД

obj.value = 0
obj.add(5): 5.0
obj.add(-3): 2.0
obj.value = 2.0
person Andreas    schedule 26.06.2016
comment
/tmp/java_4eJZg9/Test.java:16: error: unreported exception ScriptException; must be caught or declared to be thrown Bindings obj = (Bindings)engine.eval("var obj = { value: 1 }; obj; "); ^ 1 error в скобите след eval. - person hjk321; 26.06.2016
comment
Така че добавете throws ScriptException към main(). - person Andreas; 26.06.2016
comment
Човече, толкова съм тъп. Благодаря за помощта. - person hjk321; 26.06.2016
comment
Знам, че има отговор на този въпрос, но изглежда не мога да използвам същия код за низове. Също така, възможно ли е да зададете стойност на функция в javascript и след това да изпълните тази функция в Java? Това беше цялата цел за това, беше да се създадат динамични функции. - person hjk321; 26.06.2016
comment
Да, просто направете това, което описах. Отпечатайте името на класа на върнатия обект, за да можете да видите какво получавате. След това проверете javadoc как да го използвате. - person Andreas; 26.06.2016
comment
Целият смисъл беше да се създаде обект с функции, възможно ли е това с този двигател? Няма обект Function. - person hjk321; 26.06.2016
comment
@Adam Как бихте направили това, като се има предвид, че Bindings няма необходимите getMember(...) и callMember(...) методи? И имайте предвид, че ScriptObjectMirror implements Bindings. - person Andreas; 31.10.2019
comment
Извинения, бърках ScriptObjectMirror като вътрешен JDK клас, тъй като Eclipse го криеше. Очевидно не е така. В много по-прост случай на употреба използвах get() вместо getMember() за достъп до променливи. - person Adam; 31.10.2019