2016-03-04 3 views
6

ich eine einfache ENUM haben:Wie übergeben benutzerdefinierte Enum in @Query über Retrofit?

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

eine Version starten, wurde Gson der Lage, solche Aufzählungen zu analysieren. Um sicherzugehen, habe ich Folgendes getan:

Es funktioniert, wie ich erwartet habe. Ausgabe ist "0". Also versuchte ich es in meinem Retrofit-Dienste verwenden:

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

Und auch hinzugefügt Anmeldung wirklich sicher sein, um sein Ergebnis:

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

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

Aber es ist fehlgeschlagen. @Query völlig ignoriert @SerializedName und .toString() stattdessen verwendet, so dass das Protokoll mir .../index.php?page[api]=test&season_lookup=AUTUMN angezeigt.

Ich verfolgte Quellen Retrofit und gefunden Datei RequestFactoryParser mit Linien:

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

Es scheint, wie es überhaupt nicht um Aufzählungen schert. Vor diesen Zeilen testete es rawParameterType.isArray() zu einem Array oder Iterable.class.isAssignableFrom() und nichts mehr.

Retrofit Beispiel Schöpfung:

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

gson ist GsonBuilder().create(). Ich schaute auf Quellen, dort ist ENUM_TypeAdapters.ENUM_FACTORY für enums vordefiniert, also lasse ich es so wie es ist.


Die Frage ist, was kann ich tun zu verhinderntoString()auf meiner Aufzählung mit und@SerializedNameverwenden? Ich benutzetoString()für andere Zwecke.

+1

Haben Sie richtigen Konverter haben zu Ihrem Retrofit hinzugefügt? https://github.com/square/retrofit/tree/master/retrofit-converters –

+1

Es scheint, dass Retrofit Gson beim Serialisieren

@Body
, aber nicht
@Query
verwendet, weil mit es richtig serialisiert ist. –

+0

@ DawidSzydło, aber gibt es eine Möglichkeit, etwas wie Konverter für 'Enum ' nur zu schreiben? Ich möchte Reflection in das für @ SerializedName verwenden – Nexen

Antwort

6

Als @ DawidSzydło erwähnt, missverstanden Gson Verwendung im Retrofit. Es wird nur für die Decodierung/Codierung der Antwort/Anforderung verwendet, jedoch nicht für @Query/@Url/@Path e.t.c. Für sie verwendet Retrofit Converter.Factory, um einen beliebigen Typ in String umzuwandeln. Hier ist der Code für die automatische Verwendung von @SerializedName als Wert von Enum bei der Übergabe an Retrofit-Dienste.

Converter:

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 Kreation:

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

Sieht gut aus, aber es wird fehlschlagen, wenn Sie enum ohne serialisierten Namen Annotation in anderen Anfragen verwenden möchten. Im Grunde wird es eine schnelle Lösung dafür geben: In catch in Ihrer Hilfsklasse sollten Sie den Wert auf den Wert setzen, falls keine Annotation verwendet wird. –

Verwandte Themen