Buscar..


Introducción

Java en sí mismo es un lenguaje extremadamente poderoso, pero su poder se puede extender aún más gracias a JSR223 (Solicitud de especificación de Java 223) que presenta un motor de script

Observaciones

La API de scripting de Java permite que los scripts externos interactúen con Java

La API de scripting puede permitir la interacción entre el script y java. Los lenguajes de scripting deben tener una implementación de Script Engine en el classpath.

Por defecto, JavaScript (también conocido como ECMAScript) es proporcionado por nashorn de forma predeterminada. Cada Script Engine tiene un contexto de script donde todas las variables, funciones y métodos se almacenan en enlaces. En ocasiones, es posible que desee utilizar varios contextos, ya que admiten la redirección de la salida a un Escritor con búfer y el error a otro.

Hay muchas otras bibliotecas de motor de script como Jython y JRuby. Mientras estén en la ruta de clase, puede evaluar el código.

Podemos usar enlaces para exponer variables en el script. Necesitamos varios enlaces en algunos casos, ya que la exposición de las variables al motor básicamente consiste en exponer las variables solo a ese motor, a veces es necesario exponer ciertas variables como el entorno del sistema y la ruta que es la misma para todos los motores del mismo tipo. En ese caso, requerimos un enlace que es un alcance global. Exponer las variables que lo exponen a todos los motores de script creados por el mismo EngineFactory

Evaluando un archivo javascript en modo de script de nashorn

public class JSEngine {
    
    /*
    * Note Nashorn is only available for Java-8 onwards
    * You can use rhino from ScriptEngineManager.getEngineByName("js");
    */
    
    ScriptEngine engine;
    ScriptContext context;
    public Bindings scope;
    
    // Initialize the Engine from its factory in scripting mode
    public JSEngine(){
        engine = new NashornScriptEngineFactory().getScriptEngine("-scripting");
        // Script context is an interface so we need an implementation of it
        context = new SimpleScriptContext();
        // Create bindings to expose variables into
        scope = engine.createBindings();
    }
    
    // Clear the bindings to remove the previous variables
    public void newBatch(){
        scope.clear();
    }
    
    public void execute(String file){
        try {
            // Get a buffered reader for input
            BufferedReader br = new BufferedReader(new FileReader(file));
            // Evaluate code, with input as bufferdReader
            engine.eval(br);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(JSEngine.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ScriptException ex) {
            // Script Exception is basically when there is an error in script
            Logger.getLogger(JSEngine.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void eval(String code){
        try {
            // Engine.eval basically treats any string as a line of code and evaluates it, executes it
            engine.eval(code);
        } catch (ScriptException ex) {
            // Script Exception is basically when there is an error in script
            Logger.getLogger(JSEngine.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    // Apply the bindings to the context and set the engine's default context
    public void startBatch(int SCP){
        context.setBindings(scope, SCP);
        engine.setContext(context);
    }
    
    // We use the invocable interface to access methods from the script
    // Invocable is an optional interface, please check if your engine implements it
    public Invocable invocable(){
        return (Invocable)engine;
    }
    
}

Ahora el método principal

public static void main(String[] args) {
    JSEngine jse = new JSEngine();
    // Create a new batch probably unecessary
    jse.newBatch();
    // Expose variable x into script with value of hello world
    jse.scope.put("x", "hello world");
    // Apply the bindings and start the batch
    jse.startBatch(ScriptContext.ENGINE_SCOPE);
    // Evaluate the code
    jse.eval("print(x);");
}

Su salida debe ser similar a esta
hello world

Como se puede ver la variable expuesta x se ha impreso. Ahora probando con un archivo.

Aquí tenemos test.js

print(x);
function test(){
    print("hello test.js:test");
}
test();

Y el método principal actualizado.

public static void main(String[] args) {
    JSEngine jse = new JSEngine();
    // Create a new batch probably unecessary
    jse.newBatch();
    // Expose variable x into script with value of hello world
    jse.scope.put("x", "hello world");
    // Apply the bindings and start the batch
    jse.startBatch(ScriptContext.ENGINE_SCOPE);
    // Evaluate the code
    jse.execute("./test.js");
}

Suponiendo que test.js está en el mismo directorio que su aplicación, debería tener una salida similar a esta

hello world
hello test.js:test


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow