Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
423 views
in Technique[技术] by (71.8m points)

android - Retrofit - removing some invalid characters from response body before parsing it as json

I have an external web service that in the response body returns json but nested in parentheses, like this:

({"door_x":"103994.001461","door_y":"98780.7862376", "distance":"53.3"})

Using this code:

class AddressInfo {
    String door_x;
    String door_y;
}

interface AddressWebService {
    @GET("/reversegeocoding")
    AddressInfo reverseGeocoding(@Query("x") double x, @Query("y") double y);
}

It obviously fails. This is the stacktrace:

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)

What is the best way to remove the parentheses before parsing the json?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You can clean painlessly the response in your GsonConverter before Gson deserialized the body into type object.

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

                }
        };

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

Here I subclassed GsonConverter to get access to the response before it is converted to object. JsonTypedOutput is used to preserve the mime type of the response after cleaning it from the junk chars.

Usage:

restAdapterBuilder.setConverter(new CleanGsonConverter(gson));

Blame it on your backend guys. :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...