我正在编写一个为我的环境提供一些常用工具的类。
在这个类中,我有以下接收JSON字符串的方法,并且应该将JSON映射到适当的对象:
public static <T> T mapJsonToObject(String json, Class<T> clazz) {
ObjectMapper mapper = new ObjectMapper();
T parsedObject = null;
try {
parsedObject = mapper.readValue(json, clazz);
} catch (Exception e) {
e.printStackTrace();
}
return parsedObject;
}
从String到相应类的实际转换是使用Jackson库完成的,并且正常工作,以及整个方法。
调用此方法,例如:
Object o = MyUtilities.mapJsonToObject(jsonString, Object.class);
Point p = MyUtilities.mapJsonToObject(jsonString, Point.class);
PhoneBook pb = MyUtilities.mapJsonToObject(jsonString, PhoneBook.class);
都正常工作。
但是,如果我不想将JSON映射到特定的对象,我只想使用键/值对将其转换为地图,如下所示:
HashMap<String, Object> myMap = MyUtilities.mapJsonToObject(result, HashMap.class);
我从编译器收到"Type safety: The expression of type HashMap needs unchecked conversion to conform to HashMap<String,Object>"
警告。这是因为我在使用HashMap.class
在撰写此问题时,我实际上偶然发现了this教程并想到了以下列方式重载映射方法:
public static <T> T mapJsonToObject(String json, T obj) {
ObjectMapper mapper = new ObjectMapper();
T parsedObject = null;
try {
parsedObject = mapper.readValue(json, new TypeReference<T>() {});
} catch (Exception e) {
e.printStackTrace();
}
return parsedObject;
}
这需要传递一个我更愿意避免的实际对象:
HashMap<String, Object> myMap = null;
myMap = MyUtilities.mapJsonToObject(result, myMap);
知道如何改进这两种方法以避免传递Object和类型安全警告吗?请注意,我没有找到特定于HashMap的解决方案
答案 0 :(得分:6)
对于泛型类型,您将始终遇到类型擦除问题。作为解决方法,您可以执行未选中类型转换,如下所示:
@SuppressWarnings("unchecked")
public static <C, T extends C> C mapJsonToObject(String jsonString, Class<T> result) {
// ... stuff ...
return (C) parsedObject;
}
然而,考虑到你不控制杰克逊实际用于收集条目的类,这是非常难看的。
为了获得更好的结果,您可以使用杰克逊的special type system:
@SuppressWarnings("unchecked")
public static <C> C mapJsonToObject(String jsonString, JavaType type) {
// ... stuff ...
return (C) parsedObject;
}
// Check answer comments on TypeFactory#collectionType deprecation
List<MyBean> result = mapJsonToObject("[]", TypeFactory.collectionType(ArrayList.class, MyBean.class));
或者您可以使用杰克逊的type references:
public static <T> T mapJsonToObject(String jsonString, TypeReference<T> type) {
// ... stuff ...
}
List<MyBean> result = mapJsonToObject("[]", new TypeReference<List<Object>>() {});
我有点像第一种方法(通过 JavaType ),因为它不会为你编写的每个方法调用创建一个匿名类。
更新为什么第一个选项很难看:
第一个选项有效,因为通用参数T
和C
之间的关系几乎为零。虽然将根据传递的参数推断T
,但将根据结果分配推断C
。这些之间的唯一约束是T
必须扩展C
。这只是一种形式,可以防止完全不正确的调用,例如String s = mapJsonToObject("", List.class)
。
该选项很难看,因为您没有说明地图的内容。即由杰克逊来决定它想要使用哪种类。
例如,{ "foo": "xxx", "bar": 1 }
可能会使用以下条目映射到Map:
但对于{ "foo": { "bar": 1 } }
,它可能是这样的:
{ "bar": 1 }
您可以使用第一个选项。但除了Map<String, Object>
和没有嵌套对象或数组的简单JSON字符串之外,它永远不会有好处。