让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
对象,那里foo
是null
和bar
是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不提供用于任何形式的“严格”反序列化的机制,在该机制中,@Required
POJO中的字段将具有诸如注释的含义。
在您的情况下…我只是将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