当前位置: 首页 > 面试题库 >

使用GSON反序列化嵌套的通用类时的奇怪行为

阎德义
2023-03-14
问题内容

我正在编写一个将连接到服务器的类,并基于一些参数,检索一个json字符串,该字符串将与GSON一起html" target="_blank">解析为指定的(通过泛型)类。

负责班级的精简版看起来像这样:

class Executor<T> {

    private Response<T> response;

    public void execute() {
        Type responseType = new TypeToken<Response<T>>() {}.getType();
        this.response = new Gson().fromJson(json, responseType);
    }

    public Response<T> getResponse() { return this.response; }

}

JSON-variable 看起来像这样。)

反序列化后存储数据的类如下所示:

class Response<T> {

    private List<T> data = null;

    public List<T> getData() { return this.data; }

}

数据正试图反序列化的类:

public class Language {
    public String alias;
    public String label;
}

运行的代码利用了上面的类:

Executor<Language> executor = new Executor<Language();
List<Language> languages = executor.execute().getResponse().getData();
System.out.println(languages.get(0).alias); // exception occurs here

导致以下异常

ClassCastException:com.google.gson.internal.StringMap无法转换为sunnerberg.skolbibliotek.book.Language

任何帮助或建议,我们将不胜感激!


问题答案:

简短的答案是,您需要移动TypeTokenout 的创建,在创建标记()时ExecutorTin
绑定,然后将类型标记传递给构造函数。Response<T>``new TypeToken<Response<Language>>() {}``Executor

长答案是:

类型上的泛型通常在运行时删除,除非使用泛型参数绑定 编译 类型。在这种情况下,编译器会将泛型类型信息插入已编译的类中。在其他情况下,这是不可能的。

因此,例如,请考虑:

List<Integer> foo = new ArrayList<Integer>();

class IntegerList extends ArrayList<Integer> { ... }
List<Integer> bar = new IntegerList();

在运行时,Java 知道
bar包含整数,因为Integer类型是ArrayList在编译时绑定的,因此泛型类型信息保存在IntegerList类文件中。但是,的通用类型信息foo已删除,因此在运行时实际上不可能确定foo应该包含Integer

因此经常会出现这样的情况,即在正常情况下会在运行时将其擦除的情况下,例如在GSON中解析JSON数据的情况下,我们需要通用类型信息。在这些情况下,我们可以利用这样的事实,即类型信息在编译时IntegerList通过使用类型标记(在上面的示例中)进行绑定而得以保留,而这些标记实际上只是可以方便地存储泛型类型信息的微小匿名类。

现在到您的代码:

Type responseType = new TypeToken<Response<T>>() {}.getType();

在您的Executor类的这一行中,我们创建一个匿名类(从继承TypeToken),其类型Response<T>在编译时进行了硬编码(绑定)。因此,在运行时,GSON能够确定您需要的对象Response<T>。但是它不知道是什么T,因为您没有在编译时指定它!因此,GSON无法确定它创建ListResponse对象的类型是什么,而只是创建了一个StringMap

这个故事的寓意是您需要T在编译时指定它。如果Executor要一般使用,则可能需要在客户端代码中在该类之外创建类型标记。就像是:

class Executor<T> {

    private TypeToken<Response<T>> responseType;
    private Response<T> response;

    public Executor(TypeToken<Response<T>> responseType) {
        this.responseType = responseType;
    }

    public void execute() {
        this.response = new Gson().fromJson(json, responseType.getType());
    }

    public Response<T> getResponse() { return this.response; }

}

// client code:
Executor<Language> executor = new Executor<Language>(new TypeToken<Response<Language>>() { });
executor.execute();
List<Language> languages = executor.getResponse().getData();
System.out.println(languages.get(0).alias); // prints "be"

顺便说一句,我确实在我的机器上测试了以上内容。

抱歉,时间太长!



 类似资料:
  • 问题内容: 我有一个名为的类,该类具有一个作为参数的构造函数: 具有以下属性: 并且是我的应用程序的其他类,并具有以下构造函数: ,并且是的子类。 我想用Gson 反序列化数组,所以我写道: 以定义为: 调试时,实例具有正确的“ MainActivity”作为上下文,而其成员变量的上下文为null。 Gson 使用正确的构造函数创建了对象,但使用默认的无参数构造函数创建了实例。我怎样才能解决这个问

  • 我有一个名为PageItem的类,它有一个构造函数,该构造函数将上下文作为参数: 具有以下属性: 新闻提供者(Newsprovider)和主题(Topic)是我的应用程序的其他类,具有以下构造函数:

  • 问题内容: 所有,我都有以下输出/字符串(它是JIRA API的响应): 我用于遍历元素并获取值。我在下面的“嵌套对象”示例中编写了类 http://www.javacreed.com/gson-deserialiser- example/ 我能够获得到第二级的元素值。例如:在此级别之前,我能够获得的值以及其他值。我如何获得的价值? 我应该如何构造我的解串器和类。请协助。谢谢。 问题答案: 试试这

  • 问题内容: 我在Android应用程序(带有Gson库)中实现Json反序列化存在一些问题 我已经上了这样的课 反序列化的调用是: 问题是调用后的result.posts列表包含一个LinkedTreeMap对象数组(具有正确的值,因此问题是反序列化)而不是MyJson对象。当我使用MyObject而不是T时,一切运行正常并且MyObject是正确的。 那么,有什么方法可以在不创建自定义反序列化器

  • 问题内容: 根据该 GSON可以反序列化内部类。我有JSON字符串的下一个片段: 我正在使用下一堂课: 并尝试解析我的JSON字符串: 但是我得到这个错误: 您能告诉我错误在哪里吗? 问题答案: 当我将Gson与嵌套类一起使用时,我总是需要使它们起作用。在您的链接中,他们说这是没有必要的,但是在 Gson文档中 明确指出: “ Gson还可以反序列化静态嵌套类。但是,Gson不能自动反序列化纯内部

  • 问题内容: 在我当前的项目中,我在android中使用GSON库,并且遇到了嵌套地图反序列化的问题。这就是初始json的样子 而我的pojo的 和花类 但是当我尝试反序列化此对象时,我可以访问嵌套的哈希图,示例代码为 有什么建议? 问题答案: 这告诉Gson您想反序列化为未知值类型的Map。您可能会想指定类似的东西,但是您无法在Java中进行指定,因此解决方案是使用他们在Gson中称为TypeTo