请记住,JSON结构事先是未知的,即它是完全任意的,我们只知道它是JSON格式。
例如,
以下JSON
{ "Port": { "@alias": "defaultHttp", "Enabled": "true", "Number": "10092", "Protocol": "http", "KeepAliveTimeout": "20000", "ThreadPool": { "@enabled": "false", "Max": "150", "ThreadPriority": "5" }, "ExtendedProperties": { "Property": [ { "@name": "connectionTimeout", "$": "20000" } ] } } }
应该反序列化为具有类似key的类似Map的结构(为简洁起见,不包括以上所有内容):
port[0].alias port[0].enabled port[0].extendedProperties.connectionTimeout port[0].threadPool.max
我目前正在调查杰克逊,所以我们有:
TypeReference<HashMap<String, Object>> typeRef = new TypeReference<HashMap<String, Object>>() {}; Map<String, String> o = objectMapper.readValue(jsonString, typeRef);
但是,生成的Map实例基本上是嵌套Map的Map:
{Port={@alias=diagnostics, Enabled=false, Type=DIAGNOSTIC, Number=10033, Protocol=JDWP, ExtendedProperties={Property={@name=suspend, $=n}}}}
我需要使用“圆点表示法”的扁平化键和扁平化键,如上。
我不希望自己实现此功能,尽管目前我看不到其他任何方式。
您可以执行以下操作遍历树并跟踪找出点表示法属性名称的深度:
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<String, String> map = new HashMap<String, String>(); try { addKeys("", new ObjectMapper().readTree(json), map); } catch (IOException e) { e.printStackTrace(); } System.out.println(map); } private void addKeys(String currentPath, JsonNode jsonNode, Map<String, String> map) { if (jsonNode.isObject()) { ObjectNode objectNode = (ObjectNode) jsonNode; Iterator<Map.Entry<String, JsonNode>> iter = objectNode.fields(); String pathPrefix = currentPath.isEmpty() ? "" : currentPath + "."; while (iter.hasNext()) { Map.Entry<String, JsonNode> 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()); } } }
它产生以下图:
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
尽管您说JSON是任意的,但最终可能会导致键名冲突,因此剥离@和$属性名应该足够容易。
@
$