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

具有通用类型和通用字段名称的GSON反序列化

郭坚壁
2023-03-14
问题内容

假设我们有这样的结构:

JSON:

{
  "body": {
    "cats": [
      {
        "cat": {
          "id": 1,
          "title": "cat1"
        }
      },
      {
        "cat": {
          "id": 2,
          "title": "cat2"
        }
      }
    ]
  }
}

和对应的POJO:

响应类

private final Body body;

身体类

private final Collection<CatWrapper> cats

CatWrapper.class

private final Cat cat

类别

private final int id;
private final String title;

但是现在让我们说,我们具有相同的结构,但是Cat我们得到的不是truck

{
  "body": {
    "trucks": [
      {
        "truck": {
          "id": 1,
          "engine": "big",
          "wheels": 12
        }
      },
      {
        "truck": {
          "id": 2,
          "engine": "super big",
          "wheels": 128
        }
      }
    ]
  }
}

我在上使用GSON(默认Retrofitjson解析器)Android,在提供解决方案时请考虑一下。

我们可以在此处使用泛型,因此响应如下所示:

private final Body<ListResponse<ItemWrapper<T>> 但是我们不能,因为字段名称是特定于类的。

题:

我如何做才能自动序列化它而不创建太多样板类?我并不真的需要单独的类一样BodyCatBodyTruckBodyAnyOtherClassInThisStructure和我正在寻找一种方法来避免它们。

@编辑:

由于继承混乱,我更改了类(cat,dog-> cat,truck),此处用作示例的类不要互相扩展


问题答案:

一种想法是定义一个自定义的通用解串器。它的通用类型将表示包装在Body实例中的列表元素的具体类。

假设以下类别:

class Body<T> {
    private List<T> list;

    public Body(List<T> list) {
        this.list = list;
    }
}

class Cat {
    private int id;
    private String title;

    ...
}

class Truck {
    private int id;
    private String engine;
    private int wheels;

    ...
}

从您拥有包含名为“ body”的对象的意义上说,反序列化器假定json的结构始终相同。还假定此主体的第一个键值对中的值是一个列表。

现在,对于json数组中的每个元素,我们再次需要获取与每个键关联的内部对象。我们反序列化此值并将其放在列表中。

class CustomJsonDeserializer<T> implements JsonDeserializer<Body<T>> {

    private final Class<T> clazz;

    public CustomJsonDeserializer(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override
    public Body<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject body = json.getAsJsonObject().getAsJsonObject("body");
        JsonArray arr = body.entrySet().iterator().next().getValue().getAsJsonArray();
        List<T> list = new ArrayList<>();
        for(JsonElement element : arr) {
            JsonElement innerElement = element.getAsJsonObject().entrySet().iterator().next().getValue();
            list.add(context.deserialize(innerElement, clazz));
        }
        return new Body<>(list);
    }
}

对于最后一步,您只需要创建相应的类型,实例化并在解析器中注册适配器即可。例如卡车:

Type truckType = new TypeToken<Body<Truck>>(){}.getType();
Gson gson = new GsonBuilder()
    .registerTypeAdapter(truckType, new CustomJsonDeserializer<>(Truck.class))
    .create();
Body<Truck> body = gson.fromJson(new FileReader("file.json"), truckType);

如果要摆脱Body类,甚至可以直接从适配器返回列表。

有了卡车,您就会得到[1_big_12, 2_super big_128]产出,而[1_cat1, 2_cat2]有了猫。



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

  • 问题内容: 我想通过Google Gson传输列表对象,但是我不知道如何反序列化泛型类型。 看了这个之后我尝试了什么(BalusC的答案): 但是后来我在日食中遇到了一个错误,说“新的List(){}类型必须实现继承的抽象方法…”,如果我使用快速修复方法,则会得到20个以上的方法存根的怪兽。 我很确定有一个更简单的解决方案,但是我似乎找不到它! 编辑: 我现在有 但是,在“ fromJson”行中

  • 我正在努力用本地化反序列化世界天气在线API结果。 是否有更好、更简单的解决方案,只为lang对象编写一个自定义反序列化器,并允许GSON自动反序列化其余数据?

  • 问题内容: 我想编写一个通用函数,使用Gson反序列化通用类型List,下面是代码: 但是这段代码不起作用,我得到一个奇怪的结构,但是没有我的类型列表 当我使用时: 我工作,我得到了! 但是我需要一个通用函数,我该如何解决? 问候rubiktubik 问题答案: 没有将(as )的实际类型传递给您的方法,就无法做到这一点。 但是,如果显式传递它,则可以按如下所示创建for : 也可以看看:

  • 我在Android应用程序中实现Json反序列化时遇到了一些问题(带有Gson库)

  • 问题内容: 使用泛型时,我在Java中有一个小问题。我有一堂课: 在方法中,我需要获取类型名称。有没有办法找到字符串使用? (如果创建了,我希望能够做到这一点- 我必须使用通用性,因为我的方法之一必须返回)。 这似乎很容易,但是我不知道如何去做。 问题答案: 由于 类型擦除, 您通常无法执行此操作-的实例不 知道 的类型。如果需要,一种方法是使用类型文字: 然后: 这很丑陋,但这就是类型擦除的作用