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
153 views
in Technique[技术] by (71.8m points)

java - GSON ignore elements with wrong type

I'm using Retrofit (in combination with OkHttp and GSON) to communicate with an online webservice. The webservice has a default wrapper around all it's responses, similar to:

{  
  "resultCode":"OK",
  "resultObj":"Can be a string or JSON object / array",
  "error":"",
  "message":""
}

In this example resultCode will either be OK or NO. Furthermore error and message only have any contents when an error has occured while processing the request. And last, but not least, resultObj will contain the actual result from the call (which is a string in the example, but some calls return a JSON array or a JSON object).

To process this meta data, I created a generic class, like this one:

public class ApiResult<T> {

    private String error;
    private String message;
    private String resultCode;
    private T resultObj;

    // + some getters, setters etcetera
}

I've also created classes that represent the responses sometimes given in resultObj and I've defined an interface for use with Retrofit, that looks a bit like this:

public interface SomeWebService {

    @GET("/method/string")
    ApiResult<String> someCallThatReturnsAString();

    @GET("/method/pojo")
    ApiResult<SomeMappedResult> someCallThatReturnsAnObject();

}

As long as the request is valid this all works fine. But when an error occurs on the server side, it will still return a resultObj with a String-type. This causes someCallThatReturnsAnObject to crash inside the Retrofit RestAdapter / GSON library, with a message like this:

retrofit.RetrofitError: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException:

Expected BEGIN_OBJECT but was STRING at line 1 column 110 path $.resultObj

Now, finally, my questions are:

  1. Is there an (easy) way to tell GSON that it should just ignore (aka "nullify") a property if it does not match the expected type?
  2. Can I tell GSON to treat empty strings as null?
See Question&Answers more detail:os

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

1 Answer

0 votes
by (71.8m points)

Define your model like this:

public class ApiResult {

    private String error;
    private String message;
    private String resultCode;
    private MyResultObject resultObj;
}

Then, create a TypeAdapterFactory for MyResultObject:

public class MyResultObjectAdapterFactory implements TypeAdapterFactory {

    @Override
    @SuppressWarnings("unchecked")
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (type.getRawType()!= MyResultObject.class) return null;

        TypeAdapter<MyResultObject> defaultAdapter = (TypeAdapter<MyResultObject>) gson.getDelegateAdapter(this, type);
        return (TypeAdapter<T>) new MyResultObjectAdapter(defaultAdapter);
    }

    public class MyResultObjectAdapter extends TypeAdapter<MyResultObject> {

        protected TypeAdapter<MyResultObject> defaultAdapter;


        public MyResultObjectAdapter(TypeAdapter<MyResultObject> defaultAdapter) {
            this.defaultAdapter = defaultAdapter;
        }

        @Override
        public void write(JsonWriter out, MyResultObject value) throws IOException {
            defaultAdapter.write(out, value);
        }

        @Override
        public MyResultObject read(JsonReader in) throws IOException {
            /* 
            This is the critical part. So if the value is a string,
            Skip it (no exception) and return null.
            */
            if (in.peek() == JsonToken.STRING) {
                in.skipValue();
                return null;
            }
            return defaultAdapter.read(in);
        }
    }
}

Finally, register MyResultObjectAdapterFactory for Gson:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new MyResultObjectAdapterFactory())
    .create();

Now, when deserializing an ApiResult json with that Gson object, resultObj will be set null if it is a string.

I Hope this solves your problem =)


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

...