2015-06-17 15 views
7

Sto cercando di utilizzare un convertitore personalizzato per retrofitpersonalizzato Converter per retrofit

RestAdapter.Builder builder = new RestAdapter.Builder() 
       .setEndpoint(BuildConfig.BASE_SERVER_ENDPOINT) 
       .setClient(new OkClient(client)).setConverter(new CitationResponseConverter()) 
       .setLogLevel(RestAdapter.LogLevel.FULL); 

di seguito è il mio convertitore personalizzato

public class CitationResponseConverter implements Converter { 

    @Override 
    public Object fromBody(TypedInput typedInput, Type type) throws ConversionException { 
     try { 
      InputStream in = typedInput.in(); // convert the typedInput to String 
      String string = fromStream(in); 
      in.close(); // we are responsible to close the InputStream after use 

      if (String.class.equals(type)) { 
       return string; 
      } else { 
       return new Gson().fromJson(string, 
         type); // convert to the supplied type, typically Object, JsonObject or Map<String, Object> 
      } 
     } catch (Exception e) { // a lot may happen here, whatever happens 
      throw new ConversionException(
        e); // wrap it into ConversionException so retrofit can process it 
     } 
    } 

    @Override 
    public TypedOutput toBody(Object object) { 
     return null; 
    } 

    private static String fromStream(InputStream in) throws IOException { 
     BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 
     StringBuilder out = new StringBuilder(); 
     String line; 
     while ((line = reader.readLine()) != null) { 
      out.append(line); 
      out.append("\r\n"); 
     } 
     return out.toString(); 
    } 
} 

sto ottenendo il seguente errore

retrofit.RetrofitError: method POST must have a request body. 

mentre provando a fare questa chiamata api

@POST("/service/citations") 
    Observable<CitationMain> getCitations(@Body CitationRequestBody body); 

Suppongo che il convertitore stia ignorando la richiesta per la chiamata api, come evitarlo e passare il corpo della richiesta definito nel servizio di retrofit.

Risposta:

{ 
    "citations": [ 
    { 
     "coverdatestart": "2015-05-01", 
     "coverimage": [ 
     "09699961/S0969996115X00040/cov200h.gif", 
     "09699961/S0969996115X00040/cov150h.gif" 
     ], 
     "pubyear": "2015", 
     "refimage": [ 
     "09699961/S0969996115X00040/S0969996115000522/gr1-t.gif", 
     "09699961/S0969996115X00040/S0969996115000522/gr1.jpg" 
     ], 
     "volissue": "Volume 77", 
     "volume": "77" 
    }, 
    { 
     "pubdatetxt": "19700101", 
     "refimage": "mma:otto_4_9781455748600/9781455748600_0020", 
    } 
    ] 
} 
+0

sì, questo è ciò che fa "toBody". Devi effettivamente restituire qualcosa lì, altrimenti non c'è nulla nel tuo Corpo. Ad esempio, potresti provare ad estendere GsonConverter al tuo convertitore personalizzato. – njzk2

+0

ma per quello che stai cercando di fare (ricevere jsonobject o stringhe semplici), userei un GsonConverter standard, e per i servizi di stringa semplice restituisco un 'Observable ', che mapperei in un metodo per ottenere la stringa dalla risposta (usando il metodo fromStream che si ha su 'reponse.getBody(). in()') – njzk2

+0

cool, darò quella prova. Sto cercando di utilizzare un convertitore personalizzato come una delle API restituisce il campo JSON come String o List a seconda della dimensione. – 3xplore

risposta

4

vorrei fare qualcosa di simile:

public class StringList extends ArrayList<String> { 
    // Empty on purpose. The class is here only to be recognized by Gson 
} 

public class CitationMain { 
    @SerializedName("field_name_here") 
    StringList values; 

    // Your other fields 
} 

Poi durante la creazione del RestAdapter:

public class StringListDeserializer implements JsonDeserializer<StringList> { 

    @Override 
    public StringList deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext 
      context) throws JsonParseException { 
     StringList value = new StringList(); 
     if (json.isJsonArray()) { 
      for (JsonElement element : json.getAsJsonArray()) { 
       value.add(element.getAsString()); 
      } 
     } else { 
      value.add(json.getAsString()); 
     } 
     return value; 
    } 
} 

E poi:

Gson gson = new GsonBuilder() 
      .registerTypeAdapter(StringList.class, new StringListDeserializer()) 
      .create(); 

RestAdapter.Builder builder = new RestAdapter.Builder() 
      //... 
      .setConverter(new GsonConverter(gson)); 

Non è l'ideale, dal momento che l'oggetto è personalizzato, ma qualsiasi altra soluzione a cui posso pensare in questo momento è significativamente più complessa.

Il deserializzatore qui è registrato specificamente per i campi dichiarati come StringList e gestirà il caso di una singola stringa, nonché il caso di un array di stringhe. Qualsiasi altro tipo di campo utilizzerà il processo di deserializzazione predefinito.

+0

Proverò questo, il registerTypeAdapter applicherà il deserializzatore personalizzato solo per il tipo StringList? – 3xplore

+0

sì, che cosa è l'argomento 'StringList.class' in' registerTypeAdapter' – njzk2

+0

Grazie man, funziona – 3xplore