Jackson でJSON読込み key-value の BiConsumer で、日付時刻も

oboe2uran.hatenablog.com

oboe2uran.hatenablog.com

を書いたが、日付時刻は、LocalDate LocalDateTime で読み取りたいという要求に応えるために
以下のようにする。

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;
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{
   private ObjectMapper mapper;
   private Map<String, DateHandle> dpMap;
   public JsonNodeParse() {
      dpMap = new HashMap<>();
      mapper = new ObjectMapper();
   }
   public JsonNodeParse addDateDeserilaize(Pattern ptn, DateTimeFormatter formatter) {
      dpMap.put(ptn.pattern(), new DateHandle(DateType.DATE, ptn, formatter));
      return this;
   }
   public JsonNodeParse addDatetimeDeserilaize(Pattern ptn, DateTimeFormatter formatter) {
      dpMap.put(ptn.pattern(), new DateHandle(DateType.DATETIME, ptn, formatter));
      return this;
   }
   public JsonNodeParse addTimeDeserilaize(Pattern ptn, DateTimeFormatter formatter) {
      dpMap.put(ptn.pattern(), new DateHandle(DateType.TIME, ptn, formatter));
      return this;
   }

   enum DateType{ DATE, DATETIME, TIME }
   class DateHandle{
      public DateType type;
      public Pattern ptn;
      public DateTimeFormatter formatter;
      public DateHandle(DateType type, Pattern ptn, DateTimeFormatter formatter) {
         this.type = type;
         this.ptn = ptn;
         this.formatter = formatter;
      }
   }

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

   public void readJson(InputStream in, BiConsumer<String, Object> con){
      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)){
         String p = path.substring(1);
         dpMap.values().stream().filter(e->e.ptn.matcher(p).find()).findFirst()
         .<Runnable>map(e->()->{
            try{
               switch(e.type){
                  case DATE:
                     con.accept(p, LocalDate.parse(node.asText(), e.formatter));
                     break;
                  case DATETIME:
                     con.accept(p, LocalDateTime.parse(node.asText(), e.formatter));
                     break;
                  case TIME:
                     con.accept(p, LocalTime.parse(node.asText(), e.formatter));
                     break;
               }
            }catch(DateTimeParseException x){
               con.accept(p, node.asText());
            }
         }).orElse(()->{
            con.accept(p, node.asText());
         }).run();
      }
   }

   public Stream<Entry<String, Object>> jsonStream(String jsontxt){
      Stream.Builder<Entry<String, Object>> builder = Stream.builder();
      ObjectMapper mapper = new ObjectMapper();
      try{
         parseJson(mapper.readTree(jsontxt), "", builder);
      }catch (JsonProcessingException e){
         throw new RuntimeException(e);
      }
      return  builder.build();
   }

   public Stream<Entry<String, Object>> jsonStream(InputStream in){
      Stream.Builder<Entry<String, Object>> builder = Stream.builder();
      ObjectMapper mapper = new ObjectMapper();
      try{
         parseJson(mapper.readTree(in), "", builder);
      }catch (JsonProcessingException e){
         throw new RuntimeException(e);
      }catch(IOException e){
         throw new RuntimeException(e);
      }
      return  builder.build();
   }

   private void parseJson(JsonNode node, String path, Stream.Builder<Entry<String, Object>> builder){
      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(), builder);
         }
      }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 + "]", builder);
            }
         }else{
            builder.add(new SimpleEntry<String, Object>(path.substring(1), new ArrayList<Object>()));
         }
      }else if(node.getNodeType().equals(JsonNodeType.NULL)){
         builder.add(new SimpleEntry<String, Object>(path.substring(1), null));
      }else if(node.getNodeType().equals(JsonNodeType.NUMBER)){
         if (node.isDouble()){
            builder.add(new SimpleEntry<String, Object>(path.substring(1), node.asDouble()));
         }else if(node.isLong()){
            builder.add(new SimpleEntry<String, Object>(path.substring(1), node.asLong()));
         }else{
            builder.add(new SimpleEntry<String, Object>(path.substring(1), node.asInt()));
         }
      }else if(node.getNodeType().equals(JsonNodeType.BOOLEAN)){
         builder.add(new SimpleEntry<String, Object>(path.substring(1), node.asBoolean()));
      }else if(node.getNodeType().equals(JsonNodeType.STRING)){
         String p = path.substring(1);
         dpMap.values().stream().filter(e->e.ptn.matcher(p).find()).findFirst()
         .<Runnable>map(e->()->{
            try{
               switch(e.type){
                  case DATE:
                     builder.add(new SimpleEntry<String, Object>(p, LocalDate.parse(node.asText(), e.formatter)));
                     break;
                  case DATETIME:
                     builder.add(new SimpleEntry<String, Object>(p, LocalDateTime.parse(node.asText(), e.formatter)));
                     break;
                  case TIME:
                     builder.add(new SimpleEntry<String, Object>(p, LocalTime.parse(node.asText(), e.formatter)));
                     break;
               }
            }catch(DateTimeParseException x){
               builder.add(new SimpleEntry<String, Object>(p, node.asText()));
            }
         }).orElse(()->{
            builder.add(new SimpleEntry<String, Object>(p, node.asText()));
         }).run();
      }
   }
}

使い方

JsonNodeParse jsonNodeparse	= new JsonNodeParse()
.addDatetimeDeserilaize(Pattern.compile("^abc\\[\\d+\\]\\.date$"), DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"));

jsonNodeparse.readJson(jsontxt, (p, o)->{
	// p = JSON path
	// o = Object
});