Jackson でJSON読込み key-value の BiConsumer を処理する

JSON を Jackson の ObjectMapper でクラスにマッピングするのではなく、
JSON キー と 値の BiConsumer を実行する。

ObjectMapper readTree メソッドで取得する JsonNode を使用する。

import java.io.IOException;
import java.io.InputStream;
import java.util.AbstractMap.SimpleEntry;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.function.BiConsumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
/**
 * JsonNodeParse
 */
public class JsonNodeParse{

   public void readJson(String jsontxt, BiConsumer<String, Object> con){
      ObjectMapper mapper = new ObjectMapper();
      try{
         parseJson(mapper.readTree(jsontxt), "", con);
      }catch (JsonProcessingException e){
         throw new RuntimeException(e);
      }
   }

   public void readJson(InputStream in, BiConsumer<String, Object> con){
      ObjectMapper mapper = new ObjectMapper();
      try{
         parseJson(mapper.readTree(in), "", con);
      }catch (JsonProcessingException e){
         throw new RuntimeException(e);
      }catch(IOException e){
         throw new RuntimeException(e);
      }
   }

   private void parseJson(JsonNode node, String path, BiConsumer<String, Object> con){
      if (node.getNodeType().equals(JsonNodeType.OBJECT)) {
         for(Iterator<Entry<String, JsonNode>> it=node.fields(); it.hasNext();) {
            Entry<String, JsonNode> entry = it.next();
            parseJson(entry.getValue(), path + "." + entry.getKey(), con);
         }
      }else if(node.getNodeType().equals(JsonNodeType.ARRAY)){
         if (node.size() > 0){
            int x=0;
            for(Iterator<JsonNode> it=node.iterator(); it.hasNext();x++){
               parseJson(it.next(), path + "[" + x + "]", con);
            }
         }else{
            con.accept(path.substring(1), new ArrayList<Object>());
         }
      }else if(node.getNodeType().equals(JsonNodeType.NULL)){
         con.accept(path.substring(1), null);
      }else if(node.getNodeType().equals(JsonNodeType.NUMBER)){
         if (node.isDouble()){
            con.accept(path.substring(1), node.asDouble());
         }else if(node.isLong()){
            con.accept(path.substring(1), node.asLong());
         }else{
            con.accept(path.substring(1), node.asInt());
         }
      }else if(node.getNodeType().equals(JsonNodeType.BOOLEAN)){
         con.accept(path.substring(1), node.asBoolean());
      }else if(node.getNodeType().equals(JsonNodeType.STRING)){
         con.accept(path.substring(1), node.asText());
      }
   }


   public void readJson(String jsontxt, Predicate<String> pathfilter, BiConsumer<String, Object> con){
      ObjectMapper mapper = new ObjectMapper();
      try{
         parseJson(mapper.readTree(jsontxt), "", pathfilter, con);
      }catch (JsonProcessingException e){
         throw new RuntimeException(e);
      }
   }

   public void readJson(InputStream in, Predicate<String> pathfilter, BiConsumer<String, Object> con){
      ObjectMapper mapper = new ObjectMapper();
      try{
         parseJson(mapper.readTree(in), "", pathfilter, con);
      }catch (JsonProcessingException e){
         throw new RuntimeException(e);
      }catch(IOException e){
         throw new RuntimeException(e);
      }
   }
   private void parseJson(JsonNode node, String path, Predicate<String> pathfilter, BiConsumer<String, Object> con){
      if (node.getNodeType().equals(JsonNodeType.OBJECT)) {
         for(Iterator<Entry<String, JsonNode>> it=node.fields(); it.hasNext();) {
            Entry<String, JsonNode> entry = it.next();
            parseJson(entry.getValue(), path + "." + entry.getKey(), pathfilter, con);
         }
      }else if(node.getNodeType().equals(JsonNodeType.ARRAY)){
         if (node.size() > 0){
            int x=0;
            for(Iterator<JsonNode> it=node.iterator(); it.hasNext();x++){
               parseJson(it.next(), path + "[" + x + "]", pathfilter, con);
            }
         }else{
            con.accept(path.substring(1), new ArrayList<Object>());
         }
      }else if(node.getNodeType().equals(JsonNodeType.NULL)){
         String p = path.substring(1);
         if (pathfilter.test(p)){
            con.accept(p, null);
         }
      }else if(node.getNodeType().equals(JsonNodeType.NUMBER)){
         String p = path.substring(1);
         if (pathfilter.test(p)){
            if (node.isDouble()){
               con.accept(p, node.asDouble());
            }else if(node.isLong()){
               con.accept(p, node.asLong());
            }else{
               con.accept(p, node.asInt());
            }
         }
      }else if(node.getNodeType().equals(JsonNodeType.BOOLEAN)){
         String p = path.substring(1);
         if (pathfilter.test(p)){
            con.accept(p, node.asBoolean());
         }
      }else if(node.getNodeType().equals(JsonNodeType.STRING)){
         String p = path.substring(1);
         if (pathfilter.test(p)){
            con.accept(p, node.asText());
         }
      }
   }
}

JSON キーは、"." 区切りで連結し、配列は、"[n]" で表現する

使用例

JsonNodeParse jsonNodeparse = new JsonNodeParse();
jsonNodeparse.readJson(jsontxt, (p, o)->{
   System.out.println("path = " + p + "  value = "+ o);
});

JSON

{
   "id" : 1207,
   "name" : "テストFoo",
   "cat" : [ 22, 33 ],
   "mod" : null,
   "flg" : true,
   "group" : {
      "hub": "Test",
      "length": 120.45
   }
}

結果

path = id  value = 1207
path = name  value = テストFoo
path = cat[0]  value = 22
path = cat[1]  value = 33
path = mod  value = null
path = flg  value = true
path = group.hub  value = Test
path = group.length  value = 120.45

また、おまけのようではあるが、
Json キー、パスの Predicate で

JsonNodeParse jsonNodeparse = new JsonNodeParse();
jsonNodeparse.readJson(jsontxt, p->p.startsWith("group.")
, (p, o)->{
   System.out.println("path = " + p + "  value = "+ o);
});
path = group.hub  value = Test
path = group.length  value = 120.45