Search code examples
androidjsongsonretrofit

MalformedJsonException with Retrofit API?


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());

        }
    });
}

Solution

  • 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();
            }
        }
    }
    

    }