让Gson在错误的类型上抛出异常

我在项目中使用Gson将JSON字符串反序列化为Java对象。如果我提出请求,我希望服务器发出明确定义的响应。服务器将返回我期望的定义明确的响应,或者将返回一个(也定义为)错误对象。

讲清楚一点:假设我有一个简单的对象,像这样:

class Dummy{

private String foo;

private int bar;

}

和这样的错误对象:

class ErrorHolder{

private RequestError error;

}

class RequestError{

private String publicMsg;

private String msg;

}

如果我收到类似的服务器响应

{"foo":"Hello World", "bar":3 }

一切都按预期进行。

但是如果回应是这样的

{"error":{"publicMsg":"Something bad happened", msg:"you forgot requesting

some parameter"}}

我会得到一个Dummy对象,那里foonullbar是0!Gson文档(来自Json)明确指出:

抛出JsonSyntaxException-如果json不是classOfT类型的对象的有效表示形式

因此,如果我尝试像这样解析第二个响应,我希望得到一个JsonSyntaxException:

Dummy dummy = Gson.fromJson(secondResponse, Dummy.class);

因为Json并不代表虚拟对象,而是代表ErrorHolder对象。

所以我的问题是:有没有办法让Gson以某种方式检测到错误的类型并引发异常?

回答:

不幸的是,那里的文档有些误导。

仅当您的类的字段类型与JSON中的字段不匹配时,它才会引发异常,即使这样做,它也会做出一些疯狂的尝试来对其进行修复(例如int,将JSON中的转换为String类中的)

)。如果您Date在POJO中有类似字段的内容,并且int在JSON中遇到了,则会将其抛出。静默忽略JSON中存在但POJO中不存在的字段,JSON中缺失但POJO中存在的字段设置为null

当前,GSON不提供用于任何形式的“严格”反序列化的机制,在该机制中,@RequiredPOJO中的字段将具有诸如注释的含义。

在您的情况下…我只是将POJO扩展为包括一个内部错误对象…类似于:

class Dummy {

private String foo;

private int bar;

private Error error;

private class Error {

String publicMsg;

String msg;

}

public boolean isError() {

return error != null;

}

// setters and getters for your data, the error msg, etc.

}

您的另一个选择是编写一个自定义反序列化器,如果JSON是错误,则抛出该异常,例如:

class MyDeserializer implements JsonDeserializer<Dummy>

{

@Override

public Dummy deserialize(JsonElement json, Type typeOfT,

JsonDeserializationContext context)

throws JsonParseException

{

JsonObject jsonObject = (JsonObject) json;

if (jsonObject.get("error") != null)

{

throw new JsonParseException("Error!");

}

return new Gson().fromJson(json, Dummy.class);

}

}

有人最近对此进行了投票,并重新阅读了它,我认为“嗯,你知道的,你可以自己做,这也许很方便”。

这是一个可重复使用的反序列化器和注释,它将完全执行OP想要的操作。局限性在于,如果POJO仍然需要自定义反序列化器,则您必须走得更远,或者Gson在构造函数中传入一个对象以反序列化为对象本身,或者将注解签出到一个单独的方法中并使用它在您的解串器中。您还可以通过创建自己的异常并将其传递给来改进异常处理,JsonParseException以便可以getCause()在调用方中对其进行检测。

综上所述,在大多数情况下,这将起作用:

public class App

{

public static void main(String[] args)

{

Gson gson =

new GsonBuilder()

.registerTypeAdapter(TestAnnotationBean.class, new AnnotatedDeserializer<TestAnnotationBean>())

.create();

String json = "{\"foo\":\"This is foo\",\"bar\":\"this is bar\"}";

TestAnnotationBean tab = gson.fromJson(json, TestAnnotationBean.class);

System.out.println(tab.foo);

System.out.println(tab.bar);

json = "{\"foo\":\"This is foo\"}";

tab = gson.fromJson(json, TestAnnotationBean.class);

System.out.println(tab.foo);

System.out.println(tab.bar);

json = "{\"bar\":\"This is bar\"}";

tab = gson.fromJson(json, TestAnnotationBean.class);

System.out.println(tab.foo);

System.out.println(tab.bar);

}

}

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)

@interface JsonRequired

{

}

class TestAnnotationBean

{

@JsonRequired public String foo;

public String bar;

}

class AnnotatedDeserializer<T> implements JsonDeserializer<T>

{

public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException

{

T pojo = new Gson().fromJson(je, type);

Field[] fields = pojo.getClass().getDeclaredFields();

for (Field f : fields)

{

if (f.getAnnotation(JsonRequired.class) != null)

{

try

{

f.setAccessible(true);

if (f.get(pojo) == null)

{

throw new JsonParseException("Missing field in JSON: " + f.getName());

}

}

catch (IllegalArgumentException ex)

{

Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE, null, ex);

}

catch (IllegalAccessException ex)

{

Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE, null, ex);

}

}

}

return pojo;

}

}

输出:

这是foo

这是酒吧

这是foo

空值

线程“ main” com.google.gson.JsonParseException中的异常:JSON中的字段丢失:foo

以上是 让Gson在错误的类型上抛出异常 的全部内容, 来源链接: utcz.com/qa/414006.html

回到顶部