【问题标题】:MalformedJsonException with Retrofit API?带有改造 API 的 MalformedJsonException?
【发布时间】:2015-02-13 15:01:12
【问题描述】:

我需要向我的网络服务发送一个 json,json 是:

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

。我正在尝试使用 Retrofit API 1.8 来做到这一点。 当我尝试发送帖子时会引发异常。

例外:

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

我正在尝试这个

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

改造界面

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

实现

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

        }
    });
}

【问题讨论】:

  • ChatObject 的 json 输出不会是 {"usuario":"%@","adversario":"%@","atualizacao":"%@","email":"%@","device":"%@","device_tipo":"%@"}

标签: android json gson retrofit


【解决方案1】:

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) 通常在某些字符导致 JSON 格式错误时抛出。异常消息本身建议使反序列化更加宽容。

但我建议你修复你的 JSON 并从不需要的字符中删除它。

您应该扩展GsonConverter 并覆盖fromBody() 以使Gson 从容错JsonReader 中读取。然后只需将其设置为您的RestAdapter。这将尝试使用宽容的JsonReader 反序列化然后关闭它,如果没有抛出异常。

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

}

【讨论】:

  • Nikola,,,如何调用这个函数的意思是,,,, .setConverter(new LenientGsonConverter(gson))
  • 您在创建 RestAdapter 时调用它。
  • Gson 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();这不起作用
  • 是的...但我无法得到回应
  • 我的应用程序没有编译,即使我得到相同的 isuue
【解决方案2】:

Retrofit 2.0 似乎略有变化

我是这样做的:

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

一个新的宽松的 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);
        }

    }

对响应的宽松解析:

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

请求创建宽松:

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

我刚刚复制了 Retrofit 源代码,并在请求和响应转换器 jsonWriter.setLenient(true); 中添加了一行代码


甚至更简单:

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

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

【讨论】:

【解决方案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();
        }
    }

【讨论】:

  • 您可以对此答案添加一些解释吗?这段代码如何解决问题?它有什么变化?
【解决方案4】:

我挣扎了一天得到这个错误并按照这个页面的“正确答案”所说的那样做,但毕竟我发现了我的问题,那就是从一个“int”数组(也是我的模型类是 int) 到 textView 当然需要我将它转换为字符串 int 值。就我而言,我什至根本不需要做@Nikola Despotoski 的解决方案。

【讨论】:

    【解决方案5】:

    以下代码对我有用

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

    若要使用“.setLenient()”,需要在应用程序的 gradle 文件中添加以下行。

    实现'com.google.code.gson:gson:2.7'

    【讨论】:

      【解决方案6】:

      如果您使用 PHP 作为 API,请检查它是否回显 只有 JSON 编码的对象,否则它会抛出这种类型的异常

      【讨论】:

        【解决方案7】:

        你应该帮助这个代码:

        RestAdapter restAdapter = new RestAdapter.Builder()
                         .setEndpoint("http://192.168.10.115/test.php")
                         .setConverter(new GsonConverter(new Gson()))
                         .build();
        

        放入jar文件:

        [gson-2.2.2.jar][1]
        

        【讨论】:

        • 这不会让 GSON 保持信任。
        猜你喜欢
        • 2017-12-10
        • 2015-06-16
        • 1970-01-01
        • 2020-12-24
        • 2018-02-09
        • 2016-04-06
        • 2020-03-06
        • 2018-02-27
        • 1970-01-01
        相关资源
        最近更新 更多