Skip to content

Setting ValueDeserializer on Property using BeanDeserializerBuilder.addOrReplaceProperty does not work when POJO has constructor #3399

@vuquocbao

Description

@vuquocbao

Describe the bug
When setting a custom deserializer for a property using BeanDeserializerBuilder.addOrReplaceProperty that customer deserializer is not applied when the POJO has a constructor method.

After some debugging, it has to do with the _propertyBasedCreator field in the BaseBeanDeserializer class. If the POJO has a constructor method that the _propertyBaseCreator field is set. But the properties stored in those fields are not in sync with the _beanProperties fields which has the value deserializer applied from the addOrReplaceProperty.

Currently I'm using version 2.13 and running into this issue when using this library

https://github.com/codesqueak/jackson-json-crypto.

That library above add an annotation and if string fields are annotated with that annotation it will serialize the string into an encrypted format.

Version information
2.13

To Reproduce

If I have two classes

class A {
  private String value = null

  public A(String value) ...
  
  @JsonProperty
  @Encrypt
  public getValue() ...

  public setValue(String: value) ...
}

class B {
  private String value = null

  public B() ...
  
  @JsonProperty
  @Encrypt
  public getValue() ...

  public setValue(String: value) ...
}

And have a BeanDeserializationModifier that looks like this from the gitbug project above

public class EncryptedDeserializerModifier extends BeanDeserializerModifier {

    private final EncryptionService encryptionService;

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

    @Override
    public BeanDeserializerBuilder updateBuilder(final DeserializationConfig config, final BeanDescription beanDescription, final BeanDeserializerBuilder builder) {
        var it = builder.getProperties();
        while (it.hasNext()) {
            var property = it.next();
            if (null != property.getAnnotation(Encrypt.class)) {
                var current = property.getValueDeserializer();
                builder.addOrReplaceProperty(property.withValueDeserializer(new EncryptedJsonDeserializer(encryptionService, current)), true);
            }
        }
        return builder;
    }
}

I can properly serialize and then deserialize class B but not class A.

// Does not work
var objectA = new A("Some String")
var jsonA = objectMapper.writeValue(objectA)
var readA = objectMapper.readValue(jsonA, A.class)

// Does work
var objectB = new B("Some String")
var jsonB = objectMapper.writeValue(objectB)
var readB = objectMapper.readValue(jsonB, B.class)

Expected behavior

Both approaches should be able to properly read in a JSON value using a customer deserializer.

Additional context
Add any other context about the problem here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    need-test-caseTo work on issue, a reproduction (ideally unit test) needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions