如何将JSON反序列化为扁平的类似Map的结构?

请记住,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是任意的,但最终可能会导致键名冲突,因此剥离@$属性名应该足够容易。

以上是 如何将JSON反序列化为扁平的类似Map的结构? 的全部内容, 来源链接: utcz.com/qa/397231.html

回到顶部