Convertidor personalizado para reequipamiento
Estoy intentando utilizar un convertidor personalizado para Retrofit
RestAdapter.Builder builder = new RestAdapter.Builder() .setEndpoint(BuildConfig.BASE_SERVER_ENDPOINT) .setClient(new OkClient(client)).setConverter(new CitationResponseConverter()) .setLogLevel(RestAdapter.LogLevel.FULL);
A continuación es mi conversor personalizado
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(); } }
Estoy teniendo el siguiente error
retrofit.RetrofitError: method POST must have a request body.
Mientras trataba de hacer esta api llamada
@POST("/service/citations") Observable<CitationMain> getCitations(@Body CitationRequestBody body);
Supongo que el convertidor está anulando la solicitud de la llamada api, ¿cómo puedo evitar eso y pasar el cuerpo de solicitud definido en el servicio de adaptación.
Respuesta:
{ "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", } ] }
Yo haría algo así:
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 }
A continuación, al crear el 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; } }
Y entonces:
Gson gson = new GsonBuilder() .registerTypeAdapter(StringList.class, new StringListDeserializer()) .create(); RestAdapter.Builder builder = new RestAdapter.Builder() //... .setConverter(new GsonConverter(gson));
No es ideal, ya que el objeto es personalizado, pero cualquier otra solución que pueda pensar ahora es mucho más compleja.
El deserializador aquí está registrado específicamente para los campos declarados como StringList
, y manejará el caso de una sola cadena, así como el caso de una matriz de cadena. Cualquier otro tipo de campo utilizará el proceso predeterminado de deserialización.