Jackson JSON読込みで、JSON key-value を BiConsumer はまたは、Stream 生成する方法を
Jackson でJSON読込み key-value の BiConsumer を処理する - Oboe吹きプログラマの黙示録
Jackson でJSON読込み key-value の Stream生成 - Oboe吹きプログラマの黙示録
で始まり、Jackson でJSON読込み key-value の BiConsumer で、日付時刻も - Oboe吹きプログラマの黙示録
を書いたが、JSON解析結果として任意クラスを key-value → value の Object にすることまでは
これでは対応できない。日付時刻を含め、Function<T, R> でデシリアライザを指定する方法、
Function<JsonNode, Object> でデシリアライザを書いて登録しておく。という方法の方が、
任意の型 Object にデシリアライズできる。
以下のようになる。
import java.io.IOException; import java.io.InputStream; 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.function.Function; 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, Function<JsonNode, Object>> dMap; public JsonNodeParse() { dMap = new HashMap<>(); mapper = new ObjectMapper(); } public JsonNodeParse addDeserilaize(Pattern ptn, Function<JsonNode, Object> deserial) { dMap.put(ptn.pattern(), deserial); return this; } 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){ String p = path.length() > 0 ? path.substring(1) : path; Function<JsonNode, Object> nodeparser; if (dMap.size() > 0 && (nodeparser = dMap.entrySet().stream() .filter(e->Pattern.compile(e.getKey()).matcher(p).find()) .findAny().map(e->e.getValue()).orElse(null)) != null) { con.accept(p, nodeparser.apply(node)); }else{ 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(p, new ArrayList<Object>()); } }else if(node.getNodeType().equals(JsonNodeType.NULL)){ con.accept(p, null); }else if(node.getNodeType().equals(JsonNodeType.NUMBER)){ 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)){ con.accept(p, node.asBoolean()); }else if(node.getNodeType().equals(JsonNodeType.STRING)){ con.accept(p, node.asText()); } } } 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){ String p = path.length() > 0 ? path.substring(1) : path; Function<JsonNode, Object> nodeparser; if (dMap.size() > 0 && (nodeparser = dMap.entrySet().stream() .filter(e->Pattern.compile(e.getKey()).matcher(p).find()) .findAny().map(e->e.getValue()).orElse(null)) != null) { builder.add(new SimpleEntry<String, Object>(p, nodeparser.apply(node))); }else{ 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>(p, new ArrayList<Object>())); } }else if(node.getNodeType().equals(JsonNodeType.NULL)){ builder.add(new SimpleEntry<String, Object>(p, null)); }else if(node.getNodeType().equals(JsonNodeType.NUMBER)){ if (node.isDouble()){ builder.add(new SimpleEntry<String, Object>(p, node.asDouble())); }else if(node.isLong()){ builder.add(new SimpleEntry<String, Object>(p, node.asLong())); }else{ builder.add(new SimpleEntry<String, Object>(p, node.asInt())); } }else if(node.getNodeType().equals(JsonNodeType.BOOLEAN)){ builder.add(new SimpleEntry<String, Object>(p, node.asBoolean())); }else if(node.getNodeType().equals(JsonNodeType.STRING)){ builder.add(new SimpleEntry<String, Object>(p, node.asText())); } } } }
例) "time" という JSONキーがある場合、yyyy/MM/dd HH:mm:ss という書式であった場合、、
JsonNodeParse jsonarse = new JsonNodeParse().addDeserilaize(Pattern.compile("time"), n->LocalDateTime.parse(n.asText(), DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"))); jsonparse.readJson(jsonstr, (p, o)->{ // p: JSON key // o: JSON value Object }); jsonparse.jsonStream(jsonstr).forEach(e->{ // e.getKey() : JSON key // e.getValue() : JSON value Object });
Jackson の JsonNode の仕様さえ理解してれば、
public JsonNodeParse addDeserilaize(Pattern ptn, Function<JsonNode, Object> deserial)
で連結していけば良いだけである。