我需要发送一个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());
}
});
}
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true)
。异常消息本身建议使反序列化更加宽容。
但我建议您修复 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();
}
}
}
}
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();
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();
}
}
我花了一天的时间才遇到这个错误,并按照本页的“正确答案”进行操作,但毕竟我找到了我的问题,那就是从“int”数组(也是我的模型类)分配响应是 int) 到 textView,这当然需要我将其转换为字符串 int 值。在我的例子中,我什至根本不需要做@Nikola Despotoski 的解决方案。
下面的代码对我有用
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”
如果您使用 PHP 作为 API,请检查它是否回显 只能使用 JSON 编码的对象,否则会抛出此类异常
我在 Kotlin 项目中遇到了同样的 MalformedJsonException 问题,发现这里提到的解决方案都不适合我。
通过将 Kotlin 的序列化功能引入到我的项目中,该问题得到了解决。这就是我所做的:
1。添加
@Serializable
注释:
对于
Kotlin
:
@Serializable
data class MyDataClass(...)
对于
Java
import java.io.Serializable;
public class MyDataClass implements Serializable {}
2。更新
Kotlin
的依赖关系:
// build.gradle (Module)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0")
// build.gradle (Project)
kotlin("jvm") version "1.9.22" // update version
kotlin("plugin.serialization") version "1.9.22" // update version
如果您面临类似的问题并且尚未探索
Kotlin
或 Java
序列化功能,我建议您尝试一下。
你应该帮助这个代码:
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]