2015-05-12 24 views
17

我有这个Java访问类的实例在JavaScript程序犀牛:Java的数字不循规蹈矩如Javascript数字

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) 
+19

哦,我的上帝,有人实际使用的“Java”和“JavaScript的”标签一起* *正确! – immibis

+0

但为什么不尝试'engine.eval(“typeof ctx.c(1)”)'并查看JavaScript认为该类型是什么? – immibis

+0

typeof ctx.c(1)=对象 – lunicon

回答

4

这是犀牛的一个奇怪的特点:一个Java Number组与engine.put("one", new Double(1))作品如预期,而Java方法的结果取决于该方法本身声明的返回类型,它读取反射API:

  • 如果它是一个原始的,像double,它是你的样品中转换为JavaScript数字
  • 否则,就会像其他主机对象处理和+意味着串联,无论是Object等,以及Double

您可以在当前ContextWrapFactory上用wrapFactory.setJavaPrimitiveWrap(false)配置此行为。通过这种方式,犀牛代码可以被保存在你的程序的引导线,并且不扰乱ContentProvider(我猜是某种配置的代理)

live Javadoc of WrapFactory.isJavaPrimitiveWrap()

默认情况下,该方法返回true表示 字符串的情况下,数字,布尔和字符应该被包装成任何其他 Java对象和脚本可以访问任何可用的Java方法在这些 对象

因此,您可以将此标志设置为false以指示Java Number应该转换为Javascript数字。它只需两个代码

线
Context ctx = Context.enter(); 
ctx.getWrapFactory().setJavaPrimitiveWrap(false); 

这里是the Gist与完整的代码我用来测试

+0

谢谢。它应该在文档中加粗。 – lunicon

+0

同意。相反,我必须调试并下载源代码。这似乎也是一个奇怪的默认 – Raffaele

+0

我遇到了这个问题,并搜索了所有的文档,但没有找到任何东西。谢谢你节省了我的时间。 – VGaur

1

我创建了一个价值包装:

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); 

现在该表达按预期工作。谢谢大家。