GSON忽略错误类型的元素

Arn*_*nen 16 java android json gson retrofit

我正在使用Retrofit(与OkHttp和GSON结合使用)与在线Web服务进行通信.webservice有一个默认的包装器,它的响应类似于:

{  
  "resultCode":"OK",
  "resultObj":"Can be a string or JSON object / array",
  "error":"",
  "message":""
}
Run Code Online (Sandbox Code Playgroud)

在这个例子resultCode中将是OKNO.此外error,message只有在处理请求时发生错误时才有任何内容.最后,但并非最不重要的是,resultObj将包含调用的实际结果(在示例中是一个字符串,但有些调用返回JSON数组或JSON对象).

为了处理这个元数据,我创建了一个泛型类,如下所示:

public class ApiResult<T> {

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

    // + some getters, setters etcetera
}
Run Code Online (Sandbox Code Playgroud)

我还创建了表示有时给出的响应的类,resultObj并且我已经定义了一个与Retrofit一起使用的接口,看起来有点像这样:

public interface SomeWebService {

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

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

}
Run Code Online (Sandbox Code Playgroud)

只要请求有效,这一切都可以.但是当服务器端发生错误时,它仍将返回resultObj带有String类型的错误.这会导致someCallThatReturnsAnObjectRetrofit RestAdapter/GSON库内部崩溃,并显示如下消息:

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

预期BEGIN_OBJECT但是STRING在第1行第110列路径$ .resultObj

现在,最后,我的问题是:

  1. 是否有(简单)方法告诉GSON如果属性与预期类型不匹配,它应该忽略(也就是"无效")属性?
  2. 我可以告诉GSON将空字符串视为空吗?

Hei*_*ala 20

像这样定义你的模型:

public class ApiResult {

    private String error;
    private String message;
    private String resultCode;
    private MyResultObject resultObj;
}
Run Code Online (Sandbox Code Playgroud)

然后,为MyResultObject创建一个TypeAdapterFactory:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,为Gson注册MyResultObjectAdapterFactory:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new MyResultObjectAdapterFactory())
    .create();
Run Code Online (Sandbox Code Playgroud)

现在,当使用该Gson对象反序列化ApiResult json时,如果resultObj字符串,则将其设置为null.

我希望这能解决你的问题=)


RWI*_*WIL 7

我遇到了类似的问题,最后提出了以下解决方案:

而不是尝试将元素解析为Stringor Array,尝试将数据存储到简单的java.lang.Object中

这可以防止解析崩溃或抛出异常.

例如.使用GSON注释,模型的属性将如下所示:

@SerializedName("resultObj")
@Expose
private java.lang.Object resultObj;
Run Code Online (Sandbox Code Playgroud)

接下来,在运行时访问数据时,您可以检查您的resultObj属性是否是实例String.

if(apiResultObject instanceof String ){
    //Cast to string and do stuff

} else{
    //Cast to array and do stuff

}
Run Code Online (Sandbox Code Playgroud)

原帖:https://stackoverflow.com/a/34178082/3708094