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シェルからアクセスできる機能も提供します。
Rhino シェルの readFile 関数を模倣し、この質問への回答に基づいて JavaScript スコープに追加する例を次に示します:
How can I add methods from a Java class as global functions in Javascript using Rhino?
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();
}
}
}
}