[英]Unchecked cast on a Map<String, Object> (JSON converted to Map with Jackson)
In Java 8, I want to convert a JSON string to a map, and apply "complex" transformations to the keys.在 Java 8 中,我想将 JSON 字符串转换为映射,并对键应用“复杂”转换。 As an example , that "complex" transformation will simply be a lower case transformation.
例如,“复杂”转换将只是一个小写转换。 Values in the input JSON could be strings or nested JSON objects.
输入 JSON 中的值可以是字符串或嵌套的 JSON 对象。 My code is actually working, but I struggle to fix an
unchecked cast
warning.我的代码实际上正在运行,但我很难修复
unchecked cast
警告。
Example JSON input ( String
) : JSON 输入示例(
String
):
{
"Key1": "value1",
"Key2": {
"Key2.1": "value2.1"
}
}
Desired output ( Map
) :所需的输出(
Map
):
"key1" -> "value1"
"key2" ->
"key2.1" -> "value2.1"
For that part, I used Jackson (2.9.8) and defined the following function :对于那部分,我使用了 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);
}
Since values can be strings or JSON objects, the return type of that function is Map<String, Object>
.由于值可以是字符串或 JSON 对象,因此该函数的返回类型是
Map<String, Object>
。 Note also that readValue
(in ObjectMapper
class) uses generics, its signature is :还要注意
readValue
(在ObjectMapper
类中)使用泛型,它的签名是:
<T> T readValue(String content, TypeReference valueTypeRef)
I defined the following function :我定义了以下函数:
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;
}
To handle nested maps, this function is recursive.为了处理嵌套映射,这个函数是递归的。 But since it takes a
Map<String, Object>
as parameter, I must cast value
to Map<String, Object>
to call the method recursively.但是由于它需要一个
Map<String, Object>
作为参数,我必须将value
为Map<String, Object>
以递归调用该方法。
String json = "{\"Key1\": \"value1\", \"Key2\": { \"Key2.1\": \"value2.1\" }}";
Map<String, Object> initialMap = convertJsonStringToMap(json);
Map transformedMap = transformKeys(initialMap);
System.out.println(transformedMap);
This code works, and prints, as expected :此代码按预期工作并打印:
{key1=value1, key2={key2.1=value2.1}}
{key1=value1, key2={key2.1=value2.1}}
But this line in transformKeys
function :但是
transformKeys
函数中的这一行:
value = transformKeys((Map<String, Object>) value);
produces a warning :产生警告:
[WARNING] App.java:[29,74] unchecked cast
required: java.util.Map<java.lang.String,java.lang.Object>
found: java.lang.Object
The warning is clear and I understand it (the compiler cannot know if value
is really an instance of Map<String, Object>
), but is there a way to get rid of it?警告很清楚,我理解它(编译器无法知道
value
是否真的是Map<String, Object>
的实例),但是有没有办法摆脱它?
(No @SuppressWarnings
please, nor -Xlint:none
) :D (请不要
@SuppressWarnings
,也不要-Xlint:none
):D
I feel like returning a Map<String, Object>
from convertJsonStringToMap
is not the cleanest way to convert JSON String to a Map, but I can't find an other way to do it with Jackson.我觉得从
convertJsonStringToMap
返回Map<String, Object>
并不是将 JSON String 转换为 Map 的最干净的方法,但我找不到其他方法来使用 Jackson。
You need to use Object
as Map
value because it could be another Map
, List
or primitive
( String
, Integer
, etc.).您需要使用
Object
作为Map
值,因为它可能是另一个Map
、 List
或primitive
( String
、 Integer
等)。 Jackson
allows also to manipulate JSON
using JsonNode
types. Jackson
还允许使用JsonNode
类型操作JSON
。 We need to traverse JSON object
but also JSON array
(you forgot about it).我们需要遍历
JSON object
JSON array
(你忘了它)。 In that case we need to:在这种情况下,我们需要:
JSON
to JsonNode
.JSON
反序列JsonNode
。JsonNode
API
.JsonNode
API
遍历它。Map
Map
Simple implementation:简单的实现:
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);
}
}
}
Above code prints:上面的代码打印:
{key1=value1, key2={key2.1=value2.1}, key3=[{prime=11}]}
We got rid of unsafe casting and our implementation is more concise.我们摆脱了不安全的铸造,我们的实现更加简洁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.