我在项目中使用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
假设我有这样一个函数: 我想测试它是否使用Jest抛出一个(不仅仅是一个)。 然而,这项测试通过了。 如何检查Jest中异步抛出的错误类型?
我是jUnit和mockito的新手。对于虚空的嘲弄是如何发挥作用的,我完全感到困惑。在这里,如果名称是“hello”,则函数抛出一个异常。但当我测试它时,它并没有抛出异常... 测试 }
//为(int i=0; i创建具有100个存储空间的数组 //提示用户输入要查找的索引
问题内容: 我试图在Netbeans中重构一个大型程序,但我有点迷茫。我从来没有非常模块化,但是现在通过实际学习如何做到这一点来尝试纠正这种情况,并在将来纠正这种情况。不幸的是,我在将某些教程翻译成我的程序时遇到了麻烦。所以我希望这里有人可以帮忙。目前,我正在尝试分解一部分采用特定格式的文件并制成表格的代码。我知道我需要创建一个类并使用它来创建表对象,但是我不确定如何做。我有一个主文件,用于获取文
问题内容: 这是一些示例代码: 如果我运行该程序并将其设置为 like ,则一切正常。 另一方面,如果我回答,那不会嘲笑我的有趣笑话。相反,我得到这个(如预期的那样): 有没有一种方法可以使它忽略不是int的条目,或者用“有多少个入侵者”重新提示?我想知道这两种方法。 问题答案: 你可以使用的诸多一个是方法有预验证。 这可以防止从甚至被抛出,因为你总是确保它WILL你读它之前匹配。 java.ut
问题内容: 我正在使用Retrofit(与OkHttp和GSON结合使用)与在线Web服务进行通信。该Web服务的所有响应都有一个默认包装,类似于: 在此示例中,将为或。此外,仅在处理请求时发生错误时才包含任何内容。最后但并非最不重要的一点将包含调用的实际结果(示例中为字符串,但是某些调用返回JSON数组或JSON对象)。 为了处理此元数据,我创建了一个通用类,如下所示: 我还创建了代表有时给出的