2015-05-12 47 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); 

現在該表達按預期工作。謝謝大家。