Retrofit 2, GSON and custom deserializer



我已经使用了一些POJO对象的Retrofit 2已有一段时间了。这是一个可爱的图书馆,效果很好,但是我想摆脱一些可怕而混乱的模特。

我会告诉你...我有以下json仔细阅读:

    {
    "things": [
        {
            "thing": {
                "id": 823,
                "created_at": "2016-02-09T22:55:07.153Z",
                "published_at": "2016-02-10T19:23:42.666Z",
                "downloads": 16073,
                "size": 10716291
            }
        },
    ],
    "count": 4,
    "links": {}
    }

使用POJO架构生成器这会创建不必要的类,使维护代码难以执行。

这将创建:

Things.java
    @SerializedName("things")
    @Expose
    public List<Things_> things = new ArrayList<>();
Things_.java
    @SerializedName("thing")
    @Expose
    private Thing__ thing;
Things__.java
    // Insert normal variables and getter/setters here

我将其减少了一点,因为它只是为了想法。在我的用法中,我当然会重命名这些课程,以使它们更容易管理。但是我认为有一种简单地跳过事物和事物_的方法,然后允许我返回实际模型数据的列表(thing __(,并且可以删除这两个类,而" Thing thing __"可以简单地说是"事物"。

我是对的。GSON允许自定义的挑战,使我实现这一目标。我一起扔了一个快速的求职者,并使用了适当的TypeToken

    Gson gson = new GsonBuilder()
            .registerTypeAdapter(new TypeToken<ArrayList<Thing>>(){}.getType(), new AddonDeserializer())
            .create();
    List<Thing> model = gson.fromJson(jsonString, new TypeToken<ArrayList<Thing>>(){}.getType());

果然,将其传递给上述确切的JSON提供了可用的内容清单。

输入Raturofit 2!在我的reatrofit 2实例(通过我的gson实例(中添加了registerTypeadapter((,我现在收到一个错误消息:

 Expected BEGIN_ARRAY but was BEGIN_OBJECT

这是因为我的电话可能是:

@Get("end/of/url/here/{slug}.json") 
Call<List<Thing>> getThings(@Path("slug") String slug);

我的JSON以一个对象("事物"(开头,其中包含"事物"对象数组。我的求职者对此没有任何问题:

public class ThingDeserializer implements JsonDeserializer<List<Thing>> {
    @Override
    public List<Thing> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonArray array = json.getAsJsonObject().getAsJsonArray("things");
        ArrayList<Thing> list = new ArrayList<>();
        for (JsonElement anArray : array) {
            list.add((Thing) context.deserialize(anArray.getAsJsonObject().get("thing").getAsJsonObject(), Thing.class));
        }
        return list;
    }
}

无论如何,感谢您坚持这个漫长的问题!

我需要做什么不同,或者如何操纵改造与我写的Gson Deserializer相同的行为?我的工作原理,但是为了学习新知识,写出更好,更可维护的代码,我想弄清楚这一点。我可以求助于使用响应机体回调并通过我的避难所将JSON投掷,但是必须有一个更好的方法。

感谢@jonathanaste,我发现了它。

而不是求职者,我需要一个TypeadapterFactory实现。

public class ThingTypeAdapterFactory 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("things") && jsonObject.get("things").isJsonArray())
                    {
                        jsonElement = jsonObject.get("things");
                    }
                }
                if (jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();
                    if (jsonObject.has("thing") && jsonObject.get("thing").isJsonObject())
                    {
                        jsonElement = jsonObject.get("thing");
                    }
                }
                return delegate.fromJsonTree(jsonElement);
            }
        }.nullSafe();
    }
}

这使您可以使用

@GET("end/of/url/here/{slug}.json") 
Call<List<Thing>> getThings(@Path("slug") String slug);

无问题。

最新更新