wake-up-neo.com

MalformedJsonException mit Retrofit-API?

Ich muss einen Json an meinen Webservice schicken. Json ist: 

{
    "Sala": {
        "usuario": "%@",
        "adversario": "%@",
        "atualizacao": "%@",
        "device": "%@",
        "device_tipo": "ios"
    }
}

. Ich versuche es mit der Retrofit API 1.8 .. Wenn ich versuche, den Post zu senden, wird eine Ausnahme ausgelöst.

Ausnahme:

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 7 path $

Ich versuche das

public class ChatObject {
    private String usuario;
    private String adversario;
    private String atualizacao;
    private String email;
    private String device;
    private String device_tipo;

Retrofit-Schnittstelle

@POST("/WsChat/interacao.json")
    public void onReceiveMessage(@Body ChatObject obj,
                                 Callback<JsonElement> response);

Implementiert

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

        }
    });
}
16
FernandoPaiva

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) wird normalerweise ausgelöst, wenn es Zeichen gibt, die den JSON verfälschen. Ausnahmebotschaft selbst legt nahe, die Deserialisierung toleranter zu machen. 

Aber ich schlage vor, dass Sie Ihre JSON korrigieren und von unerwünschten Zeichen abschneiden.

Sie sollten GsonConverter erweitern und fromBody() überschreiben, damit Gson aus der toleranten JsonReader gelesen wird. Dann setzen Sie es einfach auf Ihre RestAdapter. Dadurch wird versucht, tolerante JsonReader zu deserialisieren und dann zu schließen, wenn keine Ausnahme ausgelöst wird. 

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

}

15

Mit Retrofit 2.0 scheint sich das etwas zu ändern

So habe ich es gemacht:

 Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://whatever.com")
        .addConverterFactory(LenientGsonConverterFactory.create(gson))
        .build();

Eine neue nachsichtige Gson-Fabrik:

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 Analyse der Antworten:

    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 Erstellung von Anfragen:

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

Ich habe gerade den Retrofit-Quellcode kopiert und der Anfrage und den Antwortkonvertern eine Zeile hinzugefügt. jsonWriter.setLenient(true);


Oder noch einfacher:

    Gson gson = new GsonBuilder()
        .setLenient()
        .create();

    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://whatever.com")
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build(); 
9
Blundell
 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();
        }
    }
1
amar mule

Der folgende Code hat für mich funktioniert

Gson gson = new GsonBuilder()
        .setLenient()
        .create();

final RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(endPoint)
        .setConverter(new GsonConverter(gson))
        .build();

Um ".setLenient ()" zu verwenden, müssen Sie die folgende Zeile in die gradle-Datei der App einfügen.

implementierung 'com.google.code.gson: gson: 2.7'

0
Avi

Ich kämpfte mich einen Tag lang darum, diesen Fehler zu bekommen und das zu tun, was die "richtige Antwort" dieser Seite sagte, aber schließlich fand ich mein Problem heraus, das war das Zuweisen der Antwort von einem Array, das "int" war (auch meine Modellklasse war int) zu einem textView, bei dem es natürlich erforderlich war, es in den int-Wert als String zu konvertieren. Ich habe nicht einmal die Lösung von @Nikola Despotoski in meinem Fall benötigt.

0
Hossein