【问题标题】:Using an inner JSON object of a response to convert it to POJO?使用响应的内部 JSON 对象将其转换为 POJO?
【发布时间】:2018-08-25 19:04:47
【问题描述】:

我想使用转换器立即从响应中获取 POJO,但根 JSON 对象并不是我想要反序列化为 POJO 的对象。事实上,我想将它的 2 个兄弟对象反序列化为一个 POJO。

例如从新的 Twitch API 获取流:

@GET("/helix/streams?first=1")
Call<TwitchStream> getLatestStreamsForGame(@Query("game_id") int gameId);

响应将是这样的:

{
  "data": [
    {
      "id": "26007494656",
      "user_id": "23161357",
      "game_id": "417752",
      "community_ids": [
        "5181e78f-2280-42a6-873d-758e25a7c313",
        "848d95be-90b3-44a5-b143-6e373754c382",
        "fd0eab99-832a-4d7e-8cc0-04d73deb2e54"
      ],
      "type": "live",
      "title": "Hey Guys, It's Monday - Twitter: @Lirik",
      "viewer_count": 32575,
      "started_at": "2017-08-14T16:08:32Z",
      "language": "en",
      "thumbnail_url": "https://static-cdn.jtvnw.net/previews-ttv/live_user_lirik-{width}x{height}.jpg"
    },
    ...
  ],
  "pagination": {
    "cursor": "eyJiIjpudWxsLCJhIjp7Ik9mZnNldCI6MjB9fQ=="
  }
}

这是我要存储流数据的类:

public class TwitchStream extends DataResponse{
    @SerializedName("id")
    private String id;
    @SerializedName("user_id")
    private String userId;
    @SerializedName("game_id")
    private String gameId;
    @SerializedName("community_ids")
    private List<String> communityIds;
    @SerializedName("type")
    private String type;
    @SerializedName("title")
    private String title;
    @SerializedName("viewer_count")
    private int viewerCount;
    @SerializedName("started_at")
    private String startedAt;
    @SerializedName("language")
    private String language;
    @SerializedName("thumbnail_url")
    private String thumbnailUrl;
    @SerializedName("cursor")
    private String paginationCursor;

    public TwitchStream(String id, String user_id, String game_id, List<String> community_ids, String type, String title, int viewer_count, String started_at, String language, String thumbnail_url, String paginationCursor) {
        this.id = id;
        this.userId = user_id;
        this.gameId = game_id;
        this.communityIds = community_ids;
        this.type = type;
        this.title = title;
        this.viewerCount = viewer_count;
        this.startedAt = started_at;
        this.language = language;
        this.thumbnailUrl = thumbnail_url;
        this.paginationCursor = paginationCursor;
    }

    public String getId() {
        return id;
    }

    public String getUserId() {
        return userId;
    }

    public String getGameId() {
        return gameId;
    }

    public List<String> getCommunityIds() {
        return communityIds;
    }

    public String getType() {
        return type;
    }

    public String getTitle() {
        return title;
    }

    public int getViewerCount() {
        return viewerCount;
    }

    public String getStartedAt() {
        return startedAt;
    }

    public String getLanguage() {
        return language;
    }

    public String getThumbnailUrl() {
        return thumbnailUrl;
    }

    public String getPaginationCursor() {
        return paginationCursor;
    }
}

我想把data的内容反序列化成上面的POJO,还需要pagination的光标。我想使用GsonConverterFactory,但Gson想反序列化根JSON对象,并且由于在此类中找不到任何名称或注释为datapagination的字段,因此它什么也没做。

我能做什么? 一种解决方案是创建一个包装类,并以这种方式创建调用:

@GET("/helix/streams?first=1")
Call<Wrapper<TwitchStream>> getLatestStreamsForGame(@Query("game_id") int gameId);

但是这样我会得到一个异常:

ResponseBase failed: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 10 path $.data
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 10 path $.data
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
    at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:122)
    at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:217)
    at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:116)
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:153)
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818)
 Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 10 path $.data
    at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:385)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:215)
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) 
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39) 
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27) 
    at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:122) 
    at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:217) 
    at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:116) 
    at okhttp3.RealCall$AsyncCall.execute(RealCall.java:153) 
    at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
    at java.lang.Thread.run(Thread.java:818)
enter code here

另一种选择是在 Gson 尝试反序列化根 JSON 对象之前使用 JSONParser,并且只将 datapagination 对象传递给 Gson 进行反序列化。但我怎么能这样做呢?

【问题讨论】:

    标签: java android json gson retrofit2


    【解决方案1】:

    正如您的例外所述

    ResponseBase 失败:com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:应为 BEGIN_OBJECT,但为 BEGIN_ARRAY 在第 1 行第 10 列路径 $.data

    它等待 json 对象但遇到 json 数组。因为在您的 json 结构中,“数据”是一个数组:

    "data": [ // data is a json array
        {
          "id": "26007494656",
          "user_id": "23161357",
          "game_id": "417752",
          "community_ids": [
            "5181e78f-2280-42a6-873d-758e25a7c313",
            "848d95be-90b3-44a5-b143-6e373754c382",
            "fd0eab99-832a-4d7e-8cc0-04d73deb2e54"
          ],
          "type": "live",
          "title": "Hey Guys, It's Monday - Twitter: @Lirik",
          "viewer_count": 32575,
          "started_at": "2017-08-14T16:08:32Z",
          "language": "en",
          "thumbnail_url": "https://static-cdn.jtvnw.net/previews-ttv/live_user_lirik-{width}x{height}.jpg"
        },
        ...
      ]
    

    所以我建议你为你的 json 结构创建一个根对象,其中包含 List&lt;Data&gt;(数据是你当前的 TwichStream 类,没有分页变量),并且根对象包含另一个代表分页对象的类。

    所以你有以下 3 个类:

    @Data // comes from lombok
    class RootClass {
        @SerializedName("data")
        private List<Data> datas;
        private Pagination pagination;
    }
    
    @Data
    class Pagination {
        private String cursor;
    }
    
    @Data
    class Data {
        // your current implementation without pagination field
    }
    

    【讨论】:

    • 很高兴为您提供帮助
    【解决方案2】:

    你提供的 JSON 基本上需要三个类。他们是以下。

    public class TwitchStream {
        public Data[] data;
        public Pagination pagination;
    }
    
    public class Pagination {
        public String cursor;
    }
    
    public class Data {
        public String id;
        public String thumbnail_url;
        public String title;
        public String game_id;
        public String started_at;
        public String[] community_ids;
        public String user_id;
        public String language;
        public String viewer_count;
        public String type;
    }
    

    希望您现在可以使用 Gson 轻松解析 JSON 响应。让我知道这是否有帮助!

    【讨论】:

    • 我想在一个列表中存储多个 Twitch Stream,我只是暂时简化了一点,专注于主要问题
    猜你喜欢
    • 1970-01-01
    • 2017-10-17
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 2015-02-17
    • 2012-10-25
    • 1970-01-01
    • 2018-07-26
    相关资源
    最近更新 更多