Jackson的BeanDeserializerModifier无法与final字段一起使用

rbpvctlc  于 2022-11-09  发布在  其他
关注(0)|答案(1)|浏览(245)

我编写了一个自定义序列化程序和自定义反序列化程序来序列化用@Confidential注解标记的属性。

@Data
public class Person {
   private String name;

   @Confidential
   private String address;
}

自订序列化程式会序列化具有下列值的POJO:

{ "name": "John Doe", "address": "Kearney St"}

如下所示:

{"name":"John Doe", "address": {"value":"IjIwMzEwIDU4dGggTG4gTkUi"}}

自定义反序列化器还能够将JSON反序列化回Person POJO fine。

但是,当我将Person POJO中的字段设置为final时,序列化继续工作,但反序列化失败。

@Data
public class Person {
    private final String name;

    @Confidential
    private final String address;
 }

下面是BeanSerializerModifier的实现:

@AllArgsConstructor
public class CustomDeserializerModifier extends BeanDeserializerModifier {
    private final ObjectMapper objectMapper;

    @Override
    public BeanDeserializerBuilder updateBuilder(final DeserializationConfig config,
                                                 final BeanDescription beanDesc,
                                                 final BeanDeserializerBuilder builder) {
        Iterator<SettableBeanProperty> beanPropertyIterator = builder.getProperties();
        beanPropertyIterator.forEachRemaining(settableBeanProperty -> {
            final Confidential annotation = settableBeanProperty.getAnnotation(Confidential.class);
            if (encryptedProperty != null) {
                JsonDeserializer<Object> current = settableBeanProperty.getValueDeserializer();
                final SettableBeanProperty newSettableBeanProperty =
                        settableBeanProperty.withValueDeserializer(
                                new CustomDeserializer(annotation, current, objectMapper)
                        );
                builder.addOrReplaceProperty(newSettableBeanProperty, true);
            }
        });

        return builder;
    }
}

我发现当Person POJO字段为final时,永远不会调用CustomDeserializer。

以下是错误消息:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token
 at [Source: {"name":"John Doe","address":{"value":"IjIwMzEwIDU4dGggTG4gTkUi"}}; line: 1, column: 30] (through reference chain: com.custom.model.Person["address"])

JacksonMaven可以告诉我为什么当POJO字段为final时,CustomDeserializer没有被调用。

谢谢你,谢谢你

9jyewag0

9jyewag01#

如前所述,序列化对于可变字段和不可变字段都能很好地工作。反序列化问题只会在使用不可变字段时发生,因为BeanDeserializerModifier在这种情况下不起作用。
在Jackson术语中,不可变字段被命名为创建者属性,这意味着它们是使用创建者初始化的。请参见BeanDeserializerBase#resolve。
为了正确地处理此用例,可以使用自定义的DeserializationContext创建ObjectMapper(ObjectMapper的扩展实现也可以设置与反序列化上下文相关的受保护字段)。
然后,通过重写方法DeserializationContext#handleSecondaryContextualization,可以更改反序列化以使其正常工作。
也许还有其他的可能性,但这一个是工作的罚款与加密。

相关问题