2015-03-13 112 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