MalformedJsonException con API de Retrofit?
Necesito enviar un json a mi webservice, json es:
{ "Sala": { "usuario": "%@", "adversario": "%@", "atualizacao": "%@", "device": "%@", "device_tipo": "ios" } }
. Estoy tratando de hacerlo utilizando Retrofit API 1.8. Cuando intento enviar el poste lanza una excepción.
- RxJava alternativa para el operador map () para guardar los elementos emitidos
- ¿Cuál es el razonamiento para separar los métodos RestAdapter.build () y .create () al usar Dagger?
- Cómo realizar una prueba de unidad
- Retrofit: ¿Cómo enviar una solicitud POST con campos constantes?
- Obtención de información de encabezado con RXJava y Retrofit
Excepción:
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $
Estoy intentando esto
public class ChatObject { private String usuario; private String adversario; private String atualizacao; private String email; private String device; private String device_tipo;
Interfaz de Retrofit
@POST("/WsChat/interacao.json") public void onReceiveMessage(@Body ChatObject obj, Callback<JsonElement> response);
Implementos
public void receiveMessage(){ ///{\"Sala\":{\"usuario\":\"%@\",\"adversario\":\"%@\",\"atualizacao\":\"%@\",\"device\":\"%@\",\"device_tipo\":\"ios\"}} ChatObject chatObject = new ChatObject(BatalhaConfigs.USUARIO_EMAIL, BatalhaConfigs.ADVERSARIO_EMAIL, new Date().toString(), BatalhaConfigs.USUARIO_EMAIL, AndroidReturnId.getAndroidId(), "android"); RestAdapter adapter = new RestAdapter.Builder() .setLogLevel(RestAdapter.LogLevel.FULL) .setRequestInterceptor(new CustomRequestInterceptor()) .setEndpoint(END_POINT) .build(); ChatListener listener = adapter.create(ChatListener.class); listener.onReceiveMessage(chatObject, new Callback<JsonElement>() { @Override public void success(JsonElement jsonElement, retrofit.client.Response response) { Log.i("JSON ELEMENT->", jsonElement.toString()); } @Override public void failure(RetrofitError error) { Log.i("FALHOU->", error.getLocalizedMessage()); } }); }
- Android rxJava Manejo de errores con retroadaptación
- Agregar cabecera a todas las solicitudes con Retrofit 2
- Retrofit y SimpleXML para el elemento raíz desconocido?
- Cómo enviar datos JSON como Cuerpo usando Retrofit android
- RxJava y Retrofit2: NetworkOnMainThreadException
- Android: subir imagen a Twitter utilizando REST API y Fabric, error de tubería roto
- ¿Cómo pasar el enum personalizado en @Query a través de Retrofit?
- Retrofit no desencadena onError cuando se utiliza ErrorHandler personalizado
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true)
se suele lanzar cuando hay algunos caracteres que malforman el JSON. El propio mensaje de excepción sugiere que la deserialización sea más tolerante.
Pero le sugiero que arreglar su JSON y recortarlo de caracteres no deseados.
Debe extender GsonConverter
y anular fromBody()
para que Gson
lea desde el JsonReader
tolerante. A continuación, sólo tiene que establecerlo en su RestAdapter
. Esto intentará usar JsonReader
tolerante para deserializar y luego cerrarlo, si no se produce una excepción.
public class LenientGsonConverter extends GsonConverter { private Gson mGson; public LenientGsonConverter(Gson gson) { super(gson); mGson = gson; } public LenientGsonConverter(Gson gson, String charset) { super(gson, charset); mGson = gson; } @Override public Object fromBody(TypedInput body, Type type) throws ConversionException { boolean willCloseStream = false; // try to close the stream, if there is no exception thrown using tolerant JsonReader try { JsonReader jsonReader = new JsonReader(new InputStreamReader(body.in())); jsonReader.setLenient(true); Object o = mGson.fromJson(jsonReader,type); willCloseStream = true; return o; } catch (IOException e) { e.printStackTrace(); }finally { if(willCloseStream) { closeStream(body); } } return super.fromBody(body, type); } private void closeStream(TypedInput body){ try { InputStream in = body.in(); in.close(); } catch (IOException e) { e.printStackTrace(); } } }
}
Parece que ha cambiado ligeramente con Retrofit 2.0
He aquí cómo lo hice:
Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://whatever.com") .addConverterFactory(LenientGsonConverterFactory.create(gson)) .build();
Una nueva fábrica leniente de gson:
public final class LenientGsonConverterFactory extends Converter.Factory { /** * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and * decoding from JSON (when no charset is specified by a header) will use UTF-8. */ public static LenientGsonConverterFactory create() { return create(new Gson()); } /** * Create an instance using {@code gson} for conversion. Encoding to JSON and * decoding from JSON (when no charset is specified by a header) will use UTF-8. */ public static LenientGsonConverterFactory create(Gson gson) { return new LenientGsonConverterFactory(gson); } private final Gson gson; private LenientGsonConverterFactory(Gson gson) { if (gson == null) throw new NullPointerException("gson == null"); this.gson = gson; } @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new LenientGsonResponseBodyConverter<>(gson, adapter); } @Override public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type)); return new LenientGsonRequestBodyConverter<>(gson, adapter); } }
Análisis sin sentido de las respuestas:
private class LenientGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> { private final Gson gson; private final TypeAdapter<T> adapter; LenientGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) { this.gson = gson; this.adapter = adapter; } @Override public T convert(ResponseBody value) throws IOException { JsonReader jsonReader = gson.newJsonReader(value.charStream()); jsonReader.setLenient(true); try { return adapter.read(jsonReader); } finally { value.close(); } } }
Leniente creación de solicitudes:
private class LenientGsonRequestBodyConverter<T> implements Converter<T, RequestBody> { private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8"); private static final Charset UTF_8 = Charset.forName("UTF-8"); private final Gson gson; private final TypeAdapter<T> adapter; LenientGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) { this.gson = gson; this.adapter = adapter; } @Override public RequestBody convert(T value) throws IOException { Buffer buffer = new Buffer(); Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8); JsonWriter jsonWriter = gson.newJsonWriter(writer); jsonWriter.setLenient(true); adapter.write(jsonWriter, value); jsonWriter.close(); return RequestBody.create(MEDIA_TYPE, buffer.readByteString()); } }
Acabo de copiar el código fuente Retrofit y agregó una línea a la solicitud y los convertidores de respuesta jsonWriter.setLenient(true);
O incluso más fácil:
Gson gson = new GsonBuilder() .setLenient() .create(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://whatever.com") .addConverterFactory(GsonConverterFactory.create(gson)) .build();
RestAdapter adapterRfqPost = new RestAdapter.Builder() .setEndpoint(Constants.ENDPOINT) `enter code here`.setConverter(new ConstantsMethods.StringConverter()) .build();
public static class StringConverter implements Converter { @Override public Object fromBody(TypedInput typedInput, Type type) throws ConversionException { String text = null; try { text = fromStream(typedInput.in()); } catch (IOException ignored) {/*NOP*/ } return text; } @Override public TypedOutput toBody(Object o) { return null; } public static String fromStream(InputStream in) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder out = new StringBuilder(); String newLine = System.getProperty("line.separator"); String line; while ((line = reader.readLine()) != null) { out.append(line); out.append(newLine); } return out.toString(); } }
Debe ayudar a este código:
RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("http://192.168.10.115/test.php") .setConverter(new GsonConverter(new Gson())) .build();
Ponga el archivo jar:
[gson-2.2.2.jar][1]
- Diseñar un diseño como debajo de la imagen con botones de imagen en android
- Fuente para CollapsingToolbarLayout