简体   繁体   English

使用Rhino和JSR-223读取JSON文件

[英]Using Rhino and JSR-223 to read a JSON file

I'm trying to read a JSON file with some JavaScript that I'm eval-ing with Rhino through the Java JSR-223 API. 我正在尝试使用一些JavaScript来读取JSON文件,我正在通过Java JSR-223 API与Rhino一起评估。 What I'm trying to do works with the Rhino shell, but not with the embedded Javascript in my Java code. 我正在尝试使用Rhino shell,但不能使用我的Java代码中的嵌入式Javascript。

Here's what works: 这是有效的:

$ java -jar js.jar
js> readFile('foo.json');
{y:"abc"}

Here is what does not work: 这是不起作用的:

ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("js");
engine.eval("readFile('foo.json')"); 

I get this error: 我收到此错误:

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)

How can i get the readFile to be available in my engine? 如何让readFile在我的引擎中可用?

If you are just trying to parse JSON , I would suggest using a JSON parsing library like Jackson or Jettison , it's a much easier approach. 如果您只是想解析JSON ,我建议使用像JacksonJettison这样的JSON解析库,这是一种更简单的方法。 The readFile call returns a string, and it is not actually converting the contents into a JavaScript object. readFile调用返回一个字符串,它实际上并没有将内容转换为JavaScript对象。 A JSON.parse or JavaScript eval call on the string would be needed in order to accomplish that. 为了实现这一点,需要对字符串进行JSON.parse或JavaScript eval调用。

If you really need to use the JavaScript engine to parse JSON and you were using Java 7 you could do something like this (but I wouldn't advise it)... 如果你真的需要使用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;
}

The JavaScript engine provided in Java has excluded some of the features provided in Rhino. Java中提供的JavaScript引擎排除了Rhino中提供的一些功能。 The readFile function is actually provided by the Rhino Shell , not the engine implementation. readFile函数实际上是由Rhino Shell提供的,而不是引擎实现。 Oracle also provides functions accessible by the jrunscript shell which are not in the engine. Oracle 还提供jrunscript shell可以访问的函数 ,这些函数不在引擎中。

Here's an example that mimics the Rhino shell readFile function and adds it to the JavaScript scope based upon the answer to this question: How can I add methods from a Java class as global functions in Javascript using Rhino? 这是一个模仿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();
            }
        }
    }
}

You can always just leverage the relevant Java classes to slurp in the JSON file, then decorate it so it's suitable for an eval(). 您总是可以利用相关的Java类来填充JSON文件,然后进行修饰以使其适用于eval()。

It can be done neatly in one line. 它可以在一条线上整齐地完成。 For example given the following: 例如,给出以下内容:

cfg.json: cfg.json:

{     
    myopts: {
        username: "tee",
        password: "password"
    }
}

And the following Javascript: 以下Javascript:

cfg = eval('(' + new java.util.Scanner( new java.io.File('cfg.json') ).useDelimiter("\\A").next() + ')');

You can now access your JSON in Javascript via: 您现在可以通过以下方式在Javascript中访问您的JSON:

log.info("Username: " + cfg.myopts.username ); // "Username: tee"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM