2017-04-17 41 views
1

我一直在使用Retrofit 2和一些POJO对象一段时间了。这是一个可爱的图书馆,工作得很好,但它需要我想摆脱的一些可怕和杂乱的模型。改装2,GSON和定制解串器

我会告诉你......我有以下的JSON细读:使用POJO模式发生器这创造,使维护代码很难做无谓类

{ 
    "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": {} 
    } 

这将产生:

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__),这两个类可以被删除,“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给我的事情的列表是可用的。

Enter Retrofit 2!已经加入registerTypeAdapter()在我改造2实例(通过我的GSON实例)现在我得到一个错误信息:

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; 
    } 
} 

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

我需要做什么改变,或者我该如何操纵Retrofit来像我写的Gson解串器一样工作?我有作品,但为了学习新东西和编写更好更易维护的代码,我想弄明白这一点。我可以使用ResponseBody回调函数并通过Deserializer抛出Json,但必须有更好的方法。

+0

我不明白为什么你没有类,让我们调用它,包含事物列表的ThingsResponse,以及其他两个属性,数量和链接。并使用pojo从api调用中获得翻新答案。 –

+0

@JonathanAste我可以。这基本上是我现在拥有的。但是一个模型有三个类。最终,我将要解析一个稍微有些布局的XML文件到相同的模型中。将这些减少一点会非常有用。我只是想知道是否没有办法使用我的Deserializer进行Retrofit工作,而无需获得原始响应,并在RF为我执行此操作时手动解析它。 – MattBoothDev

+0

嗯,似乎你可以创建一个'TypeAdapterFactory'而不是解串器。检查这是否可以帮助你http://stackoverflow.com/a/28736167/5658915 –

回答

3

感谢@JonathanAste我明白了。

而不是一个Deserializer,我需要一个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); 

没有问题。