当前位置: 首页 > 知识库问答 >
问题:

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

胡鸿羲
2023-03-14

我想反序列化表单中的类:

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后面的反序列化器被忽略。

正如在SO上的许多其他示例中看到的那样:如何使用Jackson在对象中包含原始JSON?,我使用以下方式设置了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;
    }
}

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

@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()方法,但未调用反序列化方法。整个执行过程中的属性始终是“text”属性,因此我似乎拥有正确的上下文。

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

EDIT将ITextMessage实现到解密的类,我认为这是一个不重要的细节,但事实证明是问题的原因。

共有1个答案

班承德
2023-03-14

我发现了问题!如果仔细观察TestFieldEncryptedMessage类,可以看到它实现了一个接口。使用该接口是为了使消息为测试中的断言提供一些额外的工具,但是对于反序列化,会产生意外的后果。当ObjectMapper遍历json字符串时,我认为它会尝试将反序列化器与ITextMessage中的字段相匹配,而不是与TestFieldEncryptedMessage中的字段相匹配,这就是为什么没有调用自定义反序列化器的原因(ITextMessage中没有文本字段)。

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

 类似资料:
  • I'va是一个OID接口,可以由许多具体类型实现: 现在我有一个具有两个字段的对象,一个使用抽象接口类型(OID)定义,另一个使用具体类型(MyOID)定义 我想使用jackson以不同的方式序列化/反序列化字段,无论它们是使用抽象接口类型还是具体类型定义的: 注意,被序列化,包括类型信息(多态序列化),而被序列化为文本 为此,我将OID接口注释为: 并为每个具体类型分配了类型id: 最后,对容器

  • 我有一个Spring项目,我尝试添加一个自定义反序列化器来反序列化日期属性,具体取决于它们的格式。如果我将其用作Date属性的注释,则效果很好。但是,如果我将反序列化器添加到对象映射器中,当Jackson反序列化日期时,它不会调用。 我尝试这样应用我的自定义反序列化程序: 我不想每次都对Date属性应用注释,我想默认使用此反序列化器。我做错了什么?

  • 我想通过扩展默认的反序列化器来创建自己的反序列化器,在其后面设置更多的值: 如您所见,我还想将此DTO母类重用于其他DTO。 我没有找到任何这样的例子。我真的是世界上第一个 反序列化的“AsUsual”(p,ctxt)应该是什么 我应该使用什么motherclass?JsonDeserializer/StdDeserializer/UntypedObjectDeserializer 反序列化程序会

  • 问题内容: 我无法找出使用杰克逊实现自定义序列化/反序列化的正确方法。我有很多类(〜50),它们带有应被序列化/反序列化而不是原始的原始字段。喜欢: 所有序列化和反序列化都非常相似,我只需要在整数之后添加一个后缀(C,页面,米等)。 一种简单的方法是在每个这样的字段中添加一对/ 注释并实现它们。但是我最终会得到100个 非常相似的 序列化器/反序列化器。 我想到了添加自定义注释的各个领域,说或,这

  • 我有下面的JSON,我正试图使用Jackson API反序列化它 我基本上需要一个附件类,它有一个AttachmentFile对象列表,如下所示: 如何使用自定义反序列化器实现这一点? 谢谢

  • 我正在尝试在SpringBoot应用程序中编写Jackson反序列化器模块。主要原因是使用自定义Jackson反序列化程序对传入请求中的pin码进行加密。加密属性由spring组件 我试图从这个解决方案,但我的自定义反序列化程序仍然没有调用。而不是基于此,始终调用,并且不执行加密 提前谢谢 注释: 带有要加密字段的请求正文 杰克逊构型 模块: 最后反序列化器: