[英]How to access Java exception that causes ScriptException using JSR-223
[英]Using Rhino and JSR-223 to read a JSON file
我正在嘗試使用一些JavaScript來讀取JSON文件,我正在通過Java JSR-223 API與Rhino一起評估。 我正在嘗試使用Rhino shell,但不能使用我的Java代碼中的嵌入式Javascript。
這是有效的:
$ java -jar js.jar
js> readFile('foo.json');
{y:"abc"}
這是不起作用的:
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("js");
engine.eval("readFile('foo.json')");
我收到此錯誤:
Exception in thread "main" javax.script.ScriptException:
sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "readFile" is not defined. (<Unknown source>#4) in <Unknown source> at line number 4
at com.sun.script.javascript.RhinoScriptEngine.eval(RhinoScriptEngine.java:153)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:232)
如何讓readFile
在我的引擎中可用?
如果您只是想解析JSON ,我建議使用像Jackson或Jettison這樣的JSON解析庫,這是一種更簡單的方法。 readFile調用返回一個字符串,它實際上並沒有將內容轉換為JavaScript對象。 為了實現這一點,需要對字符串進行JSON.parse或JavaScript eval調用。
如果你真的需要使用JavaScript引擎解析JSON而你使用的是Java 7,你可以做這樣的事情(但我不建議)......
public static void main(final String args[]) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("js");
Object val = null;
Scanner s = null;
try {
s = new Scanner(new File("foo.json"));
s.useDelimiter("\\Z");
engine.getBindings(ScriptContext.GLOBAL_SCOPE).put("json", s.next());
} finally {
if (s != null) {
s.close();
}
}
// The default JavaScript engine in Java 6 does not have JSON.parse
// but eval('(' + json + ')') would work
val = engine.eval("JSON.parse(json)");
// The default value is probably a JavaScript internal object and not very useful
System.out.println(val.getClass() + " = " + val);
// Java 7 uses Rhino 1.7R3 the objects will implement Map or List where appropriate
// So in Java 7 we can turn this into something a little more useable
// This is where Java 6 breaks down, in Java 6 you would have to use the
// sun.org.mozilla.javascript.internal classes to get any useful data
System.out.println(convert(val));
}
@SuppressWarnings("unchecked")
public static Object convert(final Object val) {
if (val instanceof Map) {
final Map<String, Object> result = new HashMap<String, Object>();
for (final Map.Entry<String, Object> entry: ((Map<String, Object>) val).entrySet()) {
result.put(entry.getKey(), convert(entry.getValue()));
}
return result;
} else if (val instanceof List) {
final List<Object> result = new ArrayList<Object>();
for (final Object item: ((List<Object>) val)) {
result.add(convert(item));
}
return result;
}
if (val != null) {
System.out.println(val.getClass() + " = " + val);
}
return val;
}
Java中提供的JavaScript引擎排除了Rhino中提供的一些功能。 readFile函數實際上是由Rhino Shell提供的,而不是引擎實現。 Oracle 還提供了jrunscript shell可以訪問的函數 ,這些函數不在引擎中。
這是一個模仿Rhino shell readFile函數的示例,並根據此問題的答案將其添加到JavaScript范圍: 如何使用Rhino將Java類中的方法添加為Javascript中的全局函數?
public static void main(final String args[]) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("js");
engine.getBindings(ScriptContext.GLOBAL_SCOPE).put("utils", new Utils());
engine.eval("for(var fn in utils) {\r\n" +
" if(typeof utils[fn] === 'function') {\r\n" +
" this[fn] = (function() {\r\n" +
" var method = utils[fn];\r\n" +
" return function() {\r\n" +
" return method.apply(utils,arguments);\r\n" +
" };\r\n" +
" })();\r\n" +
" }\r\n" +
"}");
engine.eval("println(readFile('foo.json'))");
}
static class Utils {
public String readFile(final String fileName) throws FileNotFoundException {
return readFile(fileName, null);
}
public String readFile(final String fileName, final String encoding) throws FileNotFoundException {
Scanner s = null;
try {
s = new Scanner(new File(fileName), (encoding == null)? Charset.defaultCharset().name(): encoding);
s.useDelimiter("\\Z");
return s.next();
} finally {
if (s != null) {
s.close();
}
}
}
}
您總是可以利用相關的Java類來填充JSON文件,然后進行修飾以使其適用於eval()。
它可以在一條線上整齊地完成。 例如,給出以下內容:
cfg.json:
{
myopts: {
username: "tee",
password: "password"
}
}
以下Javascript:
cfg = eval('(' + new java.util.Scanner( new java.io.File('cfg.json') ).useDelimiter("\\A").next() + ')');
您現在可以通過以下方式在Javascript中訪問您的JSON:
log.info("Username: " + cfg.myopts.username ); // "Username: tee"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.