Gson deserializer with Retrofit converter: just need inner JSON for all responses

我与影子孤独终老i 提交于 2019-12-20 15:16:42

问题


I am working with an API that always responds like so:

{
"stuff_i_need": [
    {
        "title": "Hello"
    },
    {
        "title": "World!"
    }
],
"status": "success"
}

and

{
"other_things_key":
    {
        "version": "208"
    },
"status": "success"
}

There are always two elements, and I just need the one that is not "status." I want to do this with one GsonBuilder, as well.

I tried:

new GsonConverter(new GsonBuilder()
    .registerTypeAdapter(List.class, new JsonDeserializer<List>() {
        @Override
        public List deserialize(JsonElement json, Type typeOfT,
                JsonDeserializationContext context)
        throws JsonParseException {
            final JsonObject jsonObject = json.getAsJsonObject();
            for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
                final JsonElement element = entry.getValue();
                if (element.isJsonArray()) {
                    return new Gson().fromJson(element.getAsJsonArray(),
                            new TypeToken<List>(){}.getType());
                }
            }
            return null;
        }
    )

but I don't think that is right, and it doens't satisfy the broader conditions.


回答1:


With some help from Gowtham, I ended up doing the following:

private static class ItemTypeAdapterFactory implements TypeAdapterFactory {

    @Override
    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>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            @Override
            public T read(JsonReader in) throws IOException {
                JsonElement jsonElement = elementAdapter.read(in);
                if (jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();
                    if (jsonObject.entrySet().size() == 2) {
                        jsonObject.remove("status");
                        jsonElement = jsonObject.entrySet().iterator().next().getValue();
                    }
                }
                return delegate.fromJsonTree(jsonElement);
            }
        }.nullSafe();
    }
}

and this is set on the RestAdapter.Builder:

.setConverter(new GsonConverter(new GsonBuilder()
                .registerTypeAdapterFactory(new ItemTypeAdapterFactory())
                .create()))

I really just ended up removing the "status" JsonObject.




回答2:


Try this

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 (jsonObject.has("data") && jsonObject.get("data").isJsonObject())
                {
                    jsonElement = jsonObject.get("data");
                }
            }

            return delegate.fromJsonTree(jsonElement);
        }
    }.nullSafe();
}}

Next, you have to add it to the Gson object in your RestClient.

public class RestClient
{
    private static final String BASE_URL = "your base url";
    private ApiService apiService;

    public RestClient()
    {
        Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(new ItemTypeAdapterFactory()) // This is the important line ;)
                .setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'")
                .create();

        RestAdapter restAdapter = new RestAdapter.Builder()
                .setLogLevel(RestAdapter.LogLevel.FULL)
                .setEndpoint(BASE_URL)
                .setConverter(new GsonConverter(gson))
                .setRequestInterceptor(new SessionRequestInterceptor())
                .build();

        apiService = restAdapter.create(ApiService.class);
    }

    public ApiService getApiService()
    {
        return apiService;
    }
}

Hope it helps...



来源:https://stackoverflow.com/questions/28601418/gson-deserializer-with-retrofit-converter-just-need-inner-json-for-all-response

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!