Gson反序列化列表和class,这里的擦除是如何工作的?
Gson desearilize list and class, how does erasure work here?
我打算编写一个通用方法来将 json 列表转换为它的特定列表 class。这是通用的 json 解析器:
public class JsonParserUtils {
private static Gson gson = new Gson();
public static <T> String toJson(T object) {
if (object == null) {
return null;
}
return gson.toJson(object);
}
public static <T> T fromJson(String json, Class<T> className) {
if (StringUtils.isEmpty(json)) {
return null;
}
T object = gson.fromJson(json, className);
return object;
}
public static <T> List<T> fromJsonList(String jsonList, Class<T> className) {
// return gson.fromJson(jsonList, TypeToken.getParameterized(List.class, className).getType());
return gson.fromJson(jsonList, new TypeToken<List<T>>() {}.getType());
}
}
这是一个虚拟 class 我想转换为 Json 然后返回 Pojo。
public class City {
private String city;
public City(String city) {
this.city = city;
}
@Override
public String toString() {
return "City [city=" + city + "]";
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
这是一个简单的测试,看看它是否有效:
public class TestParser {
public static void main(String[] args) {
City city = new City("test");
String cityJson = JsonParserUtils.toJson(city);
System.out.println(cityJson);
City fromJson = JsonParserUtils.fromJson(cityJson, City.class);
System.out.println(fromJson.getCity()); // Why does this work?
List<City> list = new LinkedList<>();
list.add(city);
String cityListJson = JsonParserUtils.toJson(list);
System.out.println(cityListJson);
List<City> fromJsonList = JsonParserUtils.fromJsonList(cityListJson, City.class);
System.out.println(fromJsonList.get(0).getCity()); // Why does this not work?
}
}
控制台输出如下:
{"city":"test"}
test
[{"city":"test"}]
Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.jtraq.hospital.vos.City
at com.jtraq.hospital.vos.TestParser.main(TestParser.java:24)
我很难理解为什么 fromJson(json, class)
有效而 fromJsonList(json, class)
无效。如果擦除适用,那么它不是适用于这两种情况吗?为什么第一种方法计算出 class 是 City
类型而不是第二种情况下的 LinkedHashMap
类型?
我看到你的代码中已经有了正确的解决方案,
我认为您正在寻找的解决方案是,
Type type = TypeToken
.getParameterized(List.class, className)
.getType();
return gson.fromJson(jsonList, type);
如果您想知道为什么一个有效而另一个无效,
那是因为类型擦除。 TypeToken class 捕获编译时完全已知的类型。
希望对您有所帮助。
类型擦除意味着T
在运行时丢失,所以
new TypeToken<List<T>>() {}.getType()
变成
new TypeToken<List>() {}.getType()
这意味着 Gson 不知道列表元素类型 (City
)。
因为它不知道将列表中的 JSON 个对象解析为 City
个对象,它会将它们解析为 Map<String, Object>
个对象,因此错误消息说“Map
无法转换为 City
".
使用 TypeToken.getParameterized()
的注释代码会起作用,所以坚持使用它。
我打算编写一个通用方法来将 json 列表转换为它的特定列表 class。这是通用的 json 解析器:
public class JsonParserUtils {
private static Gson gson = new Gson();
public static <T> String toJson(T object) {
if (object == null) {
return null;
}
return gson.toJson(object);
}
public static <T> T fromJson(String json, Class<T> className) {
if (StringUtils.isEmpty(json)) {
return null;
}
T object = gson.fromJson(json, className);
return object;
}
public static <T> List<T> fromJsonList(String jsonList, Class<T> className) {
// return gson.fromJson(jsonList, TypeToken.getParameterized(List.class, className).getType());
return gson.fromJson(jsonList, new TypeToken<List<T>>() {}.getType());
}
}
这是一个虚拟 class 我想转换为 Json 然后返回 Pojo。
public class City {
private String city;
public City(String city) {
this.city = city;
}
@Override
public String toString() {
return "City [city=" + city + "]";
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
这是一个简单的测试,看看它是否有效:
public class TestParser {
public static void main(String[] args) {
City city = new City("test");
String cityJson = JsonParserUtils.toJson(city);
System.out.println(cityJson);
City fromJson = JsonParserUtils.fromJson(cityJson, City.class);
System.out.println(fromJson.getCity()); // Why does this work?
List<City> list = new LinkedList<>();
list.add(city);
String cityListJson = JsonParserUtils.toJson(list);
System.out.println(cityListJson);
List<City> fromJsonList = JsonParserUtils.fromJsonList(cityListJson, City.class);
System.out.println(fromJsonList.get(0).getCity()); // Why does this not work?
}
}
控制台输出如下:
{"city":"test"}
test
[{"city":"test"}]
Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.jtraq.hospital.vos.City
at com.jtraq.hospital.vos.TestParser.main(TestParser.java:24)
我很难理解为什么 fromJson(json, class)
有效而 fromJsonList(json, class)
无效。如果擦除适用,那么它不是适用于这两种情况吗?为什么第一种方法计算出 class 是 City
类型而不是第二种情况下的 LinkedHashMap
类型?
我看到你的代码中已经有了正确的解决方案,
我认为您正在寻找的解决方案是,
Type type = TypeToken
.getParameterized(List.class, className)
.getType();
return gson.fromJson(jsonList, type);
如果您想知道为什么一个有效而另一个无效, 那是因为类型擦除。 TypeToken class 捕获编译时完全已知的类型。
希望对您有所帮助。
类型擦除意味着T
在运行时丢失,所以
new TypeToken<List<T>>() {}.getType()
变成
new TypeToken<List>() {}.getType()
这意味着 Gson 不知道列表元素类型 (City
)。
因为它不知道将列表中的 JSON 个对象解析为 City
个对象,它会将它们解析为 Map<String, Object>
个对象,因此错误消息说“Map
无法转换为 City
".
使用 TypeToken.getParameterized()
的注释代码会起作用,所以坚持使用它。