はじめに
Javaでライブラリとか使わず気軽にJSONって扱えないのかなと思ってちょっと調べたメモ
Java8 で確認・検証してますが、javax.script は Java6 からあるみたい。
サンプル
お天気情報をGetで取得します。
お天気Webサービス仕様 - Weather Hacks - livedoor 天気情報
http://weather.livedoor.com/weather_hacks/webservice
public static void main(String[] args) {
try {
System.out.println("東京の天気");
URL url = new URL("http://weather.livedoor.com/forecast/webservice/json/v1?city=130010");
String json;
// Get通信してStringに(evalするために丸括弧で囲む)
try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));) {
json = br.lines().collect(Collectors.joining("", "(", ")"));
}// ↑ "({"forecasts":[{"dateLabel":"x",...},{"dateLabel":"y",...},...],...})" こんなString
Bindings jsObj = (Bindings) new ScriptEngineManager().getEngineByName("js").eval(json);
jsObj = (Bindings) jsObj.get("forecasts");
// get(key)で取得できるが、戻りはObject型。必要に応じてキャスト
// js配列は values() で
jsObj.values().stream()
.map(o -> (Bindings) o)
.map(o -> o.get("dateLabel") + "\t" + o.get("telop"))
.forEach(System.out::println);
} catch (Exception e) {
e.printStackTrace();
}// 例外処理はまるっと雑にしちゃっています。ごめんなさい。
}
ポイント
大事なところはインタフェース javax.script.Bindings へのキャストです。
ScriptEngine.eval() の戻り値が Objectクラスで、JsonをScriptEngineで実行させた場合のインスタンス ScriptObjectMirror などがアクセス制限で import できずに、キャストさせることができないので、リフレクションを駆使して操作しているパターンの情報が多い。
ScriptObjectMirror が実装している Bindings インターフェースは Map<String,Object> を継承している。
なのであまり難しいことは考えずにシンプルに get(String key) や keySet(),values() などMapのメソッドを利用することができます。
いやいや、Bindingsインターフェースとかいわれてもよくわかんないですよな場合は、もう Map<?,?> にキャストしちゃってもいいと思います。
キーはStringなので特に問題ないと思うのですが、get()の戻りなどは、またまたObjectクラスなので、Jsonのネストが深い場合は、Bindings か Map でキャストして操作します。
ちなみにjavascript配列は、インデックス番号を文字列としたキー("0","1","2",...)でアクセスできるよう格納されていると思われる。が、そもそも Map.values() を利用してアクセスすればいいんじゃないかなと思っています。