在gson中剥离外部响应数组的简单方法

时间:2013-07-13 07:06:14

标签: json gson

我正在使用一个api(Phillips Hue),它将所有json响应包含在一个带有一个条目(内容)的数组中。

示例:

[{
    "error": {
        "type": 5,
        "address": "/",
        "description": "invalid/missing parameters in body"
    }
}]

我经常编写由GSON解析的标准POJO来处理响应,但由于响应不是json对象,我对处理这个问题的最佳方法感到有些困惑。我真的不希望每个对象实际上都是一个我必须调用.get(0)的数组。

POJO的示例,如果它是JSON obj而未包装在数组中。

public class DeviceUserResponse {
    private DeviceUser success;
    private Error error;

    public DeviceUser getSuccess() {
        return success;
    }

    public Error getError() {
        return error;
    }

    public static class Error {
        private int type;
        private String address;
        private String description;

        public int getType() {
            return type;
        }

        public String getAddress() {
            return address;
        }

        public String getDescription() {
            return description;
        }

        @Override
        public String toString() {
            return "Type: " + this.type
                    + " Address: " + this.address
                    + " Description: " + this.description;
        }
    }
}

我现在必须做的事情:

ArrayList<DeviceUserResponse> response.get(0).getError();

有没有办法可以为每个响应删除这个数组,或者我只需要在我的POJO中执行.get(0)而不暴露它?

1 个答案:

答案 0 :(得分:2)

我认为你要使用自定义反序列化来“剥离”数组。

这是一个可能的解决方案。

您的回复POJO的适配器:

 public class DeviceUserResponseAdapter extends TypeAdapter<DeviceUserResponse> {

   protected TypeAdapter<DeviceUserResponse> defaultAdapter;

   public DeviceUserResponseAdapter(TypeAdapter<DeviceUserResponse> defaultAdapter) {
    this.defaultAdapter = defaultAdapter;
   }

   @Override
   public void write(JsonWriter out, DeviceUserResponse value) throws IOException {
    defaultAdapter.write(out, value);
   }

   @Override
   public DeviceUserResponse read(JsonReader in) throws IOException {
     in.beginArray();
     assert(in.hasNext());
     DeviceUserResponse response = defaultAdapter.read(in);
     in.endArray();
     return response;
    }
 }

适配器的工厂:

 public class DeviceUserResponseAdapterFactory implements TypeAdapterFactory {

   @Override
   @SuppressWarnings("unchecked")
   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
     if (type.getRawType()!=DeviceUserResponse.class) return null;

     TypeAdapter<DeviceUserResponse> defaultAdapter = (TypeAdapter<DeviceUserResponse>) gson.getDelegateAdapter(this, type);
     return (TypeAdapter<T>) new DeviceUserResponseAdapter(defaultAdapter);
   }
 }

然后你要注册并使用它:

 DeviceUserResponseAdapterFactory adapterFactory = new DeviceUserResponseAdapterFactory();

 GsonBuilder gsonBuilder = new GsonBuilder();
 Gson gson = gsonBuilder.registerTypeAdapterFactory(adapterFactory).create();
 DeviceUserResponse response = gson.fromJson(json, DeviceUserResponse.class);
 System.out.println(response.getError());

如果您在其他复杂的JSON对象中包含DeviceUserResponse,则此解决方案将无效。在那种情况下,适配器将尝试查找数组,并将以错误终止。

另一种解决方案是将其解析为数组,然后在“通信”层中只获得第一个元素。这将保留GSon反序列化。

在评论中你要求更通用的解决方案,这里有一个: 适配器:

public class ResponseAdapter<T> extends TypeAdapter<T> {

protected TypeAdapter<T> defaultAdapter;

public ResponseAdapter(TypeAdapter<T> defaultAdapter) {
    this.defaultAdapter = defaultAdapter;
}

@Override
public void write(JsonWriter out, T value) throws IOException {
    defaultAdapter.write(out, value);
}

@Override
public T read(JsonReader in) throws IOException {
    in.beginArray();
    assert(in.hasNext());
    T response = defaultAdapter.read(in);
    in.endArray();
    return response;
}
}

工厂:

public class ResponseAdapterFactory implements TypeAdapterFactory {

@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
    if ((type.getRawType().getSuperclass() != Response.class)) return null;

    TypeAdapter<T> defaultAdapter = (TypeAdapter<T>) gson.getDelegateAdapter(this, type);
    return (TypeAdapter<T>) new ResponseAdapter<T>(defaultAdapter);
}
}

其中Response.class是您所有服务响应继承的超类。 第一个解决方案建议仍然有效。