2015-10-22 8 views
2

Я пытаюсь перенести/обновить свой проект, чтобы использовать Nashorn из Rhino. У меня есть некоторые функции глобальной утилиты, реализованные в Java и добавленные в глобальную область целевого сценария, типичным примером является log(message).Добавить Java-реализованную функцию в глобальную область Nashorn

В Rhino это реализовано с помощью

public static class LogFunction extends org.mozilla.javascript.BaseFunction { 
    @Override 
    public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { 
     ... 
    } 
} 

, чей экземпляр добавляется в целевой области. Что нужно сделать в случае с Нашорном? Я не могу найти, как автономная функция может быть реализована для Nashorn.

ответ

4

Вы можете легко реализовать функции скриптов в Java. Вы просто реализуете любой интерфейс @FunctionalInterface (https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html) с использованием лямбда и выставляете то же самое, что и глобальную переменную, вызывая метод ScriptEngine.put (https://docs.oracle.com/javase/8/docs/api/javax/script/ScriptEngine.html#put-java.lang.String-java.lang.Object-). В следующем примере реализованы две такие функции скрипта, реализованные в Java-коде.

import javax.script.*; 
import java.util.function.*; 
import java.util.Random; 

public class Main { 
    public static void main(String[] args) throws Exception { 
    ScriptEngineManager m = new ScriptEngineManager(); 
    ScriptEngine e = m.getEngineByName("nashorn"); 

    // expose 'log' function - any @FunctionInterface Java 
    // object can be exposed as 'function' 
    e.put("log", (Consumer<String>)System.out::println); 

    Random r = new Random(); 
    // expose 'next gaussian' as script global function 
    e.put("gaussian", (Supplier<Double>)r::nextGaussian); 

    // call functions implemented in Java! 
    e.eval("log('hello')"); 
    e.eval("print(gaussian())"); 
    e.eval("print(gaussian())"); 
    } 
} 
1

Через некоторое время после того, как задать вопрос, я еще раз гугле и нашел этот пост: http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-December/002520.html

*) Реализовать любой интерфейс @FunctionalInterface в JDK (или ваш собственный @FunctionalInterface) и передать/положить объект того же самого в файле javax.script.Bindings или даже глобальной области. Скрипт может получить доступ к ним как , хотя это функции.

*) Внесите jdk.nashorn.api.scripting.JSObject в свой класс и реализуйте на нем метод «вызова». Опять же, гибкий дилер на основе Nashorn, основанный на , будет рассматривать ваш JSObject impl. как будто это функция. Этот может также использоваться для реализации «конструктора» (метода newObject) в Java и т. Д.

Я решил пойти с реализацией JSObject, и мой код выглядит более похожим на Rhino и ближе к моему исходному коду, чем подход, рекомендованный в ответе Sundararajan. Не уверен, есть ли разница в производительности между ними.

import jdk.nashorn.api.scripting.AbstractJSObject; 

public static class PrintFunction extends AbstractJSObject { 

    public PrintFunction() { 
    } 

    @Override 
    public boolean isFunction() { 
     return true; 
    } 

    @Override 
    public Object call(Object thiz, Object... args) { 
     ... do something ... 

     return null; 
    } 
} 

... 

void onInitScriptObjects(Bindings scope) { 
    scope.put("print", new PrintFunction()); 
} 
Смежные вопросы