Rhino:Java 数字不像 Java 脚本数字
Rhino: Java numbers don't behave like Javascript numbers
我有一个 Java class 的实例可以在我的 Java 脚本程序中访问
public class ContentProvider {
public Object c(int n) {
switch (n) {
case 1: return 1.1;
case 2: return 2.2;
case 3: return 3.3;
case 4: return "4";
case 5: return new java.util.Date();
}
return null;
}
}
这是 main() 中的代码:
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
engine.put("ctx", new ContentProvider());
res = engine.eval("ctx.c(1)");
System.out.printf("rhino:> %s (%s)%n"
, res
, res != null ? res.getClass().getName() : null
);
简单表达式 ctx.c(1)
输出:
rhino:> 1.1 (java.lang.Double)
现在 ctx.c(1) + ctx.c(2)
发生了什么:
rhino:> 1.12.2 (java.lang.String)
最后 (ctx.c(1) + ctx.c(2)) * ctx.c(3)
:
rhino:> nan (java.lang.Double)
Rhino 正在执行字符串连接而不是数字算术!以下程序按预期运行:
engine.put("a", 1.1);
engine.put("b", 2.2);
engine.put("c", 3.3);
res = engine.eval("(a + b) * c");
输出:
rhino:> 10,89 (java.lang.Double)
我创建了一个值包装器:
public static class JSValue extends sun.org.mozilla.javascript.internal.ScriptableObject
{
Object value;
public JSValue(Object value) {
this.value = value;
}
public String getClassName() {
return value != null? value.getClass().getName(): null;
}
@Override
public Object getDefaultValue(Class typeHint) {
if (typeHint == null || Number.class.isAssignableFrom(typeHint)) {
if (value instanceof Number)
return ((Number) value).doubleValue();
}
return toString();
}
@Override
public String toString() {
return value != null? value.toString(): null;
}
}
和编辑功能:
public static class ContentProvider {
public Object c(int n) {
... return new JSValue(1.1);
现在表达式按预期工作了。谢谢大家
这是 Rhino 的一个奇怪功能:Java Number
设置为 engine.put("one", new Double(1))
可以正常工作,而 Java 方法的结果取决于 return 方法本身声明的类型,通过反射读取 API:
- 如果是原语,比如
double
,它会被转换成Java脚本编号
- 否则它会像其他宿主对象一样处理,
+
表示串联,就像您的示例中的 Object
以及 Double
您可以在当前 Context
的 WrapFactory
上使用 wrapFactory.setJavaPrimitiveWrap(false)
配置此行为。这样,Rhino 代码可以保存在程序的 bootstrap 行中,并且不会使 ContentProvider
混乱(我猜这是某种配置代理)
来自live Javadoc of WrapFactory.isJavaPrimitiveWrap()
By default the method returns true to indicate that instances of
String, Number, Boolean and Character should be wrapped as any other
Java object and scripts can access any Java method available in these
objects
因此您可以将此标志设置为 false
以指示 Java Number
应转换为 Java 脚本数字。只需两行代码
Context ctx = Context.enter();
ctx.getWrapFactory().setJavaPrimitiveWrap(false);
这里是 the Gist 我用来测试的完整代码
我有一个 Java class 的实例可以在我的 Java 脚本程序中访问
public class ContentProvider {
public Object c(int n) {
switch (n) {
case 1: return 1.1;
case 2: return 2.2;
case 3: return 3.3;
case 4: return "4";
case 5: return new java.util.Date();
}
return null;
}
}
这是 main() 中的代码:
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("JavaScript");
engine.put("ctx", new ContentProvider());
res = engine.eval("ctx.c(1)");
System.out.printf("rhino:> %s (%s)%n"
, res
, res != null ? res.getClass().getName() : null
);
简单表达式 ctx.c(1)
输出:
rhino:> 1.1 (java.lang.Double)
现在 ctx.c(1) + ctx.c(2)
发生了什么:
rhino:> 1.12.2 (java.lang.String)
最后 (ctx.c(1) + ctx.c(2)) * ctx.c(3)
:
rhino:> nan (java.lang.Double)
Rhino 正在执行字符串连接而不是数字算术!以下程序按预期运行:
engine.put("a", 1.1);
engine.put("b", 2.2);
engine.put("c", 3.3);
res = engine.eval("(a + b) * c");
输出:
rhino:> 10,89 (java.lang.Double)
我创建了一个值包装器:
public static class JSValue extends sun.org.mozilla.javascript.internal.ScriptableObject
{
Object value;
public JSValue(Object value) {
this.value = value;
}
public String getClassName() {
return value != null? value.getClass().getName(): null;
}
@Override
public Object getDefaultValue(Class typeHint) {
if (typeHint == null || Number.class.isAssignableFrom(typeHint)) {
if (value instanceof Number)
return ((Number) value).doubleValue();
}
return toString();
}
@Override
public String toString() {
return value != null? value.toString(): null;
}
}
和编辑功能:
public static class ContentProvider {
public Object c(int n) {
... return new JSValue(1.1);
现在表达式按预期工作了。谢谢大家
这是 Rhino 的一个奇怪功能:Java Number
设置为 engine.put("one", new Double(1))
可以正常工作,而 Java 方法的结果取决于 return 方法本身声明的类型,通过反射读取 API:
- 如果是原语,比如
double
,它会被转换成Java脚本编号 - 否则它会像其他宿主对象一样处理,
+
表示串联,就像您的示例中的Object
以及Double
您可以在当前 Context
的 WrapFactory
上使用 wrapFactory.setJavaPrimitiveWrap(false)
配置此行为。这样,Rhino 代码可以保存在程序的 bootstrap 行中,并且不会使 ContentProvider
混乱(我猜这是某种配置代理)
来自live Javadoc of WrapFactory.isJavaPrimitiveWrap()
By default the method returns true to indicate that instances of String, Number, Boolean and Character should be wrapped as any other Java object and scripts can access any Java method available in these objects
因此您可以将此标志设置为 false
以指示 Java Number
应转换为 Java 脚本数字。只需两行代码
Context ctx = Context.enter();
ctx.getWrapFactory().setJavaPrimitiveWrap(false);
这里是 the Gist 我用来测试的完整代码