8

我正在调用一个带@JSFunction注释的方法ScriptableObject

JavaScript 文件

Target = Packages.com.acme.rhino.Target;

function evaluate() {
    var t = Target();
    t.addModifier("foobar", 1);
    return t;
}

Java 文件

public class Target extends ScriptableObject {
    private static final long serialVersionUID = 1L;
    public List<Modifier> modifiers = new LinkedList<>();

    @JSConstructor
    public Target() {
    }

    @JSFunction
    public void addModifier(final String message, final int value) {
        modifiers.add(new Modifier(message, value));
    }

    public int getValue() {
        int sum = 0;
        for (final Modifier modifier : modifiers) {
            sum += modifier.getValue();
        }
        return sum;
    }

    @Override
    public String getClassName() {
        return "Target";
    }
}

但我明白了

org.mozilla.javascript.EcmaError: TypeError: Cannot find default value for object.
    at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3687)
    at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3665)
    at org.mozilla.javascript.ScriptRuntime.typeError(ScriptRuntime.java:3693)
    at org.mozilla.javascript.ScriptRuntime.typeError1(ScriptRuntime.java:3705)
    at org.mozilla.javascript.ScriptableObject.getDefaultValue(ScriptableObject.java:976    )
    at org.mozilla.javascript.ScriptableObject.getDefaultValue(ScriptableObject.java:895    )
    at org.mozilla.javascript.ScriptRuntime.toString(ScriptRuntime.java:761)
    at org.mozilla.javascript.ScriptRuntime.notFunctionError(ScriptRuntime.java:3774)
    at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThisHelper(ScriptRuntime.    java:2269)
    at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime.    java:2251)
    at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:83)
    at org.mozilla.javascript.gen.script_5._c_evaluate_1(script:6)
    at org.mozilla.javascript.gen.script_5.call(script)
    at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:394)
    at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3091)
    at org.mozilla.javascript.gen.script_5.call(script)

不知道从那里去哪里。当我不调用addModifier方法时,给定的代码有效,并且notFunctionError在堆栈跟踪中给出错误,我认为 Rhino 不会将给定的方法解释为 JavaScript 函数。

  • OSX 10.8.2
  • 爪哇 7
  • 犀牛1.7R4

可以在此处找到重现错误的完整 Maven 项目

4

2 回答 2

3

tl;博士看到 两种选择。

上述方法的问题Target.prototype在于未在脚本范围内正确设置。ScriptableObject.defineClass()有关如何在脚本范围内正确定义原型的详细信息,请参阅静态方法。

您有几个选择来为Target您的脚本提供构造函数。第一种选择是始终Target为所有脚本定义构造函数。如果您提前知道要Target在全球范围内可用,则此方法效果很好。这基本上归结为以下几点:

final Context context = Context.enter();
try {
  final ScriptableObject scope = context.initStandardObjects();
  ScriptableObject.defineClass(scope, Target.class, false, true);
  context.evaluateString(scope, script, "script", 1, null);
  // etc.
} finally {
  Context.exit();
}

相反,如果您希望脚本作者决定哪些构造函数是必需的,则第二种选择是将defineClass函数提供给脚本。使用此功能,脚本作者可以在其类路径上“导入”任何可编写脚本的对象(这可能超出您的允许范围)。要为defineClass脚本提供功能,请在进入上下文后执行以下操作:

final Context context = Context.enter();
try {
  final ScriptableObject scope = context.initStandardObjects();
  scope.defineFunctionProperties(
          new String[] {"defineClass"},
          Global.class,
          ScriptableObject.DONTENUM);

  context.evaluateString(scope, script, "script", 1, null);
  // etc.
} finally {
  Context.exit();
}

然后,JavaScript 作者使用Target以下构造函数:

defineClass("com.acme.rhino.Target");
// whatever `getClassName()` returns is now available
var target = new Target();

在上述两个分支中,如果您向Target构造函数添加更多内容,我还进行了一些其他更改,这些更改可以让您更好地设置。零参数构造函数不需要@JSConstructor注释。如果您以后想要一个接受参数的构造函数,这个零参数构造函数将用作原型构造函数,并且您可以@JSConstructor在用于初始化对象的方法上使用注释。根据您编写此构造方法的方式,new在 JavaScript 中使用关键字将变得很重要。

简而言之,Packages.com.acme...语法对于从脚本访问构造函数没有用处。ScriptableObject

于 2013-01-29T17:34:03.863 回答
0

我通过使用 new 运算符让它工作(非常相似的代码)。在你的例子中

 function evaluate() {
      var t = new Target();
      ...

应该也可以。

于 2016-09-26T20:42:21.843 回答