2016-05-03 2 views
0

Типичный JSR-223 сценарий будет начинаться с серией суррогатного импорта, как это (JavaScript + Nashorn выбранного для примера):Как передать типы и функции сценарию JSR-223?

// "import" classes and static methods 
var Foo = Java.type("my.package.Foo"); // application classes require Java.type() use 
var bar = Foo.bar; // static method 
var Logger = java.util.logging.Logger; // system classes can be accessed directly 
var sin = java.lang.Math.sin; // the same for static methods 

// use them 
var foo = new Foo(); 
print(bar()); 
var log = Logger.getLogger("foo"); 
print(sin(42)); 

Я хочу, чтобы избавиться от этих суррогатов, подражая импортный подобные функциональные возможности для скриптов , Это означает, что я хочу иметь глобальные объекты (например, Foo, bar, Logger и sin в приведенном выше примере), созданный моим кодом Java. Это должно автоматически сделать общий набор импорта доступным для нескольких сценариев.

Я нашел два способа сделать это с Nashorn:

Метод 1: создать сценарий прелюдии и eval() его перед основным скриптом. Это будет буквально первая половина кода примера выше.

Метод 2: Получение ссылки на класс и метод из ScriptEngine, кэширует их и использовать для последующих вызовов сценария:

ScriptEngineManager sem = new ScriptEngineManager(); 
ScriptEngine nashorn = sem.getEngineByName("nashorn"); 

Object fooClass = nashorn.eval("Java.type('my.package.Foo')"); // instance of jdk.internal.dynalink.beans.StaticClass 
Object loggerClass = nashorn.eval("java.util.logging.Logger"); // the same 

Object barFunction = nashorn.eval("Java.type('my.package.Foo').bar"); // instance of jdk.internal.dynalink.beans.SimpleDynamicMethod 
Object sinFunction = nashorn.eval("java.lang.Math.sin"); // the same 

ScriptEngine nashorn1 = sem.getEngineByName("nashorn"); 

nashorn1.put("Foo", fooClass); 
nashorn1.put("bar", barFunction); 
nashorn1.put("Logger", loggerClass); 
nashorn1.put("sin", sinFunction); 
nashorn1.eval("var foo = new Foo(); bar(); var log = Logger.getLogger('foo'); print(sin(42));"); 

Очевидно, что ни один из этих методов не будет работать для любого другого JSR-223 двигатель. Есть ли способ реализовать то же самое в переносном режиме?

+0

Имейте [здесь] (http://stackoverflow.com/questions/36968431/nashorn-how-to-pre-set-java-type-vars-inside-of-java-before-javascript-execut) – Zsolt

ответ

0

Я понятия не имею, как решить проблему в отношении новой операции (как избежать вызовов на Java.type()).

Но когда вы скомпилировать скрипт, вы можете назначить методы, как лямбды:

ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); 
Compilable nashorn = (Compilable) scriptEngineManager.getEngineByName("Nashorn"); 

CompiledScript script = nashorn.compile("print(sin(3.14)); var log = getLogger('foo');"); 

Bindings bindings = new SimpleBindings(); 
bindings.put("sin", (DoubleFunction<Double>) Math::sin); 
bindings.put("getLogger", (Function<String,Logger>) Logger::getLogger); 

script.eval(bindings); 

Для метода void bar() (нет аргументов, нет возвращаемого значения), вы должны предоставить свой собственный функциональный интерфейс, как java.util.function пакет не имеет такого метода.

К сожалению, этот подход, похоже, не работает для не-скомпилированных скриптов. И это не работает для всех типов лямбда (функциональных интерфейсов). Я сделал несколько экспериментов, но не смог найти шаблон, но что работает, а что нет. Несомненно, что функциональные интерфейсы, которые определяют метод, бросающий проверенное исключение, не работают таким образом. Также, если функциональный интерфейс не является общедоступным, а является частным внутренним интерфейсом.

Должно быть очевидно, что я пропустил ненужные обработки ошибок и блоки try-catch из приведенного выше кода примера.

Смежные вопросы