我必须在JSON反序列化时的Jackson中添加一个拦截器,以验证构造的POJO,并可以访问Json对象以进行监视/记录。
为此,我添加了一个简单的反序列化器,该反序列化器将POJO清楚地反序列化如下:
@Override
public T deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
ObjectCodec codec = p.getCodec();
JsonNode node = codec.readTree(p);
ABC transaction = codec.treeToValue(node, klass);
if (ObjectUtil.hasAllFieldsNull(transaction)) {
MonitorClient monitor = (MonitorClient) ctx.findInjectableValue("monitor", null, null);
monitor.fireError..etc
}
return transaction;
}
我已经注释了ABC类,如下所示
@JsonDeserialize(as = ABC.class, using = ABCDeserializer.class)
class ABC {}
问题在于这会导致StackOverflowError
java.lang.StackOverflowError: null
at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:246) ~[?:?]
at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:68) ~[?:?]
at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:15) ~[?:?]
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3972) ~[?:?]
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:2372) ~[?:?]
解决此问题的一种方法是使用多态json的模式,并按如下所示创建接口IABC
@JsonDeserialize(using = ABCDeserializer.class)
interface IABC {}
并将ABC和注释的定义更改为
@JsonDeserialize(as = ABC.class)
class ABC implements IABC {}
但是我不喜欢这种方法,因为我必须对每个反序列化的对象进行反序列化,这会导致很多“无用的”接口。
这可以用更简单的方法解决吗?
编辑: 我最后要做的是
添加一个BeanDeserializerModifier来创建自定义的Deserializer,该代理将委托给默认的序列化器并拦截json的后继构造:
public class MonitoringObjectDeserializerModifier extends BeanDeserializerModifier {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (beanDesc.getBeanClass() == Abcd.class) {
return new MonitoringBeanDeserializer((BeanDeserializerBase) deserializer);
}
return deserializer;
}
}
解串器如下所示:
public class MonitoringBeanDeserializer<T> extends BeanDeserializer {
private static final long serialVersionUID = 1L;
private final JsonDeserializer<?> deserializer;
public MonitoringBeanDeserializer(BeanDeserializerBase base) {
super(base);
this.deserializer = base;
}
@Override
public T deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
JsonLocation initialLocation = p.getCurrentLocation();
T transaction = ObjectUtil.uncheckedCast(deserializer.deserialize(p, ctx));
if (ObjectUtil.hasAllFieldsNull(transaction)) {
String txJson = extractJson(initialLocation, p.getCurrentLocation());
MonitorClient monitor = (MonitorClient) ctx.findInjectableValue("monitor", null, null);
monitor.abcd..
}
return transaction;
}
private static String extractJson(JsonLocation initialLocation, JsonLocation finalLocation) {
Object source = initialLocation.getSourceRef();
String sourceJson;
if (source instanceof StringReader) {
sourceJson = (String) ObjectUtil.get(source, "str");
} else {
sourceJson = (String) source;
}
int start = (int) initialLocation.getCharOffset() - 1;
int end = (int) finalLocation.getCharOffset();
return sourceJson.substring(start, end);
}
}
不再需要注释和其他内容。这都是一个很棒的技巧,但是我宁愿这样做,也不愿创建很多接口。