How to deserialize JSON into flat, Map-like structure?

后端 未结 7 2114
醉梦人生
醉梦人生 2020-12-01 06:34

Have in mind that the JSON structure is not known before hand i.e. it is completely arbitrary, we only know that it is JSON format.

For example,

The followin

7条回答
  •  醉酒成梦
    2020-12-01 07:09

    You can do this to traverse the tree and keep track of how deep you are to figure out dot notation property names:

    import com.fasterxml.jackson.databind.JsonNode;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ArrayNode;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    import com.fasterxml.jackson.databind.node.ValueNode;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import org.junit.Test;
    
    public class FlattenJson {
      String json = "{\n" +
          "   \"Port\":\n" +
          "   {\n" +
          "       \"@alias\": \"defaultHttp\",\n" +
          "       \"Enabled\": \"true\",\n" +
          "       \"Number\": \"10092\",\n" +
          "       \"Protocol\": \"http\",\n" +
          "       \"KeepAliveTimeout\": \"20000\",\n" +
          "       \"ThreadPool\":\n" +
          "       {\n" +
          "           \"@enabled\": \"false\",\n" +
          "           \"Max\": \"150\",\n" +
          "           \"ThreadPriority\": \"5\"\n" +
          "       },\n" +
          "       \"ExtendedProperties\":\n" +
          "       {\n" +
          "           \"Property\":\n" +
          "           [                         \n" +
          "               {\n" +
          "                   \"@name\": \"connectionTimeout\",\n" +
          "                   \"$\": \"20000\"\n" +
          "               }\n" +
          "           ]\n" +
          "       }\n" +
          "   }\n" +
          "}";
    
      @Test
      public void testCreatingKeyValues() {
        Map map = new HashMap();
        try {
          addKeys("", new ObjectMapper().readTree(json), map);
        } catch (IOException e) {
          e.printStackTrace();
        }
        System.out.println(map);
      }
    
      private void addKeys(String currentPath, JsonNode jsonNode, Map map) {
        if (jsonNode.isObject()) {
          ObjectNode objectNode = (ObjectNode) jsonNode;
          Iterator> iter = objectNode.fields();
          String pathPrefix = currentPath.isEmpty() ? "" : currentPath + ".";
    
          while (iter.hasNext()) {
            Map.Entry entry = iter.next();
            addKeys(pathPrefix + entry.getKey(), entry.getValue(), map);
          }
        } else if (jsonNode.isArray()) {
          ArrayNode arrayNode = (ArrayNode) jsonNode;
          for (int i = 0; i < arrayNode.size(); i++) {
            addKeys(currentPath + "[" + i + "]", arrayNode.get(i), map);
          }
        } else if (jsonNode.isValueNode()) {
          ValueNode valueNode = (ValueNode) jsonNode;
          map.put(currentPath, valueNode.asText());
        }
      }
    }
    

    It produces the following map:

    Port.ThreadPool.Max=150, 
    Port.ThreadPool.@enabled=false, 
    Port.Number=10092, 
    Port.ExtendedProperties.Property[0].@name=connectionTimeout, 
    Port.ThreadPool.ThreadPriority=5, 
    Port.Protocol=http, 
    Port.KeepAliveTimeout=20000, 
    Port.ExtendedProperties.Property[0].$=20000, 
    Port.@alias=defaultHttp, 
    Port.Enabled=true
    

    It should be easy enough to strip out @ and $ in the property names, although you could end up with collisions in key names since you said the JSON was arbitrary.

提交回复
热议问题