Rhino: Как передать Java-объект в скрипт, где его можно назвать «this» - PullRequest
3 голосов
/ 15 июля 2011

Я новичок в JSR-223 Java Scripting, на самом деле я переключаюсь с MVEL на стандарт Mozilla Rhino JS .Я прочитал всю документацию, но застрял.Я пытался ссылаться на некоторые объекты Java из скрипта с помощью привязок, как в учебном пособии:

    // my object
    public class MyBean {
       public String getStringValue() { return "abc" };
    }

    // initialization
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");

    // add bindings
    engine.put("bean", new MyBean());

    // evaluate script, output is "abc"
    engine.eval("print(bean.stringValue)");

На объект Java ссылаются из скрипта как свойство bean.Все идет нормально.

Но я хочу ссылаться на свой объект в скрипте как this, я хочу использовать его свойства и методы без префикса или явно с префиксом this.Вот так:

    // add bindings
    engine.put(....., new MyBean()); // or whatever ???

    // evaluate scripts, all have the same output "abc"
    engine.eval("print(stringValue)");
    engine.eval("print(this.stringValue)");

Я знаю, что this в JavaScript имеет особое значение (как в Java), но в сценариях MVEL это можно сделать с помощью пользовательских ParserContext иобычай PropertyHandler.

Возможно ли что-то подобное в Rhino?

Большое спасибо.

Ответы [ 2 ]

1 голос
/ 20 июля 2011

Я пытаюсь реализовать эту идею из ответа от Pointy (еще раз спасибо), но этот обходной путь не работает для свойств без префикса this, который кажется ИМХО тем же.Вместо использования Rhino 1.5 из Java API существует оригинальный Rhino 1.7 от Mozilla.Тестовый пример здесь:

import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Wrapper;

public class RhinoTest2 {

  private Obj obj = new Obj();

  public class Obj {
    public String getStringValue() {
      return "abc";
    }
  }

  private Object eval(String expression) {
    Context cx = Context.enter();
    try {
      ScriptableObject scope = cx.initStandardObjects();

      // convert my "this" instance to JavaScript object  
      Object jsObj = Context.javaToJS(obj, scope);

      // prepare envelope function run()    
      cx.evaluateString(scope, 
        String.format("function run() { %s }", expression), 
        "<func>", 1, null);

      // call method run()
      Object fObj = scope.get("run", scope);
      Function f = (Function) fObj;
      Object result = f.call(cx, scope, (Scriptable) jsObj, null);
      if (result instanceof Wrapper)
        return ((Wrapper) result).unwrap();
      return result;

    } finally {
      Context.exit();
    }
  }

  @Test
  public void test() {

    // works
    eval("return this.getStringValue()");
    eval("return this.stringValue");

    // doesn't work, throws EcmaError: ReferenceError: "getStringValue" is not defined.
    eval("return getStringValue()");
    eval("return stringValue");
  }
}

Почему this.getStringValue()/this.stringValue работает, а getStringValue()/stringValue нет?Какой-то пункт упущен?Заостренный

1 голос
/ 15 июля 2011

Что ж, в JavaScript действительно имеет смысл думать о том, что this устанавливается в контексте вызываемой функции.Поэтому я думаю, что вы должны иметь возможность использовать метод «invoke» в ScriptEngine (который должен быть приведен к «Invocable»):

  ((Invocable) engine).invokeMethod(objectForThis, "yourFunction", arg, arg ...);

Теперь ссылка «objectForThis» (по моему опыту)как правило, то, что было возвращено из предыдущего вызова «eval ()» (или «invokeMethod», я думаю);другими словами, это должен быть объект на соответствующем языке для скриптового движка.Можете ли вы передать туда Java-объект (и он сработает), я точно не знаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...