从 JavaScript 调用 @JSFunction,TypeError:找不到对象的默认值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14561874/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling @JSFunction from JavaScript, TypeError: Cannot find default value for object
提问by oschrenk
I'm calling a @JSFunction
annotated method of a ScriptableObject
我正在调用一个带@JSFunction
注释的方法ScriptableObject
The JavaScript file
JavaScript 文件
Target = Packages.com.acme.rhino.Target;
function evaluate() {
var t = Target();
t.addModifier("foobar", 1);
return t;
}
The Java File
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";
}
}
But I get
但我得到
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)
and don't know where to go from there. When I don't call addModifier
method the given code works, and given the error notFunctionError
down in the stack trace I think that Rhino doesn't interpret the given method as a JavaScript Function.
不知道从那里去哪里。当我不调用addModifier
方法时,给定的代码有效,并且notFunctionError
在堆栈跟踪中给出了错误,我认为 Rhino 不会将给定的方法解释为 JavaScript 函数。
- OSX 10.8.2
- Java 7
- Rhino 1.7R4
- OSX 10.8.2
- 爪哇 7
- 犀牛1.7R4
Complete Maven project that reproduces the error can be found here
可以在此处找到重现错误的完整 Maven 项目
采纳答案by Tim Schaub
tl;dr see thesetwoalternatives.
The problem with the approach above is that Target.prototype
is not properly set up in the script scope. See the static ScriptableObject.defineClass()
method for details on how to properly define prototypes in a script scope.
上述方法的问题Target.prototype
在于未在脚本范围内正确设置。有关ScriptableObject.defineClass()
如何在脚本范围内正确定义原型的详细信息,请参阅静态方法。
You have a couple alternatives for providing the Target
constructor to your scripts. The first alternativewould be to always define the Target
constructor for all scripts. This works well if you know ahead of time that you want Target
to be globally available. This basically comes down to the following:
您有几种替代方法可以为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();
}
If instead you want the script author to decide which constructors are necessary, the second alternativeis to provide the defineClass
function to scripts. With this function, script authors can "import" any scriptable objects on their class path (which may be more than you want to allow). To provide the defineClass
functions to scripts, do the following after entering the context:
相反,如果您希望脚本作者决定哪些构造函数是必需的,则第二种选择是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();
}
And then, the JavaScript author makes use of the Target
constructor with the following:
然后,JavaScript 作者使用Target
具有以下内容的构造函数:
defineClass("com.acme.rhino.Target");
// whatever `getClassName()` returns is now available
var target = new Target();
In both of the above branches, I've made a couple other changes that set you up better if you add more to the Target
constructor. The zero argument constructor doesn't need the @JSConstructor
annotation. If you later want to have a constructor that accepts arguments, this zero argument constructor will be used as the prototype constructor, and you can use the @JSConstructor
annotation on a method that will be used to initialize your object. Depending on how you author this constructor method, it will become important to use the new
keyword in your JavaScript.
在上述两个分支中,我做了一些其他更改,如果您向Target
构造函数添加更多内容,这些更改会更好。零参数构造函数不需要@JSConstructor
注释。如果您以后想要一个接受参数的构造函数,这个零参数构造函数将用作原型构造函数,您可以@JSConstructor
在将用于初始化对象的方法上使用注释。根据您编写此构造函数方法的方式,new
在 JavaScript 中使用关键字变得很重要。
In short, the Packages.com.acme...
syntax is notuseful for getting access to ScriptableObject
constructors from scripts.
简而言之,Packages.com.acme...
语法对于从脚本访问构造函数没有用ScriptableObject
。
回答by elxala
I get it working (very similar code) by using the new operator. In your example doing
我通过使用 new 运算符让它工作(非常相似的代码)。在你的例子中
function evaluate() {
var t = new Target();
...
should work as well.
也应该工作。