MalformedJsonException with Retrofit API?
Solution 1
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true)
is usually thrown when there is some character(s) that malforms the JSON. Exception message itself suggest to make the deserialization more tolerant.
But I suggest you to fix your JSON and trim it from unwanted characters.
You should extend GsonConverter
and override fromBody()
to make Gson
read from the tolerant JsonReader
. Then just set it to your RestAdapter
. This will attempt to use tolerant JsonReader
to deserialize and then close it, if not exception is thrown.
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();
}
}
}
}
Solution 2
Seems its changed slightly with Retrofit 2.0
Here's how I did it:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://whatever.com")
.addConverterFactory(LenientGsonConverterFactory.create(gson))
.build();
A new lenient gson factory:
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);
}
}
Lenient parsing of responses:
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();
}
}
}
Lenient creation of requests:
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());
}
}
I just copied the Retrofit source code and added a line to the request and the response converters jsonWriter.setLenient(true);
Or even easier:
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://whatever.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Solution 3
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();
}
}
Comments
-
FernandoPaiva about 3 years
I need send a json to my webservice, json is:
{ "Sala": { "usuario": "%@", "adversario": "%@", "atualizacao": "%@", "device": "%@", "device_tipo": "ios" } }
. I'm trying do it using Retrofit API 1.8. When I try send the post throws an exception.
Exception:
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $
I'm trying this
public class ChatObject { private String usuario; private String adversario; private String atualizacao; private String email; private String device; private String device_tipo;
Retrofit Interface
@POST("/WsChat/interacao.json") public void onReceiveMessage(@Body ChatObject obj, Callback<JsonElement> response);
Implements
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()); } }); }
-
Girish Patel about 9 yearsNikola,,,How to call this function means,,,, .setConverter(new LenientGsonConverter(gson))
-
Nikola Despotoski about 9 yearsYou call this when you create your
RestAdapter
. -
Girish Patel about 9 yearsGson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .registerTypeAdapter(Date.class, new DateTypeAdapter()) .create(); RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(urlString) .setConverter(new LenientGsonConverter(gson)) .build(); This is not working
-
Girish Patel about 9 yearsYes...But i am not able to getting response
-
Nikola Despotoski about 9 yearsThis does not make GSON lient.
-
ugali soft almost 8 yearsi got this error can not resolve setLenient(), in 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
-
Blundell almost 8 years@ZachariaMwalwama latest version is
2.0.2
search.maven.org/#search%7Cga%7C1%7Cconverter-gson -
Tot Zam about 7 yearsCan you add some explanation to this answer? How does this code solve the problem? What is it changing?
-
Mehul Tank over 5 yearsmy app is not compile even i am getting same isuue