JSON → 任意のクラスオブジェクトに変換させることなく、
JSON のキーを指定して対象の値、valueを取得するものを汎用的なメソッドを用意しようと考えると
先日紹介した
oboe2uran.hatenablog.com
を超える機能のメソッドを作るのは難しい。
紹介した GitHub - json-path/JsonPath: Java JsonPath implementation に機能が追い付かなくてもいいから
Google GSON 利用で書いてみた。
import java.io.Reader; import java.io.StringReader; import java.util.Arrays; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonParser; /** * JSonValue */ public final class JSonValue{ private Reader reader; private Pattern aryPattern = Pattern.compile("\\[\\d+\\]"); private Pattern decPattern = Pattern.compile("\\d+"); public JSonValue(Reader reader){ this.reader = reader; } public JSonValue(String json){ this.reader = new StringReader(json); } /** * JSONキー指定 JsonElement オブジェクト取得 * @param path JSON Key path 表現は "."区切り、配列は [Index]で表現 * @return JsonElement * path にマッチしない場合は nullが返る */ public JsonElement get(String path){ if (path==null) return null; if (path.replaceAll(" ", "").length()==0) return null; return get(path, new JsonParser().parse(reader)); } private JsonElement get(String path, JsonElement je){ String[] pary = path.split("\\."); String key = pary[0].replaceAll("\\[\\d+\\]", ""); if (je.isJsonNull()){ return null; }else if(je.isJsonObject()){ for(Entry<String, JsonElement> entry:je.getAsJsonObject().entrySet()){ if (entry.getKey().equals(key)){ if (entry.getValue().isJsonArray() && aryPattern.matcher(pary[0]).find()){ int i = getIndex(pary[0]); JsonArray ja = entry.getValue().getAsJsonArray(); if (i < ja.size()){ if (pary.length > 1) { return get(Arrays.stream(pary).skip(1) .collect(Collectors.joining(".")), ja.get(i)); } return ja.get(i); }else{ return null; } }else{ if (pary.length > 1) { return get(Arrays.stream(pary).skip(1) .collect(Collectors.joining(".")), entry.getValue()); } return entry.getValue(); } } } }else if(je.isJsonPrimitive()){ return je; } return null; } private int getIndex(String s){ Matcher m = aryPattern.matcher(s); if (m.find()){ Matcher md = decPattern.matcher(m.group()); if (md.find()){ return Integer.parseInt(md.group()); } } return -1; } }
コンストラクタ Reader を指定させるのは、可能ならば、BufferedReader で Reader 読み出し位置を mark して
reset() 実行で何回も Reader をそのまま使用するためだが、現実的ではない。
使用例
try(InputStream in = new FileInputStream("sample2.json"); Reader reader = new InputStreamReader(in, "UTF-8")){ BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); JSonValue jsv = new JSonValue(br); JsonElement je = jsv.get("store.book[1].title"); }catch(Exception ex){ }
JsonElement を取得できれば、JsonPrimitive JsonArray JsonObject にcastして使用できる