代码之家  ›  专栏  ›  技术社区  ›  Michael Coxon

Jackson反序列化未在自定义反序列化程序上调用反序列化

  •  3
  • Michael Coxon  · 技术社区  · 7 年前

    我想反序列化表单的类:

    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实例之前取消对值的加密。

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

    也就是说,我正在构建一个扩展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后面的反序列化程序被忽略。

    如许多其他例子所示: How can I include raw JSON in an object using Jackson? ,我使用以下命令设置EncryptedDeserializerModifier:

    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;
        }
    }
    

    最后,encryptedjsondersializer本身会重写以下内容:

    @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);
    }
    

    调用了createContext()方法,但未调用反序列化方法。整个执行过程中的属性始终是“文本”属性,因此我似乎拥有正确的上下文。

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

    编辑 补充 implements ITextMessage 解密类,我认为这是一个不重要的细节,但结果是问题的原因。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Michael Coxon    7 年前

    我找到问题了!如果你仔细观察 TestFieldEncryptedMessage 类,其 text 字段是加密的,您可以看到它实现了一个接口。接口的使用使得消息为测试中的断言提供了一些额外的工具,但是对于反序列化,会产生意外的结果。当ObjectMapper通过json字符串工作时,我认为它会尝试将反序列化程序与内部的字段匹配 ITextMessage ,而不是里面的一块地 TestFieldEncryptedMessage消息 ,这就是为什么没有调用自定义反序列化程序(没有 文本 字段输入 文本消息 ).

    一旦我停止实现ITextMessage,就会调用自定义反序列化程序。