2016-03-04 61 views
6

我有一個簡單枚舉:如何通過改進在@Query中傳遞自定義枚舉?

public enum Season { 
    @SerializedName("0") 
    AUTUMN, 
    @SerializedName("1") 
    SPRING; 
} 

開始有些版本,GSON成爲能夠解析這樣的枚舉。爲了確保,我做到了這一點:

final String s = gson.toJson(Season.AUTUMN); 

它按我的預期工作。輸出是"0"。所以,我想在我的改裝服務使用它:

@GET("index.php?page[api]=test") 
Observable<List<Month>> getMonths(@Query("season_lookup") Season season); 
/*...some files later...*/ 
service.getMonths(Season.AUTUMN); 

而且還新增記錄,真正做到某些關於它的結果:

HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); 
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); 

OkHttpClient httpClient = new OkHttpClient.Builder() 
     .addInterceptor(httpLoggingInterceptor) 
     .build(); 

但失敗了。 @Query完全忽略@SerializedName而用.toString()代替,所以日誌顯示我.../index.php?page[api]=test&season_lookup=AUTUMN

我追查改造來源,發現文件RequestFactoryParser用線:

Converter<?, String> converter = 
    retrofit.stringConverter(parameterType, parameterAnnotations); 
action = new RequestAction.Query<>(name, converter, encoded); 

看來,好像它並不關心在所有關於枚舉。在這些線路之前,它測試了rawParameterType.isArray()是一個數組或Iterable.class.isAssignableFrom(),僅此而已。

改造實例創建:

retrofit = new Retrofit.Builder() 
       .baseUrl(ApiConstants.API_ENDPOINT) 
       .client(httpClient) 
       .addConverterFactory(GsonConverterFactory.create(gson)) 
       .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
       .build(); 

gsonGsonBuilder().create()。我在源代碼中偷看,其中預定義了ENUM_TypeAdapters.ENUM_FACTORY用於枚舉,所以我將它保留原樣。


的問題是,我能做些什麼,以防止使用我枚舉toString()和使用@SerializedName?我使用toString()用於其他目的。

+1

你有適當的轉換器添加到您的改造? https://github.com/square/retrofit/tree/master/retrofit-converters –

+1

似乎Retrofit使用Gson,而序列化

@Body
,但不是
@Query
,因爲與
@Body
它是序列化的正確方式。 –

+0

@DawidSzydło,但是有沒有什麼辦法可以像'Enum '這樣的轉換器?我想在'@ SerializedName'中使用反射 – Nexen

回答

6

As @DawidSzydło提到,我誤解了Gson在改造中的用法。它僅用於響應/請求解碼/編碼,但不適用於@Query/@Url/@Path e.t.c。對於他們來說,Retrofit使用Converter.Factory將任何類型轉換爲String。 這是自動使用@SerializedName作爲任何Enum傳遞給Retrofit服務時的值的代碼。

轉換器:

public class EnumRetrofitConverterFactory extends Converter.Factory { 
    @Override 
    public Converter<?, String> stringConverter(Type type, Annotation[] annotations, Retrofit retrofit) { 
     Converter<?, String> converter = null; 
     if (type instanceof Class && ((Class<?>)type).isEnum()) { 
      converter = value -> EnumUtils.GetSerializedNameValue((Enum) value); 
     } 
     return converter; 
    } 
} 

EnumUtils:

public class EnumUtils { 
    @Nullable 
    static public <E extends Enum<E>> String GetSerializedNameValue(E e) { 
     String value = null; 
     try { 
      value = e.getClass().getField(e.name()).getAnnotation(SerializedName.class).value(); 
     } catch (NoSuchFieldException exception) { 
      exception.printStackTrace(); 
     } 
     return value; 
    } 
} 

改造創造:

retrofit = new Retrofit.Builder() 
     .baseUrl(ApiConstants.API_ENDPOINT) 
     .client(httpClient) 
     .addConverterFactory(GsonConverterFactory.create(gson)) 
     .addConverterFactory(new EnumRetrofitConverterFactory()) 
     .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
     .build(); 
+2

看起來很好,但是如果你想在其他請求中使用沒有序列化名稱註釋的枚舉,它會失敗。基本上會有這樣的快速解決方法:在抓住你的助手類時,如果沒有使用註釋,你應該將value值設置爲枚舉值。 –