非奨励の nashorn 使用する方法でなく、別の方法です。
有名な Graal VM の助けを借りる方法です。
https://www.graalvm.org/
準備:
Maven pom.xml
<dependency> <groupId>org.graalvm.js</groupId> <artifactId>js</artifactId> <version>21.0.0.2</version> </dependency> <dependency> <groupId>org.graalvm.js</groupId> <artifactId>js-scriptengine</artifactId> <version>21.0.0.2</version> </dependency>
前回同様、JSON のキーのパスを指定して値を取得するものです。
import java.util.ArrayDeque; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Queue; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Value; /** * JsonBody */ public class JsonBody{ private Value root; public JsonBody(String json) { Context context = Context.newBuilder("js").build(); root = context.eval("js", "var obj=" + json+ "; obj;"); } public static JsonBody of(String json){ return new JsonBody(json); } public Object getObject(String path) { Queue<String> queue = Arrays.stream(path.split("\\.")) .collect(ArrayDeque<String>::new, (r, t)->r.add(t), (r, t)->{}); Value value = root; Object o = root; do{ if (o==null){ throw new IllegalArgumentException(path + " is Refreence null"); } if (o instanceof Map) { o = ((Map<String, Object>)o).get(queue.poll()); }else{ value = (Value)o; o = getJavaObject(value.getMember(queue.poll())); } }while(!queue.isEmpty()); return o; } @SuppressWarnings("unchecked") public <R> R get(String path) { return (R)getObject(path); } private Object getJavaObject(Value value) { if (value.isNull()) return null; if (value.isBoolean()) return value.asBoolean(); if (value.isDate()) return value.asDate(); if (value.isTime()) return value.asTime(); if (value.fitsInInt()) return value.asInt(); if (value.fitsInLong()) return value.asLong(); if (value.fitsInDouble()) return value.asDouble(); if (value.isString()) return value.asString(); if (value.hasMembers()){ if (value.hasArrayElements()){ Object[] o = new Object[(int)value.getArraySize()]; for(int i=0;i < value.getArraySize();i++) { o[i] = getJavaObject(value.getArrayElement(i)); } return o; }else{ Map<String, Object> map = new HashMap<String, Object>(); value.getMemberKeys().stream() .forEach(e->map.put(e, getJavaObject(value.getMember(e)))); return map; } } return value; } }
JSON サンプル
{ "name" : "テスト", "width" : 228, "length" : 12.53, "points" : [ 14, 8, 21 ], "flg" : true, "unit" : { "color": "Red", "rank": 12 } }
呼び出しサンプル
JsonBody body = JsonBody.of(jsontxt); String name = body.get("name"); String color = body.get("unit.color"); Object[] points = body.get("points"); Map<String, Object> unit = body.get("unit");
上の JsonBody の getJavaObject メソッドの中の
if (value.isDate()) return value.asDate();
org.graalvm.polyglot.Value で Date型か問い合わせて asDate() で、java.time.LocalDate に変換する
ことを作用させるJSON は、結局、JavaScript の Date型を値にしたJSON 書式で
{ "date" : new Date() }
でないと動かない。
JavaScript としての JSON の書式で new Date() であり、同じ解析は、Jackson や、
Google gson ではできないでしょう。new Date()記述を一度文字列として読込んで
LocalDate.now() を実行しなくてはなりません。純粋なJSON解析とは言えなくなります。
また、java.time.LocalTime を望む isTime() や、 asTime() を働かせる方法が良くわからない。
{ "time": (new Date()).toJSON() }
これでは、asString() で処理されてしまう。