【问题标题】:Gson desearilize list and class, how does erasure work here?Gson 反序列化列表和类,擦除在这里如何工作?
【发布时间】:2020-04-10 05:38:49
【问题描述】:

我打算编写一个通用方法来将 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, TypeToken.getParameterized(List.class, className).getType());
        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());  // 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) 无效。如果擦除适用,那么它是否适用于两种情况?为什么第一种方法会发现类的类型是 City 而不是 LinkedHashMap 像第二种情况那样?

【问题讨论】:

标签: java json generics gson erasure


【解决方案1】:

类型擦除意味着T在运行时丢失,所以

new TypeToken<List<T>>() {}.getType()

变成

new TypeToken<List>() {}.getType()

这意味着 Gson 不知道列表元素类型 (City)。

由于它不知道将列表中的 JSON 对象解析为 City 对象,因此它将它们解析为 Map&lt;String, Object&gt; 对象,因此错误消息说“Map 无法转换为 City”。

使用TypeToken.getParameterized() 的注释代码将起作用,所以请坚持下去。

【讨论】:

    【解决方案2】:

    我看到你的代码中已经有正确的解决方案了,

    我认为您正在寻找的解决方案是,

    Type type = TypeToken
                    .getParameterized(List.class, className)
                    .getType();
            return gson.fromJson(jsonList, type);
    

    如果您想知道为什么一个有效而另一个无效, 那是因为类型擦除。 TypeToken 类捕获在编译时完全已知的类型。

    希望对你有帮助。

    【讨论】:

    • 在被询问的代码正上方的注释中的代码是什么,所以 OP 已经知道了。
    • 是的,我注意到了,不幸的是我还没来得及完成我的评论就发表了
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多