除非我添加带注释的接口,否则自定义Jackson的反序列化将导致StackOverflowError

时间:2018-06-28 07:49:32

标签: java json jackson json-deserialization

我必须在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);
    }
}

不再需要注释和其他内容。这都是一个很棒的技巧,但是我宁愿这样做,也不愿创建很多接口。

0 个答案:

没有答案