使用Retrofit和Gson将JSON反序列化为POJO

时间:2015-08-12 10:19:20

标签: java json gson retrofit json-deserialization

我正在使用一个API,它对单个用户资源的响应如下:

{
  "data": {
    "id": 11,
    "first_name": "First",
    "last_name": "Last",
    "books": {
      "data": [
        {
          "id": 13,
          "name": "Halo"
        }
      ]
    },
    "games": {
      "data": [
        {
          "id": 1,
          "name": "Halo"
        }
      ]
    }
  }
}

或类似以下用于多个用户资源:

{
  "data": [
    {
      "id": 11,
      "first_name": "First",
      "last_name": "Last",
      "books": {
        "data": [
          {
            "id": 13,
            "name": "Halo"
          }
        ]
      },
      "games": {
        "data": [
          {
            "id": 1,
            "name": "Halo"
          }
        ]
      }
    },
  ],
  "meta": {
    "pagination": {
      "total": 11,
      "count": 10,
      "per_page": 10,
      "current_page": 1,
      "total_pages": 2,
      "links": {
        "next": "http://api.###.com/users?page=2"
      }
    }
  }
}

需要注意的关键事项是:

  1. 所有资源都嵌套在data键下,单个作为对象,或多个作为对象数组。这包括嵌套资源,例如上面示例中的书籍和游戏。
  2. 我需要能够为我的分页例程检索meta键的值
  3. 用户模型

    public class User extends BaseModel {
    
        public Integer id;
        public String firstName;
        public String lastName;
    
        public List<Book> books; // These will not receive the deserialized 
        public List<Game> games; // JSON due to the parent data key
    
    }
    

    自定义JSON反序列化程序

    public class ItemTypeAdapterFactory implements TypeAdapterFactory {
    
        public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
    
            final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
            final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
    
            return new TypeAdapter<T>() {
    
                public void write(JsonWriter out, T value) throws IOException {
                    delegate.write(out, value);
                }
    
                public T read(JsonReader in) throws IOException {
    
                    JsonElement jsonElement = elementAdapter.read(in);
                    if (jsonElement.isJsonObject()) {
                        JsonObject jsonObject = jsonElement.getAsJsonObject();
                        // If the data key exists and is an object or array, unwrap it and return its contents
                        if (jsonObject.has("data") && (jsonObject.get("data").isJsonObject() || jsonObject.get("data").isJsonArray())) {
                            jsonElement = jsonObject.get("data");
                        }
                    }
    
                    return delegate.fromJsonTree(jsonElement);
                }
            }.nullSafe();
        }
    }
    

    这一切都运行正常,但我无法弄清楚如何访问meta密钥进行分页。

    理想情况下,我会让Gson反序列化对以下POJO的响应:

    public class ApiResponse {
        public Object data;
        public Meta meta
    }
    

    我可以将response字段转换为响应回调中的正确类型,如下所示:

    Map<String, String> params = new HashMap<String, String>();
    params.put("include", "books,games");
    ApiClient.getClient().authenticatedUser(params, new ApiClientCallback<ApiResponse>() {
        @Override
        public void failure(RestError restError) {
            Log.d("TAG", restError.message);
        }
    
        @Override
        public void success(ApiResponse response, Response rawResponse) {
            User user = (User) response.data; // Cast data field to User type
            Log.d("TAG", user.firstName);
            Log.d("TAG", "Total pages" + response.meta.pagination.total.toString()); // Still have access to meta key data
        }
    });
    

    data对象的ApiResponse字段为null

    我的Java非常生疏,我不知道这是否可能,也不知道如何正确理解,任何帮助都会非常感激。

0 个答案:

没有答案