在Java8中,我希望将JSON字符串转换为映射,并对键应用“复杂”转换。以为例,这个“复杂”的转换将仅仅是一个小写的转换。输入JSON中的值可以是字符串或嵌套的JSON对象。我的代码实际上正常工作,但我很难修复unchecked cast
警告。
示例
示例JSON输入(String
):
{
"Key1": "value1",
"Key2": {
"Key2.1": "value2.1"
}
}
所需输出(Map
):
"key1" -> "value1"
"key2" ->
"key2.1" -> "value2.1"
1. JSON String ->映射
为此,我使用了Jackson (2.9.8)并定义了以下函数:
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
Map<String, Object> convertJsonStringToMap(String json) throws IOException {
ObjectMapper mapper = new ObjectMapper();
TypeReference type = new TypeReference<Map<String, Object>>(){};
return mapper.readValue(json, type);
}
由于值可以是字符串或JSON对象,因此该函数的返回类型为Map<String, Object>
。还要注意,readValue
(在ObjectMapper
类中)使用泛型,它的签名是:
<T> T readValue(String content, TypeReference valueTypeRef)
2.使用变换后的关键点映射->映射(示例:小写)
我定义了以下函数:
Map<String, Object> transformKeys(Map<String, Object> map) {
Map<String, Object> result = new HashMap<>(map.size());
for (Map.Entry<String, Object> entry : map.entrySet()) {
Object value = entry.getValue();
if (value instanceof Map) {
value = transformKeys((Map<String, Object>) value);
}
// toLowerCase() is the transformation here (example), but I could have used something else
result.put(entry.getKey().toLowerCase(), value);
}
return result;
}
为了处理嵌套的映射,这个函数是递归的。但是因为它接受Map<String, Object>
作为参数,所以我必须将value
转换为Map<String, Object>
才能递归调用该方法。
3.把所有的东西放在一起
String json = "{\"Key1\": \"value1\", \"Key2\": { \"Key2.1\": \"value2.1\" }}";
Map<String, Object> initialMap = convertJsonStringToMap(json);
Map transformedMap = transformKeys(initialMap);
System.out.println(transformedMap);
这段代码按照预期工作并打印出来:
{key1=value1,key2={key2.1=value2.1}}
但在transformKeys
函数中有以下这一行:
value = transformKeys((Map<String, Object>) value);
生成警告:
[WARNING] App.java:[29,74] unchecked cast
required: java.util.Map<java.lang.String,java.lang.Object>
found: java.lang.Object
警告很清楚,我也理解(编译器无法知道value
是否真的是Map<String, Object>
的一个实例),但是有没有办法摆脱它呢?
(请不要@SuppressWarnings
,也不要-Xlint:none
) :D
我觉得从convertJsonStringToMap
返回一个Map<String, Object>
并不是将JSON String转换为Map的最简洁的方法,但是我找不到其他的方法来处理JSON。
发布于 2019-03-21 03:59:20
您需要使用Object
作为Map
值,因为它可以是另一个Map
、List
或primitive
(String
、Integer
等)。Jackson
还允许使用JsonNode
类型操作JSON
。我们不仅要遍历JSON object
,还要遍历JSON array
(你忘了这一点)。在这种情况下,我们需要:
使用到Map
的JsonNode
.
API
.
JSON
进行反序列化以对其进行反序列化简单的实现:
import com.fasterxml.jackson.core.type.TypeReference;
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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
String json = "{\"Key1\": \"value1\", \"Key2\": { \"Key2.1\": \"value2.1\" }, \"Key3\":[{\"pRiMe\":11}]}";
Map<String, Object> map = convertJsonStringToMap(json);
System.out.println(map);
}
private static Map<String, Object> convertJsonStringToMap(String json) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
transformKeys(node);
TypeReference mapType = new TypeReference<Map<String, Object>>() {
};
return mapper.convertValue(node, mapType);
}
private static void transformKeys(JsonNode parent) {
if (parent.isObject()) {
ObjectNode node = (ObjectNode) parent;
List<String> names = new ArrayList<>();
node.fieldNames().forEachRemaining(names::add);
names.forEach(name -> {
JsonNode item = node.remove(name);
transformKeys(item);
node.replace(name.toLowerCase(), item);
});
} else if (parent.isArray()) {
ArrayNode array = (ArrayNode) parent;
array.elements().forEachRemaining(JsonApp::transformKeys);
}
}
}
上面的代码打印:
{key1=value1, key2={key2.1=value2.1}, key3=[{prime=11}]}
我们摆脱了不安全的类型转换,我们的实现更加简洁。
https://stackoverflow.com/questions/55261039
复制相似问题