假设您有一个语法有效 JSON 文档,您可以创建一个反序列化程序来忽略由于类型不匹配或类型转换导致的解析错误。该实现不需要处理反序列化本身,它可以从 Jackson API 委托给现有的反序列化器。这种方法首先在 answer 中进行了描述。
对于错误报告,您可以捕获 JsonProcessingException,检查特定子类型,然后从异常 API 获取一些详细信息。根据您的需要,JsonParser 和 DeserializationContext API 可以为您提供日志的更多详细信息。
请参阅下面的自定义反序列化器可能是什么样的:
public class NonBlockingDeserializer<T> extends JsonDeserializer<T> {
private static final Logger LOGGER = Logger.getLogger(NonBlockingDeserializer.class.getName());
private StdDeserializer<T> delegate;
public NonBlockingDeserializer(StdDeserializer<T> delegate) {
this.delegate = delegate;
}
@Override
public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
try {
// Delegate the deserialization
return delegate.deserialize(jp, ctxt);
} catch (JsonProcessingException e) {
// Log the exception
logException(e);
// Return default null value
return delegate.getNullValue(ctxt);
}
}
private void logException(JsonProcessingException e) {
StringBuilder builder = new StringBuilder(e.getOriginalMessage() + System.lineSeparator());
builder.append(String.format("Source: %s \n", e.getLocation().getSourceRef()));
builder.append(String.format("Line: %s \n", e.getLocation().getLineNr()));
builder.append(String.format("Column: %s \n", e.getLocation().getColumnNr()));
if (e instanceof InvalidFormatException) {
InvalidFormatException e1 = (InvalidFormatException) e;
builder.append(String.format("Value: %s \n", e1.getValue()));
builder.append(String.format("Value type: %s \n", e1.getValue().getClass().getTypeName()));
builder.append(String.format("Target type: %s \n", e1.getTargetType().getTypeName()));
} else if (e instanceof UnrecognizedPropertyException) {
UnrecognizedPropertyException e1 = (UnrecognizedPropertyException) e;
builder.append(String.format("Property name: %s \n", e1.getPropertyName()));
builder.append(String.format("Known properties: %s \n", e1.getKnownPropertyIds()));
}
LOGGER.warning(builder.toString());
}
}
然后按如下方式使用它,为要忽略错误的类型添加反序列化器:
// Create module for custom deserializers
SimpleModule module = new SimpleModule("customDeserializers", Version.unknownVersion());
// Add deserializers for primitive types
module.addDeserializer(Double.TYPE, new NonBlockingDeserializer<Double>(
new NumberDeserializers.DoubleDeserializer(Double.TYPE, 0.d)));
module.addDeserializer(Integer.TYPE, new NonBlockingDeserializer<Integer>(
new NumberDeserializers.IntegerDeserializer(Integer.TYPE, 0)));
// Add deserializers for wrapper classes
module.addDeserializer(Double.class, new NonBlockingDeserializer<Double>(
new NumberDeserializers.DoubleDeserializer(Double.class, null)));
module.addDeserializer(Integer.class, new NonBlockingDeserializer<Integer>(
new NumberDeserializers.IntegerDeserializer(Integer.class, null)));
// Create ObjectMapper and register module
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
// Perform the deserialization as usual
Foo foo = mapper.readValue(json, Foo.class);
解析错误将被记录为:
Mar 11, 2018 10:45:33 AM org.example.playground.NonBlockingDeserializer logException
WARNING: Cannot deserialize value of type `java.lang.Integer` from String "18a": not a valid Integer value
Source: {"name": "Joe", "age": "18a"}
Line: 1
Column: 24
Value: 18a
Value type: java.lang.String
Target type: java.lang.Integer