先日の「Big JSON を読み込む JsonReader の実践」より汎用化を考えました。。
以下、抜粋のコードです。
public void execute(JsonReader reader, Consumer<T> consumer){ boolean request = false; try{ while((reader.hasNext() || reader.peek().equals(JsonToken.END_ARRAY) || reader.peek().equals(JsonToken.END_OBJECT)) && !reader.peek().equals(JsonToken.END_DOCUMENT) ){ JsonToken token = reader.peek(); if (token.equals(JsonToken.BEGIN_ARRAY)){ reader.beginArray(); if (targetptn.matcher(reader.getPath()).matches()){ request = true; } }else if(token.equals(JsonToken.END_ARRAY)){ reader.endArray(); if (request) request = true; }else if(token.equals(JsonToken.BEGIN_OBJECT)){ if (request) { consumer.accept(gson.fromJson(reader, type)); }else{ reader.beginObject(); } }else if(token.equals(JsonToken.END_OBJECT)){ reader.endObject(); }else if(token.equals(JsonToken.NAME)){ reader.nextName(); }else if(token.equals(JsonToken.STRING)){ reader.nextString(); }else if(token.equals(JsonToken.NUMBER)){ reader.nextLong(); }else if(token.equals(JsonToken.BOOLEAN)){ reader.nextBoolean(); }else if(token.equals(JsonToken.NULL)){ reader.nextNull(); } } }catch(Exception ex){ throw new RuntimeException(ex.getMessage(), ex); } }
配列の開始、JsonToken.BEGIN_ARRAY で、targetptn は、
JSONパス $.key1.key2[0] 、$.key1.key2[1]、、、と
一致をチェックする正規表現 Pattern です。
consumer.accept(gson.fromJson(reader, type)); で、
予め用意する Google gson で配列要素を解析して Consumer で処理します。
この type=java.lang.reflect.Type をどうやって上を呼ぶ前のメソッドで指定させようかと悩みました。
com.google.gson.reflect.TypeToken を使って、
new TypeToken<T>(){}.getType()
と思ったのですが、それは T がどのクラスか実行時に認識できる時のみです。
わけのわからんままこのように getTypeで求めて
gson の fromJson に渡してしまうと ClassCastException になります。
java.lang.reflect.Type を求める方法は、いろいろあって、、Fooというクラスに対して、、、
com.google.common.reflect.TypeToken を使用
TypeToken.of(Foo.class).getType();
または、
new TypeToken<Foo>(){}.getType();
com.google.inject.TypeLiteral を使用
TypeLiteral.get(Foo.class).getType();
com.google.gson.reflect.TypeToken を使用
TypeToken.get(Foo.class).getType();
com.google.gson.reflect.TypeToken を選択して、大量のJSON 配列を処理するものを
以下、yipuran-gsonhelper にまとめました。
Stream<T> を取得するのも用意しました。
Wiki
jsonarrayparse · yipuran/yipuran-gsonhelper Wiki · GitHub
JsonArrayParseBuilder を見てのとおり生成時に
Json-PATH 指定の文字列中に正規表現対象の文字列はエスケープします。