使用GSON调整改造响应

Rya*_*yan 11 android json gson retrofit

我希望通过从特定API收到的每个成功响应,以非常方式检索已知JSON对象的子元素.

每个服务器响应都返回以下JSON格式(为简单起见,精简):

{
    "status": "success",
    "error_title": "",
    "error_message": "",
    "data": {
        "messages": [
            { "message_id": "123",
              "content": "This is a message" },
            { "message_id": "124",
              "content": "This is another message" }
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

错误响应包含相同的通用格式,"data"对象为空,错误相关的JSON对象包含有用的值.在出现错误的情况下,我想提取与错误相关的JSON对象.

通过上面的响应,我有一个MessageResponse包含status,errorTitle和errorMessage String属性的类以及一个MessageData对象.MessageData然后该对象包含一个消息列表 - List<Message> messages.在这种情况下获取消息的我的GET方法如下(为简单起见,简化):

@GET("/chat/conversation")
void getMessages(Callback<MessageResponse> callback);
Run Code Online (Sandbox Code Playgroud)

如果我坚持使用GSON的串行器提供的默认POJO映射,那么这种设计需要每个响应类型有三个类.我的最终目标是通过仅从成功的服务器响应中读取我需要的内容并忽略其余类来减少所需的类数量.我希望我所有的成功,这个API上的回调数据类型尽可能接近"数据"内容.

换句话说,我想非常地返回"数据"的子元素.在上面的例子中,它是一个名为"messages"的数组,但在某些其他响应中,它可能是一个"用户"对象,例如.我知道这可以通过TypeAdapter为每种响应类型注册单独的s 来完成,但我希望通过使用单个通用解决方案来实现我的最终目标.

更新:从下面实施David的建议

public class BaseResponse<T> {
     @SerializedName("status") public String status;
     @SerializedName("error_title") public String errorMessageTitle;
     @SerializedName("error_message") public String errorMessage;
     @SerializedName("data") public T data;
}

public class MessagesResponse extends BaseResponseData<List<Message>> {
     @SerializedName("messages") List<Message> messages;
}

@GET("/chat/conversation")
void getMessages(Callback<BaseResponse<MessageResponse>> callback);
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不是正确的序列化.如果我能以某种方式通知GSON来自"data"父级的可变命名的JSON对象子级,并将该子级反序列化为通用数据类型引用的模型类.基本上,dataJsonObject.getChild().

Rya*_*yan 9

经过几个小时向GSON提供通用,基本响应类失败后,我最终传递了这条路线并解决了我几天前实施的解决方案(减去状态检查条件).

GSON TypeAdapter通过在泛型中定义反序列化逻辑,提供了向所有响应添加的能力TypeAdapterFactory.这个实体并不像我希望的那样干净和无知,但它确实可以减少必要的响应模型类的数量,同时还可以维护一个适配器.

private static class ResponseTypeAdapterFactory implements TypeAdapterFactory {

    private static final String STATUS = "status";
    private static final String SUCCESS = "success";
    private static final String DATA = "data";

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> jsonElementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegateAdapter.write(out, value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                // Ignore extraneous data and read in only the response data when the response is a success
                JsonElement jsonElement = jsonElementAdapter.read(in);
                if (jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();
                    if (jsonObject.has(STATUS)) {
                        if (jsonObject.get(STATUS).getAsString().equals(SUCCESS)) {
                            if (jsonObject.has(DATA) && jsonObject.get(DATA).isJsonObject()) {
                                jsonElement = jsonObject.get(DATA);
                            }
                        }
                    }
                }
                return delegateAdapter.fromJsonTree(jsonElement);
            }
        }.nullSafe();
    }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,如果响应成功,我告诉GSON获取"数据"JSON对象.否则,返回整个响应主体,以便我的自定义Retrofit错误处理程序可以使用从服务器返回的"error_title"和"error_message"字段.

对@ david.mihola的巨大建议,提出了很好的建议,并最终将我的注意力转回到TypeAdapterFactory解决方案上.