【问题标题】:GSON deserialization of a wrapped list of objects包装的对象列表的 GSON 反序列化
【发布时间】:2015-08-17 22:13:58
【问题描述】:

我正在尝试从 JSON 响应中反序列化对象列表。 JSON 数组有一个密钥,这会导致使用 GSON 对其进行反序列化时出现问题。

我有大约 20 个类似的对象。

public class Device extends Entity {
  String device_id;
  String device_type;
  String device_push_id;
}

对于大多数情况,有一个返回对象列表的 API 方法。返回的 JSON 如下所示。由于其他客户端,此时更改 JSON 的格式不是一个合理的选择。

{
   "devices":[
      {
         "id":"Y3mK5Kvy",
         "device_id":"did_e3be5",
         "device_type":"ios"
      },
      {
         "id":"6ZvpDPvX",
         "device_id":"did_84fdd",
         "device_type":"android"
      }
   ]
}

为了解析这种类型的响应,我目前正在使用org.json 方法和 Gson 的组合。

JSONArray jsonResponse = new JSONObject(response).getJSONArray("devices");

Type deviceListType = new TypeToken<List<Device>>() {}.getType();
ArrayList<Device> devices = gson.fromJson(jsonResponse.toString(), deviceListType);

我正在寻找一种更简洁的反序列化方法,因为我想使用 Retrofit。 Get nested JSON object with GSON using retrofit 中的答案接近我所需要的,但不能处理 Lists。我在这里复制了答案的通用版本:

public class RestDeserializer<T> implements JsonDeserializer<T> {
  private Class<T> mClass;
  private String mKey;

  public RestDeserializer(Class<T> targetClass, String key) {
    mClass = targetClass;
    mKey = key;
  }

  @Override
  public T deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext)
    throws JsonParseException {

    JsonElement value = jsonElement.getAsJsonObject().get(mKey);
    if (value != null) {
      return new Gson().fromJson(value, mClass);
    } else {
      return new Gson().fromJson(jsonElement, mClass);
    }
  }
}

我的目标是让这个电话“正常工作”。

@GET("/api/v1/protected/devices")
public void getDevices(Callback<List<Device>> callback);

【问题讨论】:

  • 不就是一个简单的List&lt;Device&gt;吗?如果字段名称与 Json 名称不同,只需使用 @SerializedName 注释即可。 Retrofit 会为你做解析
  • 你如何创建和注册你的反序列化器?
  • 我目前没有使用反序列化器,因为它实际上并不能解决问题。
  • @MarcoAcierno,我没有包含设备列表的类。我试图避免创建不需要的(希望是不必要的!)包装类。
  • @Derek,你是怎么解决这个问题的。你能发表你的答案吗?

标签: java android json gson retrofit


【解决方案1】:

使用下面的类

public class Devices {

@Expose
private List<Device> devices = new ArrayList<Device>();

/**
* 
* @return
* The devices
*/
public List<Device> getDevices() {
return devices;
}

/**
* 
* @param devices
* The devices
*/
public void setDevices(List<Device> devices) {
this.devices = devices;
}

}

设备类

public class Device extends Entity {
  @Expose
  String id;
   @Expose
  String device_id;
  @Expose
  String device_type;
}

public class Device extends Entity {
  @Expose @SerializedName("id")
  String deviceId;
   @Expose @SerializedName("device_id")
  String devicePushId;
  @Expose @SerializedName("device_type")
  String deviceType;
}

更新改造方法

@GET("/api/v1/protected/devices")
public void getDevices(Callback<Devices> callback);

devices.getDevices() //call inside callback method will give you the list

另外,您不需要自定义反序列化器

【讨论】:

  • 我考虑过这一点,如果没有通用选项出现,我确实会这样做。但是,因为我有 20 多个这样的对象,所以我希望避免使用 20 个额外的类来包装列表。
  • 试试这个 @GET("/api/v1/protected/devices") public void getDevices(Callback callback callback);我自己没有尝试过,让我知道这是否可行。如果可行,您不必创建额外的对象
  • 那行不通。一个问题是 Gson 如何知道名为“devices”的 json 元素是正确解包以找到它的 List 或 Device[]。
  • List 应该可以工作,你试过吗? Retrofit 在内部使用 gson 并为您处理映射。如果不进行改造,您将不得不编写自己的反序列化器
  • 我试过 List。问题是 gson 不能凭直觉知道如何解开 {"devices": [ { ... device ... }, { ... device ...} ] }。上面的泛型反序列化器是一种解包单个对象的紧凑方式,但在 java 中没有用于参数化类型(如 List&lt;Device&gt;)的类文字。你给了我使用 Device[] 的想法,它确实有一个类文字。我现在会努力解决这个问题。谢谢!
猜你喜欢
  • 1970-01-01
  • 2015-04-07
  • 2016-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多