JSONのキーから、JsonElemnt 抽出を関数型インターフェースにする

JSONのキーから、JsonElement - Oboe吹きプログラマの黙示録
"." ドットで繋げたJSONのキーから JsonElement を抽出する
これを更に、関数型インターフェースにする。Reader 、JsonElement 、JSON文字列、各々に対するパターンを
書いたが、JsonElement に対するこのインスタンスは、PATH を変えながら再利用できるはずだ。

package org.yipuran.gsonhelper;

import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
import java.util.stream.StreamSupport;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/**
 * JSONキーPATHによるJsonElement抽出.
 */
@FunctionalInterface
public interface JsonPathSearch extends Serializable{
   void accept(Optional<JsonElement> je);

   public static JsonPathSearch of(Consumer<Optional<JsonElement>> consumer){
      return e->consumer.accept(e);
   }
   default void compute(String key, JsonElement je){
      accept(elementParse(je, key));
   }
   default void compute(String key, Reader reader){
      accept(elementParse(new JsonParser().parse(reader), key));
   }
   default void compute(String key, String jsonstring){
      accept(elementParse(new JsonParser().parse(new StringReader(jsonstring==null ? "" : jsonstring)), key));
   }
   static Optional<JsonElement> elementParse(JsonElement je, String key){
      if (!je.isJsonObject()) return Optional.empty();
      if (key.contains(".")){
         String[] sp = key.split("\\.");
         if (sp.length > 1){
            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                  je.getAsJsonObject().entrySet().iterator(), Spliterator.ORDERED ), false)
               .filter(e->e.getKey().equals(sp[0])).findAny()
               .flatMap(e->elementParse(e.getValue(), key.replaceFirst("^[\\w_]+\\.", "")));
         }else{
            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                  je.getAsJsonObject().entrySet().iterator(), Spliterator.ORDERED ), false)
               .filter(e->e.getKey().equals(sp[0])).findAny().map(e->e.getValue());
         }
      }
      return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            je.getAsJsonObject().entrySet().iterator(), Spliterator.ORDERED ), false)
         .filter(e->e.getKey().equals(key)).findAny().map(e->e.getValue());
   }
}

使用例、JSON ファイルの内容が以下の場合、

 { "a":{ "b":{ "c": 2345 , "num":[0,1,2] } } }
try(InputStream in = new FileInputStream("test.json");
     Reader reader = new InputStreamReader(in, "UTF-8")){
   JsonElement je = new JsonParser().parse(reader);
   JsonPathSearch js = JsonPathSearch.of(je->{
     je->je.ifPresent(e->{
         System.out.println( e.getAsInt() );
     });
   });
   js.compute("a.b.c", je);
}catch(IOException e){
  e.printStackTrace();
}

あるいは、"a.b.num" を指定して、取得する配列を JsonArray に変換して処理する。

JsonPathSearch.of(je->{
   je.ifPresent(e->{
      e.getAsJsonArray().forEach(t->{
         System.out.println( t.getAsInt() );
      });
   });
}).compute("a.b.num", reader);