1

我正在使用一个 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) 而不公开它?

4

1 回答 1

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 是您的超类,所有服务响应都从该超类继承。第一个解决方案建议仍然有效。

于 2013-07-13T07:46:37.020 回答