2015-02-13 3 views
5

Stellen Sie sich folgende Anfrage:Serialize Abfrage-Parameter in Retrofit

@POST("/recipes/create") 
void createRecipe(@Query("recipe") Recipe recipe, Callback<String> callback); 

Ich möchte toJson haben (Rezept), aber leider ist meine Bitte rufen toString nur() für mein Rezept, das überhaupt nicht funktionieren.

Ich könnte den toString innerhalb von Rezept überschreiben, aber ich hätte lieber eine allgemeine Lösung.

Ich kann nicht verwenden @Body wie ich angeben müssen, was ich schicke (ich habe Notwendigkeit, „Rezept = json (theRecipe)“.

Ich kann auch nicht die Serialisierung ändern hinzufügen „Rezept =“ da ich nicht verantwortlich für die Server bin.

im Moment habe ich eine QueryMap Karte bin mit dem ich in einem serialisierten Objekt setzen. Obwohl dies funktioniert, ist es nicht eine sehr schöne Lösung meiner Meinung nach.

Kann ich den Retrofit-Adapter irgendwie abfangen?

Antwort

6

Ich glaube nicht, dass es dies jetzt auf eine nette Weise unterstützt. Überprüfen Sie diese Antwort von einem der Autoren: https://github.com/square/retrofit/issues/291

Das vorgeschlagene Verfahren aus dieser Antwort ist einen benutzerdefinierten Typ zu erstellen, die die toString() Methode überschreibt, weil Retrofit intern String.valueOf(value) verwendet Abfrage oder Pfadparameter in Strings zu konvertieren.

So konnten Sie so etwas wie dieses:

class Recipe { 
    public int id; 
    public String title; 

    @Override 
    public String toString() { 
    // You can use a GSON serialization here if you want 
    // This is not a robust implementation 
    return Integer.toString(id) + "-" + title; 
    } 
} 
+0

Anscheinend Unterstützung wurde seit hinzugefügt. Siehe [Antwort unten] (http://stackoverflow.com/a/42459356/741217) –

0

Sie können r verwenden etrofit.RestAdapter.Builder(). setConverter (...) um einen benutzerdefinierten JSON-Konverter zu übergeben.

+1

Vielen Dank für die schnelle Antwort. Ich habe den Konverter schon eingestellt. Das Problem ist, dass der Konverter nur innerhalb des @ Body verwendet wird.Ich brauche meine Serialisierung innerhalb der @ Query – Frame91

3

Dies ist nun möglich, wenn eine benutzerdefinierte Converter.Factory Registrierung, die die stringConverter Methode überschreibt, die aufgerufen wird, wenn die Parameter zu lösen. Die Github issue, auf die sich @William vor 2 Jahren bezog, scheint nicht aktualisiert zu sein, seit Support hinzugefügt wurde.

Methode Javadoc:

Gibt einen Konverter für Typ Konvertierung in einen String oder null, wenn Typ kann nicht von diesem Werk behandelt werden. Dies wird verwendet, um Konverter für Typen zu erstellen, die durch die Werte @Field, @FieldMap, @Header, @HeaderMap, @Path, @Query und @QueryMap angegeben werden.

Das folgende Beispiel delegiert an Gson, aber genauso kann jede Art von Konvertierung auf die Parameter angewendet werden.

Beispiel: GsonStringConverterFactory

class GsonStringConverterFactory 
    extends Converter.Factory { 

    private final transient Gson gson; 

    GsonStringConverterFactory(final Gson gson) { 

     this.gson = gson; 
    } 

    @Override 
    public Converter<?, String> stringConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) { 

     final TypeAdapter typeAdapter; 
     typeAdapter = gson.getAdapter(TypeToken.get(type)); 

     return new StringConverter<>(typeAdapter); 
    } 

    private static class StringConverter<T> 
      implements Converter<T, String> { 

     private final TypeAdapter<T> typeAdapter; 

     private StringConverter(final TypeAdapter<T> typeAdapter) { 

      this.typeAdapter = typeAdapter; 
     } 

     @Override 
     public String convert(final T value) 
       throws IOException { 

      /* This works in our case because parameters in this REST api are always some kind of scalar 
      * and the toJson method converts these to simple json types. */ 
      final String jsonValue; 
      jsonValue = typeAdapter.toJson(value)); 

      if (jsonValue.startsWith("\"") && jsonValue.endsWith("\"") { 
       /* Strip enclosing quotes for json String types */ 
       return jsonValue.substring(1, jsonValue.length() - 1); 
      } else { 
       return jsonValue; 
      } 
     } 
    } 
} 

Registrieren der Konverter:

den benutzerdefinierten Konverter Um sich anzumelden, könnte Ihr Retrofit-Builder wie folgt aussehen:

new Retrofit.Builder().baseUrl(BASE_URL) 
          .addConverterFactory(GsonConverterFactory.create(gson)) 
          .addConverterFactory(new GsonStringConverterFactory(gson)) 
          .build();