如何使用 Jackson BeanDeserializerModifier?

Mar*_*eri 3 jackson deserialization

我正在尝试实现自定义解串器。因为我只想给默认的反序列化器添加功能,所以我尝试在我的自定义反序列化器中存储默认的:我想使用默认的反序列化json然后添加其他信息。

我正在尝试使用 BeanDeserializerModifier 来注册自定义解串器。

SimpleModule module = new SimpleModule("ModelModule", Version.unknownVersion());

module.setDeserializerModifier(new BeanDeserializerModifier() {
    @Override
    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        JsonDeserializer<?> configuredDeserializer = super.modifyDeserializer(config, beanDesc, deserializer);
        if (Document.class.isAssignableFrom(beanDesc.getBeanClass())) {
            logger.debug("Returning custom deserializer for documents");

            configuredDeserializer = new DocumentDeserializer(configuredDeserializer, (Class<Document>)beanDesc.getBeanClass());
        } 

        return configuredDeserializer;
    }
});
Run Code Online (Sandbox Code Playgroud)

如您所见,如果要生成的对象是“文档”,我正在修改返回自定义解串器的解串器。我将默认反序列化器传递给构造函数,以便稍后使用它。

当我尝试反序列化时,Jackson 失败并显示错误:

No _valueDeserializer assigned(..)
Run Code Online (Sandbox Code Playgroud)

我已经调查过,似乎默认解串器没有正确的解串器属性:对于所有属性,它使用的解串器 FailingDeserializer 当然失败并返回上述错误。这个解串器应该被替换,但事实并非如此。

看来,在调用了 modifyDeserializer 方法之后,Jackson 就完成了配置。

我使用的自定义解串器是:

@SuppressWarnings("serial")
public class DocumentDeserializer extends StdDeserializer<Document> {
    private JsonDeserializer<?> defaultDeserializer;
    private DocumentDeserializer(JsonDeserializer<?> defaultDeserializer, Class<? extends Document> clazz) {
        super(clazz);
        this.defaultDeserializer = defaultDeserializer;
    }

    @Override
    public Document deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        Document documentDeserialized = (Document) defaultDeserializer.deserialize(jp, ctxt);
        /* I want to modify the documentDeserialized before returning it */
        return documentDeserialized;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新: 我使用不同的解串器解决了这个问题:

public class CustomDeserializerModifier extends BeanDeserializerModifier {
    private static final Logger logger = Logger.getLogger(CustomDeserializerModifier.class);

    public CustomDeserializerModifier (Factory factory) {
        this.factory = factory;
    }

    @Override
    public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
        JsonDeserializer<?> configuredDeserializer;
        if (CustomDeserializedNode.class.isAssignableFrom(beanDesc.getBeanClass())) {
            Converter<Object, Object> conv = beanDesc.findDeserializationConverter();
            JavaType delegateType = conv.getInputType(config.getTypeFactory());
            configuredDeserializer = new CustomDeserializedNodeDeserializer(conv, delegateType, (JsonDeserializer<Document>) deserializer, 
                    (Class<? extends CustomDocument<?>>)beanDesc.getBeanClass());
        } else {
            configuredDeserializer = super.modifyDeserializer(config, beanDesc, deserializer);
        }

        return configuredDeserializer;
    }

    @SuppressWarnings("serial")
    public class CustomDeserializedNodeDeserializer extends StdDelegatingDeserializer<Object> {
        private Class<? extends CustomDocument<?>> beanClass;
        public CustomDeserializedNodeDeserializer(Converter<Object,Object> converter,
                JavaType delegateType, JsonDeserializer<Document> delegateDeserializer, Class<? extends CustomDocument<?>> beanClass) {
            super(converter, delegateType, delegateDeserializer);
            this.beanClass = beanClass;
        }

        @Override
        public CustomDeserializedNode deserialize(JsonParser jp, DeserializationContext ctxt)

                throws IOException, JsonProcessingException {
            CustomDeserializedNode node = (CustomDeserializedNode)factory.createCustomDocument(beanClass);
            CustomDeserializedNode documentDeserialized = (Document) super.deserialize(jp, ctxt, node);

            return documentDeserialized;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

可能扩展 StdDelegatingDeserializer 做了@StaxMan 的建议。

Sta*_*Man 5

这应该在FAQ中添加,但您需要做的是实现2个接口:

  • ResolvableDeserializer(方法resolve(...)
  • ContextualDeserializer(方法createContextual(...)

并将这些调用委托给defaultDeserializer它,以防它实现一个或两个接口。这些是解串器初始化所必需的;特别是ContextualDeserializer通过属性注释可用于反序列化器。并且ResolvableDeserializer被用于BeanDeserializer获取它所具有的属性的反序列化器(如果有的话);这是有_valueDeserializer问题的地方可能会被提取。