在地图上未经检查的投射<String, Object>(JSON 与 Jackson 一起转换为地图)
Unchecked cast on a Map<String, Object> (JSON converted to Map with Jackson)
在 Java 8 中,我想将 JSON 字符串转换为映射,并对键应用 "complex" 转换。 例如,"complex" 转换只是小写转换。
输入 JSON 中的值可以是字符串或嵌套的 JSON 对象。
我的代码确实有效,但我很难修复 unchecked cast
警告。
示例
示例 JSON 输入 (String
) :
{
"Key1": "value1",
"Key2": {
"Key2.1": "value2.1"
}
}
期望的输出(Map
):
"key1" -> "value1"
"key2" ->
"key2.1" -> "value2.1"
1。 JSON 字符串 -> 映射
对于那部分,我使用了 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 对象,因此该函数的 return 类型是 Map<String, Object>
。还要注意的是
readValue
(in ObjectMapper
class) 使用泛型,它的签名是:
<T> T readValue(String content, TypeReference valueTypeRef)
2。 Map -> Map with transformed keys(例如:小写)
我定义了以下函数:
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
我觉得 return 从 convertJsonStringToMap
中 Map<String, Object>
是
不是将 JSON String 转换为 Map 的最干净的方法,但我找不到其他方法来使用 Jackson。
您需要使用 Object
作为 Map
值,因为它可能是另一个 Map
、List
或 primitive
(String
, Integer
,等等)。 Jackson
还允许使用 JsonNode
类型来操作 JSON
。我们需要遍历 JSON object
也需要遍历 JSON array
(你忘记了)。在这种情况下,我们需要:
- 将
JSON
反序列化为 JsonNode
。
- 使用
JsonNode
API
遍历它。
- 转换为
Map
实现简单:
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}]}
我们摆脱了不安全的转换,我们的实现更加简洁。
在 Java 8 中,我想将 JSON 字符串转换为映射,并对键应用 "complex" 转换。 例如,"complex" 转换只是小写转换。
输入 JSON 中的值可以是字符串或嵌套的 JSON 对象。
我的代码确实有效,但我很难修复 unchecked cast
警告。
示例
示例 JSON 输入 (String
) :
{
"Key1": "value1",
"Key2": {
"Key2.1": "value2.1"
}
}
期望的输出(Map
):
"key1" -> "value1"
"key2" ->
"key2.1" -> "value2.1"
1。 JSON 字符串 -> 映射
对于那部分,我使用了 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 对象,因此该函数的 return 类型是 Map<String, Object>
。还要注意的是
readValue
(in ObjectMapper
class) 使用泛型,它的签名是:
<T> T readValue(String content, TypeReference valueTypeRef)
2。 Map -> Map with transformed keys(例如:小写)
我定义了以下函数:
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
我觉得 return 从 convertJsonStringToMap
中 Map<String, Object>
是
不是将 JSON String 转换为 Map 的最干净的方法,但我找不到其他方法来使用 Jackson。
您需要使用 Object
作为 Map
值,因为它可能是另一个 Map
、List
或 primitive
(String
, Integer
,等等)。 Jackson
还允许使用 JsonNode
类型来操作 JSON
。我们需要遍历 JSON object
也需要遍历 JSON array
(你忘记了)。在这种情况下,我们需要:
- 将
JSON
反序列化为JsonNode
。 - 使用
JsonNode
API
遍历它。 - 转换为
Map
实现简单:
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}]}
我们摆脱了不安全的转换,我们的实现更加简洁。