pom*_*ber 6 android json jsonp gson retrofit
我有一个外部Web服务,在响应体中返回json但嵌套在括号中,如下所示:
({"door_x":"103994.001461","door_y":"98780.7862376", "distance":"53.3"})
Run Code Online (Sandbox Code Playgroud)
使用此代码:
class AddressInfo {
String door_x;
String door_y;
}
interface AddressWebService {
@GET("/reversegeocoding")
AddressInfo reverseGeocoding(@Query("x") double x, @Query("y") double y);
}
Run Code Online (Sandbox Code Playgroud)
它显然失败了.这是堆栈跟踪:
retrofit.RetrofitError: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:377)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
at com.something.$Proxy7.reverseGeocoding(Native Method)
at com.something.ReverseGeocodingService.getAddress(ReverseGeocodingService.java:24)
at com.something.LocationProvider$1.run(LocationProvider.java:77)
at java.lang.Thread.run(Thread.java:864)
Caused by: retrofit.converter.ConversionException: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1
at retrofit.converter.GsonConverter.fromBody(GsonConverter.java:67)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:362)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
at com.something.$Proxy7.reverseGeocoding(Native Method)
at com.something.ReverseGeocodingService.getAddress(ReverseGeocodingService.java:24)
at com.something.LocationProvider$1.run(LocationProvider.java:77)
at java.lang.Thread.run(Thread.java:864)
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176)
at com.google.gson.Gson.fromJson(Gson.java:803)
at com.google.gson.Gson.fromJson(Gson.java:768)
at retrofit.converter.GsonConverter.fromBody(GsonConverter.java:63)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:362)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
at com.something.$Proxy7.reverseGeocoding(Native Method)
at com.something.ReverseGeocodingService.getAddress(ReverseGeocodingService.java:24)
at com.something.LocationProvider$1.run(LocationProvider.java:77)
at java.lang.Thread.run(Thread.java:864)
Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1
at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:374)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:165)
at com.google.gson.Gson.fromJson(Gson.java:803)
at com.google.gson.Gson.fromJson(Gson.java:768)
at retrofit.converter.GsonConverter.fromBody(GsonConverter.java:63)
at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:362)
at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:240)
at com.something.$Proxy7.reverseGeocoding(Native Method)
at com.something.ReverseGeocodingService.getAddress(ReverseGeocodingService.java:24)
at com.something.LocationProvider$1.run(LocationProvider.java:77)
at java.lang.Thread.run(Thread.java:864)
Run Code Online (Sandbox Code Playgroud)
在解析json之前删除括号的最佳方法是什么?
Nik*_*ski 12
GsonConverter在Gson将主体反序列化为类型对象之前,您可以无痛地清除您的响应.
public class CleanGsonConverter extends GsonConverter{
public CleanGsonConverter(Gson gson) {
super(gson);
}
public CleanGsonConverter(Gson gson, String encoding) {
super(gson, encoding);
}
@Override
public Object fromBody(TypedInput body, Type type) throws ConversionException {
String dirty = toString(body);
String clean = dirty.replaceAll("(^\\(|\\)$)", "");
body = new JsonTypedInput(clean.getBytes(Charset.forName(HTTP.UTF_8)));
return super.fromBody(body, type);
}
private String toString(TypedInput body){
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(body.in()));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
};
Run Code Online (Sandbox Code Playgroud)
JsonTypedInput:
public class JsonTypedInput implements TypedInput{
private final byte[] mStringBytes;
JsonTypedInput(byte[] stringBytes) {
this.mStringBytes = stringBytes;
}
@Override
public String mimeType() {
return "application/json; charset=UTF-8";
}
@Override
public long length() {
return mStringBytes.length;
}
@Override
public InputStream in() throws IOException {
return new ByteArrayInputStream(mStringBytes);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我将子类GsonConverter转换为在转换为对象之前访问响应.JsonTypedOutput用于在从垃圾字符中清除响应后保留响应的mime类型.
用法:
restAdapterBuilder.setConverter(new CleanGsonConverter(gson));
归咎于你的后端人.:)
下面的代码与GsonConverter您可以Response在转换为其模型之前编辑之前的代码相同
编辑public T convert(ResponseBody value)以清理你的Response
/**
* Modified by TarekkMA on 8/2/2016.
*/
public class MyJsonConverter extends Converter.Factory {
public static MyJsonConverter create() {
return create(new Gson());
}
public static JsonHandler create(Gson gson) {
return new JsonHandler(gson);
}
private final Gson gson;
private JsonHandler(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 GsonResponseBodyConverter<>(gson, adapter);
}
@Override
public Converter<?, RequestBody> requestBodyConverter(Type type,
Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
return new GsonRequestBodyConverter<>(gson, adapter);
}
final class GsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
private final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
private final Charset UTF_8 = Charset.forName("UTF-8");
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonRequestBodyConverter(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);
adapter.write(jsonWriter, value);
jsonWriter.close();
return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
}
}
final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final Gson gson;
private final TypeAdapter<T> adapter;
GsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
this.gson = gson;
this.adapter = adapter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String dirty = value.string();
String clean = dirty.replace("<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
"<string xmlns=\"http://tempuri.org/\">","").replace("</string>","");
try {
return adapter.fromJson(clean);
} finally {
value.close();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)