2017-04-17 42 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); 

沒有問題。