【问题标题】:How to parse dynamic json in android with retrofit 2 using annotations如何使用注释在改造 2 的 android 中解析动态 json
【发布时间】:2017-10-03 18:46:33
【问题描述】:

我有一个 JSON 结构,我想使用改造 2 (@Expose) 对其进行解析。下面我提到了 JSON。需要帮助使用动态注释对其进行解析。

{
  "status": 1,
  "message": "success",
  "data" : [
    {
      "type": 1,
      "heading": "",
      "description": "",
      "created_on": 141123213,
      "author_id": 123,
      "author_name": "some name",
      "author_pic": "some_pic",
      "read_time": "3.1 min",
      "post_pic_url": "",
      "post_web_url": "",
      "isLiked": false,
      "isSaved": false,
      "totalLikes": 12
   },
   {
      "type": 2,
      "author_id": 123,
      "author_name": "some name",
      "author_pic": "some pic",
      "author_about": "",
      "tags":[
        "travel", "weekends"
      ],
      "isFollowing": false
   },
   {
     "type": 3,
     "poll_name": "Some name",
     "poll_options": [
       "opt1", "opt2", "opt3"
     ],
     "author_id": 123,
     "author_name": "some name",
     "author_pic": "some pic",
     "isLiked": true,
     "isFollowing": false
   },
   {
     "type": 4,
     "ad_url": "url",
     "ad_pic": "pic"
   },
   {
     "type": 5,
     "tags": [
       "tag1", "tag2", "tag3"
     ]
   }
  ]
 }

我已经用所有 5 种类型更新了 JSON 结构。

【问题讨论】:

  • 动态注解意味着每次json结构都会改变?
  • 在问这里之前你有没有尝试过?
  • 当然,我尝试使用 JSON 中提到的所有项目创建一个模型,它有效,但不是我想要使用的最佳解决方案。寻找一些有效的方法
  • @Lingeshwaran 动态注释意味着我的数据 jsonarray 将有 5 种类型,每种类型包含不同的键。现在我为每种类型创建了 5 个不同的模型,但不知道如何使用 gson 与这些模型进行交流以进行改造
  • @ketan268 发布我们将看到的完整 json 结构,即包括所有 5 种类型

标签: java android json gson retrofit2


【解决方案1】:

Retrofit 不做序列化和反序列化,但 Gson 做。 您可能想使用 Google Gson extras 包中的 RuntimeTypeAdapterFactory。 它没有在工件存储库中发布,您可以简单地将代码复制到您的项目中。 如果类型适配器有点复杂(因为它们与 JSON 流一起使用),您可能会发现 JsonDeserializer<T> 更易于使用并且可能更易于维护(它们与消耗更多内存的 JSON 树一起使用,但无论如何这是唯一的方法)。

定义您的映射类似于:

// There might be no the common root, and target lists might be parameterized with Object, but it's up to you
abstract class Element {

    final int type = Integer.valueOf(0);

    // Since the number of types is really finite, we can define all known types in one place
    private Element() {
    }

    static final class Type1Element
            extends Element {

        // the rest of properties go here

        // Gson does not need constructors, neither we do (at least public ones)
        private Type1Element() {
        }

    }

    static final class Type2Element
            extends Element {

        // the rest of properties go here

        private Type2Element() {
        }

    }

}
final class Response<T> {

    final int status = Integer.valueOf(0);
    final String message = null;
    final T data = null;

}

现在是反序列化器本身:

final class ElementJsonDeserializer
        implements JsonDeserializer<Element> {

    private static final JsonDeserializer<Element> elementJsonDeserializer = new ElementJsonDeserializer();

    private ElementJsonDeserializer() {
    }

    // The deserializer is essentially a singleton, but we hide away this fact making sure that only 1 instance exists
    static JsonDeserializer<Element> getElementJsonDeserializer() {
        return elementJsonDeserializer;
    }

    @Override
    public Element deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
            throws JsonParseException {
        final int typeCode = jsonElement.getAsJsonObject().getAsJsonPrimitive("type").getAsInt();
        // Simple dispatching here
        // RuntimeTypeAdapterFactory basically does the same
        switch ( typeCode ) {
        case 1:
            return context.deserialize(jsonElement, Type1Element.class);
        case 2:
            return context.deserialize(jsonElement, Type2Element.class);
        default:
            throw new JsonParseException("Unrecognized type: " + typeCode);
        }
    }

}

现在让它们一起工作(response.json 是您的 JSON 文档资源):

private static final Type type = new TypeToken<Response<List<Element>>>() {
}.getType();

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapter(Element.class, getElementJsonDeserializer())
        .create();

public static void main(final String... args)
        throws IOException {
    try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q43802350.class, "response.json") ) {
        final Response<List<Element>> response = gson.fromJson(jsonReader, type);
        response.data
                .stream()
                .map(Element::getClass)
                .map(Class::getSimpleName)
                .forEach(System.out::println);
    }
}

输出:

Type1Element
类型2元素

当然,不要忘记在 Retrofit 构建器中使用 GsonConverterFactory.create(gson) 注册 gson 实例。

【讨论】:

    【解决方案2】:

    1 使用改造转换 示例 GSON 转换

    2 在 gradle 文件中添加 com.squareup.retrofit2:converter-gson 3 在 Retrofit 对象中添加转换器工厂

    改造改造 = new Retrofit.Builder() .baseUrl(Ws_Url) .addConverterFactory(GsonConverterFactory.create()) .client(clientBuilder.build()) .build();

    4 为您的响应创建模型类 使用下面的链接生成模型类 http://www.jsonschema2pojo.org/

    【讨论】:

    • 该服务无法处理多态 JSON。
    • 是的,这无济于事,因为根据我提到的 JSON 结构,模型类中的项目应该是不同的。如果我在具有所有 json 项的模型类上创建,那么它会引发异常,因为它找不到其他 json 数组项的 KEY。
    猜你喜欢
    • 2021-09-06
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 2018-04-13
    • 2021-11-02
    相关资源
    最近更新 更多