Jackson反序列化未在Custom Deserializer上调用反序列化 [英] Jackson Deserialization not calling deserialize on Custom Deserializer

查看:229
本文介绍了Jackson反序列化未在Custom Deserializer上调用反序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想反序列化以下形式的类:

I want to deserialize classes of the form:

public class TestFieldEncryptedMessage implements ITextMessage {

    @JsonProperty("text")
    @Encrypted(cipherAlias = "testAlias")
    private String text;

    public TestFieldEncryptedMessage() {
    }

    @JsonCreator
    public TestFieldEncryptedMessage(@JsonProperty("text") String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

在加密文本的地方,反序列化应该在重建TestFieldEncryptedMessage实例之前对值进行解密.

Where the text is encrypted and deserialization should unencrypt the value before rebuilding the TestFieldEncryptedMessage instance.

我遵循的方法非常类似于: https://github.com/codesqueak/jackson-json-crypto

I am following an approach very similar to: https://github.com/codesqueak/jackson-json-crypto

也就是说,我正在构建一个扩展SimpleModule的模块:

That is, I am building a module extending SimpleModule:

public class CryptoModule extends SimpleModule {
    public final static String GROUP_ID = "au.com.auspost.messaging";
    public final static String ARTIFACT_ID = "jackson-json-crypto";
    private EncryptedSerializerModifier serializerModifier;
    private EncryptedDeserializerModifier deserializerModifier;

    public CryptoModule() {
    }

   public CryptoModule addEncryptionService(final EncryptionService encryptionService) {
        serializerModifier = new EncryptedSerializerModifier(encryptionService);
        deserializerModifier = new EncryptedDeserializerModifier(encryptionService);
        return this;
    }

    @Override
    public String getModuleName() {
        return ARTIFACT_ID;
    }

    @Override
    public Version version() {
        return new Version(major, minor, patch, null, GROUP_ID, ARTIFACT_ID);
    }

    @Override
    public void setupModule(final SetupContext context) {
        if ((null == serializerModifier) || (null == deserializerModifier))
            throw new EncryptionException("Crypto module not initialised with an encryption service");
        context.addBeanSerializerModifier(serializerModifier);
        context.addBeanDeserializerModifier(deserializerModifier);
    }
}

如您所见,设置了两个修饰符:EncryptedSerializerModifier可以正常工作并由ObjectMapper调用,但是EncryptedDeserializerModifier背后的反序列化器将被忽略.

As you can see, two modifiers are set up: the EncryptedSerializerModifier works perfectly and is called by the ObjectMapper, but the deserializer behind the EncryptedDeserializerModifier is ignored.

如在SO上的许多其他示例中所见,例如:

As is seen in many other examples on SO such as here: How can I include raw JSON in an object using Jackson?, I set up the EncryptedDeserializerModifier with:

public class EncryptedDeserializerModifier extends BeanDeserializerModifier {

    private final EncryptionService encryptionService;

    private Map<String, SettableBeanProperty> properties = new HashMap<>();

    public EncryptedDeserializerModifier(final EncryptionService encryptionService) {
        this.encryptionService = encryptionService;
    }

    @Override
    public BeanDeserializerBuilder updateBuilder(final DeserializationConfig config, final BeanDescription beanDescription, final BeanDeserializerBuilder builder) {

        Encrypted annotation = beanDescription.getType().getRawClass().getAnnotation(Encrypted.class);
        Iterator it = builder.getProperties();

        while (it.hasNext()) {
            SettableBeanProperty p = (SettableBeanProperty) it.next();

            if (null != p.getAnnotation(Encrypted.class)) {
                JsonDeserializer<Object> current = p.getValueDeserializer();
                properties.put(p.getName(), p);

                builder.addOrReplaceProperty(p.withValueDeserializer(new EncryptedJsonDeserializer(encryptionService, current, p)), true);
            }
        }
        return builder;
    }
}

最后,EncryptedJsonDeserializer本身将覆盖以下内容:

Finally, the EncryptedJsonDeserializer itself overrides the following:

@Override
public Object deserialize(final JsonParser parser, final DeserializationContext context) throws JsonMappingException {
    JsonDeserializer<?> deserializer = baseDeserializer;

    if (deserializer instanceof ContextualDeserializer) {
        deserializer = ((ContextualDeserializer) deserializer).createContextual(context, property);
    }

    return service.decrypt(parser, deserializer, context, property != null ? property.getType() : type);
}

@Override
public JsonDeserializer<?> createContextual(final DeserializationContext context, final BeanProperty property) throws JsonMappingException {
    JsonDeserializer<?> wrapped = context.findRootValueDeserializer(property.getType());
    return new EncryptedJsonDeserializer(service, wrapped, property);
}

调用createContextual()方法,但不调用反序列化方法.在整个执行过程中,该属性始终是文本"属性,因此我似乎拥有正确的上下文.

The createContextual() method is called, but the deserialize method is not called. The property throughout the execution is always the "text" property, so I seem to have the right context.

有人知道为什么ObjectMapper找不到正确的反序列化器吗?

anyone know why the ObjectMapper doesn't find the right Deserializer?

编辑implements ITextMessage添加到了解密的类中,我认为这是一个不重要的细节,但事实证明是造成该问题的原因.

EDIT added implements ITextMessage to decrypted class, which I thought was an unimportant detail, but turned out to be the cause of the issue.

推荐答案

我发现了问题!如果仔细查看TestFieldEncryptedMessage类(其text字段已加密),您会发现它实现了一个接口.使用该接口是为了使消息为测试中的断言提供一些额外的工具,但是对于反序列化,则会产生意想不到的结果.我认为,当ObjectMapper遍历json字符串时,它会尝试将反序列化器与ITextMessage内的字段匹配,而不是与TestFieldEncryptedMessage内的字段匹配,这就是为什么未调用自定义反序列化器的原因(在ITextMessage中没有text字段.

I found the issue! If you look closely at the TestFieldEncryptedMessage class, whose text field is encrypted, you can see that it implements an interface. The interface is used so that the messages give some extra tooling for asserts in tests, however for deserialization, there is an unintended consequence. When the ObjectMapper is working its way through the json string, it tries, I think, to match a deserializer to a field inside ITextMessage, not to a field inside TestFieldEncryptedMessage, which is why the custom deserializer was not called (there is no text field in ITextMessage).

一旦我停止实现ITextMessage,就会调用自定义解串器.

Once I stopped implementing ITextMessage, the custom deserializer was called.

这篇关于Jackson反序列化未在Custom Deserializer上调用反序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆