java - Gson 将失败的字段解析视为 null
问题描述
有没有办法配置 Gson 以便它将任何失败的字段解析视为 null 而不是抛出解析异常?理想情况下,我们可以捕获并记录异常——但即使某些字段(或子字段)未按预期解析,我们也希望该选项继续执行程序。
例子:
格式错误的 JSON:
{
"dog": []
}
与类:
class Farm {
public Dog dog;
}
class Dog {
public String name;
}
Gson gson = new Gson();
Farm oldMcdonald = gson.fromJson(json, Farm.class); // should not throw exception
assertNull(oldMcdonald.dog); // should pass
解决方案
在 Gson 中,它可以很容易地实现。尽管我猜以下解决方案似乎在任何情况下都不起作用(例如,原语),但如有必要,可以对其进行增强。
final class JsonFailSafeTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory instance = new JsonFailSafeTypeAdapterFactory();
private JsonFailSafeTypeAdapterFactory() {
}
static TypeAdapterFactory get() {
return instance;
}
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// We can support non-primitive types only
if ( typeToken.getRawType().isPrimitive() ) {
return null;
}
final TypeAdapter<T> delegateTypeAdapter = gson.getAdapter(typeToken);
return new JsonFailSafeTypeAdapter<>(delegateTypeAdapter);
}
private static final class JsonFailSafeTypeAdapter<T>
extends TypeAdapter<T> {
private final TypeAdapter<T> delegateTypeAdapter;
private JsonFailSafeTypeAdapter(final TypeAdapter<T> delegateTypeAdapter) {
this.delegateTypeAdapter = delegateTypeAdapter;
}
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegateTypeAdapter.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
try {
return delegateTypeAdapter.read(in);
} catch ( final MalformedJsonException | RuntimeException ignored ) {
// Once we get into unexpected JSON token, let's *always* consider a fallback to the default value
// Well, the default is always `null` anyway, but we'll do more work
return fallback(in);
}
}
private static <T> T fallback(final JsonReader in)
throws IOException {
final JsonToken jsonToken = in.peek();
switch ( jsonToken ) {
case BEGIN_ARRAY:
case BEGIN_OBJECT:
case NAME:
case STRING:
case NUMBER:
case BOOLEAN:
case NULL:
// Assume we're at the beginning of a complex JSON value or a JSON primitive
in.skipValue();
break;
case END_ARRAY:
// Not sure if we skipValue() can fast-forward this one
in.endArray();
break;
case END_OBJECT:
// The same
in.endObject();
break;
case END_DOCUMENT:
// do nothing
break;
default:
throw new AssertionError(jsonToken);
}
// Just return null (at least at the moment)
return null;
}
}
}
现在只需注册上述类型工厂来处理所有类型(如果我没记错的话,java.lang.Object 除外)。
private static final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(JsonFailSafeTypeAdapterFactory.get())
.create();
public static void main(final String... args)
throws IOException {
try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50002961.class, "farm.json") ) {
final Farm oldMcdonald = gson.fromJson(jsonReader, Farm.class);
if ( oldMcdonald.dog != null ) {
throw new AssertionError();
}
System.out.println(oldMcdonald);
}
}
示例输出:
q50002961.Farm@626b2d4a
如果不需要全局注册工厂,另一个选项也是指定目标字段。例如:
final class Farm {
@JsonAdapter(JsonFailSafeTypeAdapterFactory.class)
final Dog dog = null;
}
推荐阅读
- javascript - 如何在现有的 node.js express 设置中集成 rate-limiter-flexible?
- nix - 通过 Docker 构建时,如何缓存 nix 派生的依赖项?
- android - 为什么 Android Studio 抱怨 getApplicationContext()?
- javascript - 将回调函数结果附加到特定的 div/位置?
- python-3.x - 根据所需的季度将值替换为 nan
- excel - 无法创建输出每月出现次数的表
- javascript - TS/JS 混合和 Visual Studio 代码的错误导入错误
- c# - C# - 有条件地加载带有 switch 语句的特定页脚
- javascript - YouTube webhook 订阅请求返回“hub.mode 的值无效”?
- tensorflow - 可变通道数