2015-03-13 110 views
1

我正在編寫一個Scala應用程序(應該使用Spark在Hadoop上運行),我的用戶需要執行他們上傳的JavaScript代碼段,並且我想提供對某些寫入的幫助函數的訪問在Scala中(比如「發送HTTP呼叫」等)給這些JavaScript用戶。所以我要做的就是寫一個大JavaScriptHelpers對象,然後使用訪問Java對象中的JavaScript對象的字段

engine = scriptEngineManager.getEngineByName("JavaScript") 
engine.put("jql", JavaScriptHelpers) 

這樣用戶就可以說在JavaScript jql.httpPost(...)給訪問該對象。斯卡拉代碼,使這成爲可能看起來如下:

def httpPost(where: String, params: Object): Try[String] = { 
    params match { 
    // JavaScript string becomes Java's String: 
    case body: String => 
     // ... 

    // JavaScript object becomes Java's ScriptableObject 
    case obj: ScriptableObject => 
     val params = convertToMap(obj) 
     // ... 
    } 
} 

protected def convertToMap(obj: ScriptableObject): Map[String, String] = { 
    (for (key <- obj.getIds().toList) yield { 
    (key.toString, obj.get(key) match { 
     case s: String => 
     s 
     case d: java.lang.Double if d.toString.endsWith(".0") => 
     d.toInt.toString 
     case other => other.toString 
    }) 
    }).toMap 
} 

我發現訪問存儲在JavaScript對象信息的唯一途徑是在他們看作爲sun.org.mozilla.javascript.ScriptableObject一個實例。現在,這就像我本地的OpenJDK安裝一個魅力

java version "1.7.0_75" 
OpenJDK Runtime Environment (fedora-2.5.4.2.fc20-x86_64 u75-b13) 
OpenJDK 64-Bit Server VM (build 24.75-b04, mixed mode) 

,但是當我在我的Hadoop集羣,這是運行

java version "1.7.0_67" 
Java(TM) SE Runtime Environment (build 1.7.0_67-b01) 
Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode) 

上運行相同的代碼,然後我得到:

java.lang.NoClassDefFoundError: sun/org/mozilla/javascript/ScriptableObject 
    sun.org.mozilla.javascript.internal.JavaMembers.discoverAccessibleMethods(JavaMembers.java:383) 
    sun.org.mozilla.javascript.internal.JavaMembers.discoverAccessibleMethods(JavaMembers.java:335) 
    sun.org.mozilla.javascript.internal.JavaMembers.reflect(JavaMembers.java:455) 
    sun.org.mozilla.javascript.internal.JavaMembers.<init>(JavaMembers.java:76) 
    sun.org.mozilla.javascript.internal.JavaMembers.lookupClass(JavaMembers.java:847) 
    sun.org.mozilla.javascript.internal.NativeJavaObject.initMembers(NativeJavaObject.java:88) 
    sun.org.mozilla.javascript.internal.NativeJavaObject.<init>(NativeJavaObject.java:78) 
    sun.org.mozilla.javascript.internal.NativeJavaObject.<init>(NativeJavaObject.java:68) 
    ... 

並查看Oracle與JDK 7捆綁在一起的Rhino版本,從http://www.oracle.com/technetwork/opensource/jdk7-source-1634015.html可下載,似乎所有的sun.org.mozilla.javascript.*類已被移至sun.org.mozilla.javascript.internal.*

現在我該如何處理這種情況?是否有任何Rhino獨立的方式訪問Java中的JavaScript對象的字段?或者,如何強制Oracle JVM在本地環境中使用...javascript.internal.ScriptableObject而使用...javascript.ScriptableObject

任何幫助非常感謝。

+0

嗯。出於我的想法:您正在爲用戶提供帶有Jacascript語法的DomainSpecificLanguage。您是否看過JSR 233?另外轉換一個Javascript對象有很多庫已經涵蓋了這個話題,我的第一個命中是http://stackoverflow.com/questions/1395551/convert-a-json-string-to-object-in-java – 2015-03-13 11:09:10

回答

1

您可以改用函數重載。

// `params` matches a JavaScript string 
def httpPost(where: String, params: String): Try[String] = { 
    // ... 
} 

// `params` matches a JavaScript object 
def httpPost(where: String, params: java.util.Map[_, _]): Try[String] = { 
    // ... 
} 

該解決方案適用於我的環境(Oracle JDK 8和OpenJDK 1.7)。

+0

非常感謝你很多,這工作!請注意,即使存在來自scala.collection.JavaConversions的隱式轉換,它確實應該是java.util.Map而不是Scala的Map。 – tgpfeiffer 2015-03-16 01:56:36