英文:
Gson desearilize list and class, how does erasure work here?
问题
以下是您提供的内容的翻译部分:
我打算编写一个通用方法,将 JSON 列表转换为具有类的特定列表。这是通用的 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, new TypeToken<List<T>>() {}.getType());
}
}
这是一个我想要将其转换为 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()); // 为什么这个有效?
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()); // 为什么这个无效?
}
}
控制台输出如下:
{"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)` 不起作用。如果应用了擦除,那么它不是对两种情况都适用吗?为什么第一个方法能够确定类的类型为 `City`,而第二种情况中却是 `LinkedHashMap`?
请注意,我只翻译了您提供的代码和相关的注释,而没有包含问题或其他额外的内容。
英文:
I intend to write a generic method to convert a json list into it's specific list with class. This is the generic json parser:
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());
}
}
Here is a dummy class I'd like to convert to Json and back to 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;
}
}
Here is a simple test to see if it works:
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?
}
}
The console output is as follows:
{"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)
I'm struggling to understand why fromJson(json, class)
works but fromJsonList(json, class)
doesn't. If erasure applies, then doesn't it apply to both cases? Why is it that first method figures out the class is of type City
and not LinkedHashMap
like in the second case?
答案1
得分: 1
类型擦除意味着T
在运行时丢失,所以
new TypeToken<List<T>>() {}.getType()
变成了
new TypeToken<List>() {}.getType()
这意味着Gson不知道列表元素的类型(City
)。
由于它不知道如何将列表中的JSON对象解析为City
对象,它将它们解析为Map<String, Object>
对象,因此出现了错误消息,提示“无法将Map
强制转换为City
”。
使用TypeToken.getParameterized()
的已注释代码将会起作用,所以坚持使用它。
英文:
Type erasure means that T
is lost at runtime, so
new TypeToken<List<T>>() {}.getType()
becomes
new TypeToken<List>() {}.getType()
which means that Gson doesn't know the list element type (City
).
Since it doesn't know to parse the JSON objects in the list into City
objects, it parses them into Map<String, Object>
objects, hence the error message saying "Map
cannot be cast to City
".
The commented code using TypeToken.getParameterized()
will work, so just stick with that.
答案2
得分: 0
我看到你的代码中已经有了正确的解决方案,
我认为你在寻找的解决方案是,
Type type = TypeToken
.getParameterized(List.class, className)
.getType();
return gson.fromJson(jsonList, type);
如果你想知道其中一个为什么有效而另一个为什么无效,
那是因为类型擦除。TypeToken 类在编译时捕获完全已知的类型。
希望能有所帮助。
英文:
I saw that the correct solution is already there in your code,
I think he solution you are looking for is,
Type type = TypeToken
.getParameterized(List.class, className)
.getType();
return gson.fromJson(jsonList, type);
If you want to know why one works and other don't,
That is because of the type erasure. TypeToken class captures types that are fully known at compile time.
Hope it helps.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论