gsonconverterfactory ejemplo android json gson retrofit

android - ejemplo - ¿Cómo manejar Dynamic JSON en Retrofit?



retrofit gson converter (8)

Estoy utilizando la actualización eficiente de la biblioteca de red, pero no pude manejar Dynamic JSON que contiene el prefijo simple responseMessage que cambia al object aleatoriamente, el mismo prefijo ( responseMessage ) cambia a String en algunos casos (dinámicamente).

Formato Json Objeto de responseMessage:

{ "applicationType":"1", "responseMessage":{ "surname":"Jhon", "forename":" taylor", "dob":"17081990", "refNo":"3394909238490F", "result":"Received" } }

El formato responseMessage Json cambia dinámicamente a tipo string:

{ "applicationType":"4", "responseMessage":"Success" }

El problema para mí es que, dado que la actualización tiene un análisis JSON integrado, ¡tenemos que asignar un solo POJO por solicitud! pero la REST-API desafortunadamente está construida con respuestas JSON dinámicas, el prefijo cambiará a cadena para objetar aleatoriamente en los métodos de éxito (...) y falla (...) .

void doTrackRef(Map<String, String> paramsref2) { RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint("http://192.168.100.44/RestDemo").build(); TrackerRefRequest userref = restAdapter.create(TrackerRefRequest.class); userref.login(paramsref2, new Callback<TrackerRefResponse>() { @Override public void success( TrackerRefResponse trackdetailresponse, Response response) { Toast.makeText(TrackerActivity.this, "Success", Toast.LENGTH_SHORT).show(); } @Override public void failure(RetrofitError retrofitError) { Toast.makeText(TrackerActivity.this, "No internet", Toast.LENGTH_SHORT).show(); } }); }

Pojo:

public class TrackerRefResponse { private String applicationType; private String responseMessage; //String type //private ResponseMessage responseMessage; //Object of type ResponseMessage //Setters and Getters }

En el código anterior, POJO TrackerRefResponse.java, prefijo responseMessage se establece en cadena u objeto de tipo responseMessage, por lo que podemos crear el POJO con la variable ref con el mismo nombre (java basics :)), así que estoy buscando la misma solución para JSON dinámico en Retrofit . Sé que este es un trabajo muy fácil en clientes HTTP normales con tareas asíncronas, ¡pero no es la mejor práctica en el análisis REST-Api JSON ! mirando el rendimiento Benchmarks siempre Volley o Retrofit es la mejor opción, ¡pero no pude manejar el JSON dinámico!

Posible solución que yo sé

  1. Use la antigua tarea asyc con el análisis del cliente http. :(

  2. Intenta convencer al desarrollador de back-end de RESTapi.

  3. Crear cliente de modificación personalizado :)



Cualquiera de sus posibles soluciones funcionará. Lo que también puede hacer es enviar el tipo de retorno de la interfaz de la API Retrofit a la respuesta. Con esa respuesta obtienes un cuerpo Inputstream que puedes convertir a un Objeto JSON y leer como mejor te parezca.

Mira: http://square.github.io/retrofit/#api-declaration - en RESPONSE OBJECT TYPE

Actualizado

Retrofit 2 ya salió y con él algunos cambios en la documentación y la biblioteca.

Mire http://square.github.io/retrofit/#restadapter-configuration hay un objeto cuerpo de solicitud y respuesta que se puede usar.


La respuesta aceptada me pareció demasiado complicada, la resuelvo de esta manera:

Call<ResponseBody> call = client.request(params); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Response<ResponseBody> response) { if (response.isSuccess()) { Gson gson = new Gson(); ResponseBody repsonseBody = response.body().string(); if (isEmail) { EmailReport reports = gson.fromJson(responseBody, EmailReport.class); } else{ PhoneReport reports = gson.fromJson(repsonseBody, PhoneReport.class); } } } @Override public void onFailure(Throwable t) { Log.e(LOG_TAG, "message =" + t.getMessage()); } });

Esto es solo un ejemplo en un intento de mostrarle cómo puede usar un modelo diferente.

La variable isEmail es solo un booleano para que su condición use el modelo apropiado.


RestClient.java

import retrofit.client.Response; public interface RestClient { @GET("/api/foo") Response getYourJson(); }

YourClass.java

RestClient restClient; // create your restClient Response response = restClient.getYourJson(); Gson gson = new Gson(); String json = response.getBody().toString(); if (checkResponseMessage(json)) { Pojo1 pojo1 = gson.fromJson(json, Pojo1.class); } else { Pojo2 pojo2 = gson.fromJson(json, Pojo2.class); }

Debe implementar el método "checkResponseMessage".


Sé que llegué muy tarde a la fiesta. Tuve un problema similar y lo resolví así:

public class TrackerRefResponse { private String applicationType; // Changed to Object. Works fine with String and array responses. private Object responseMessage; }

Literalmente cambié para escribir a Object. Elegí este enfoque porque solo un campo de la respuesta era dinámico (para mí, mi respuesta era mucho más complicada), por lo que usar un convertidor me habría dificultado la vida. Usó Gson para trabajar con el objeto desde allí, dependiendo de si era un valor String o Array.

Espero que esto ayude a alguien a buscar una respuesta simple :).


Si no fuera posible cambiar la API backend, consideraría las siguientes variantes (si Gson se usa para convertir JSON).

  1. Podemos usar adaptadores de tipo Gson para crear un adaptador personalizado para el tipo de ResponseMessage que dinámicamente decide cómo analizar el inoming JSON (usando algo como if (reader.peek() == JsonToken.STRING) ).

  2. Ponga una metainformación que describa el tipo de respuesta en un encabezado HTTP y utilícela para determinar qué tipo de información se debe suministrar a la instancia de Gson.


Tarde a la fiesta, pero puedes usar un convertidor.

RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://graph.facebook.com") .setConverter(new DynamicJsonConverter()) // set your static class as converter here .build(); api = restAdapter.create(FacebookApi.class);

Luego usas una clase estática que implementa Convertidor de actualización:

static class DynamicJsonConverter 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) { // not required 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(); } }

He escrito este convertidor de muestra para que devuelva la respuesta Json como String, Object, JsonObject o Map <String, Object>. Obviamente, no todos los tipos de devolución funcionarán para todos los Json, y hay margen de mejora. Pero demuestra cómo usar un convertidor para convertir casi cualquier respuesta a Json dinámico.


Pruebe la deserialización personalizada usando gson-converter como se gson-converter continuación (respuesta actualizada para Retrofit 2.0)

Crea tres modelos como se muestra a continuación

ResponseWrapper

public class ResponseWrapper { @SerializedName("applicationType") @Expose private String applicationType; @SerializedName("responseMessage") @Expose private Object responseMessage; public String getApplicationType() { return applicationType; } public void setApplicationType(String applicationType) { this.applicationType = applicationType; } public Object getResponseMessage() { return responseMessage; } public void setResponseMessage(Object responseMessage) { this.responseMessage = responseMessage; } }

ResponseMessage

public class ResponseMessage extends ResponseWrapper { @SerializedName("surname") @Expose private String surname; @SerializedName("forename") @Expose private String forename; @SerializedName("dob") @Expose private String dob; @SerializedName("refNo") @Expose private String refNo; @SerializedName("result") @Expose private String result; public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } public String getForename() { return forename; } public void setForename(String forename) { this.forename = forename; } public String getDob() { return dob; } public void setDob(String dob) { this.dob = dob; } public String getRefNo() { return refNo; } public void setRefNo(String refNo) { this.refNo = refNo; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } }

ResponseString

public class ResponseString extends ResponseWrapper { }

UserResponseDeserializer (deserializador personalizado)

public class UserResponseDeserializer implements JsonDeserializer<ResponseWrapper> { @Override public ResponseWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (((JsonObject) json).get("responseMessage") instanceof JsonObject){ return new Gson().fromJson(json, ResponseMessage.class); } else { return new Gson().fromJson(json, ResponseString.class); } } }

Implementación de Retrofit 2.0

Gson userDeserializer = new GsonBuilder().setLenient().registerTypeAdapter(ResponseWrapper.class, new UserResponseDeserializer()).create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("base_url") .addConverterFactory(GsonConverterFactory.create(userDeserializer)) .build(); UserService request = retrofit.create(UserService.class); Call<ResponseWrapper> call1=request.listAllUsers(); call1.enqueue(new Callback<ResponseWrapper>() { @Override public void onResponse(Call<ResponseWrapper> call, Response<ResponseWrapper> response) { ResponseWrapper responseWrapper=response.body(); Log.i("DYNAMIC RESPONSE", String.valueOf(response.body().getResponseMessage())); } @Override public void onFailure(Call<ResponseWrapper> call, Throwable t) { } });

Bibliotecas utilizadas

compile ''com.squareup.retrofit2: retrofit: 2.3.0''

compile ''com.squareup.retrofit2: converter-gson: 2.3.0''

***** Respuesta anterior (la respuesta anterior es más recomendada) *****

Cambia tu pojo como este

public class TrackerRefResponse { private String applicationType; private Object responseMessage; public Object getResponseMessage() { return responseMessage; } public void setResponseMessage(Object responseMessage) { this.responseMessage = responseMessage; } }

y cambiar la respuesta de on-retrofit como esta

@Override public void onResponse(Response<TrackerRefResponse > response) { if (response.isSuccess()) { if (response.getResponseMessage() instanceof String) { handleStringResponse(); } else { handleObjectResponse(); } } }

Consulte esta publicación en el blog para obtener más detalles sobre el análisis dinámico json