Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nulls property metadata ignored for creators #2458

Closed
XakepSDK opened this issue Sep 16, 2019 · 7 comments
Closed

Nulls property metadata ignored for creators #2458

XakepSDK opened this issue Sep 16, 2019 · 7 comments
Milestone

Comments

@XakepSDK
Copy link
Contributor

I'm using jackson databind 2.9.9.3.
I'm trying to deserialize object with creator. I've set

objectMapper.setDefaultSetterInfo(JsonSetter.Value.construct(Nulls.AS_EMPTY, Nulls.AS_EMPTY))

But jackson tries to put null instead of empty set in my constructor.

I debugged jackson and found, that jackson calls BasicDeserializerFactory#constructCreatorProperty to get constructor argument property(class CreatorProperty).
This class holds ProperyMetadata, which is used later to handle Nulls value.

PropertyMetadata constructed using PropertyMetadata.construct method (line 1066 in source code in IDE or https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/deser/BasicDeserializerFactory.java#L930 in current)

This call does not fill _valueNulls and _contentNulls. Looks like JsonSetter annotation and defaults are completely ignored for constructor arguments.

Is this intended? How can i prevent jackson from putting nulls in my contructor?

@cowtowncoder
Copy link
Member

It sounds like a bug. What would be super useful is a simple unit test to show the problem, might be easy to fix.

@XakepSDK
Copy link
Contributor Author

XakepSDK commented Sep 16, 2019

databind 2.9.9.3
https://gist.github.com/XakepSDK/ed57a991510848f19aebc4ebff535ef0

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

public class Test {
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setDefaultSetterInfo(JsonSetter.Value.construct(Nulls.AS_EMPTY, Nulls.AS_EMPTY));
        Pojo pojo = mapper.readValue("{}", Pojo.class);
    }

    public static class Pojo {
        private final List<String> list;

        @JsonCreator
        public Pojo(@JsonProperty("list") List<String> list) {
            this.list = Objects.requireNonNull(list, "list");
        }

        public List<String> getList() {
            return list;
        }
    }
}

@cowtowncoder
Copy link
Member

Thanks!

cowtowncoder added a commit that referenced this issue Sep 22, 2019
@cowtowncoder
Copy link
Member

Ok, so looks like NullValueProvider for SettableBeanProperty is not considered during checking of values by PropertyValueBuffer in getParameters() where null-check for DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES is made.

It looks like there is already a loop for checking "missing" properties, which seems like the place to do call for NullValueProvider... I'll see if I can find a way to get NVP for property.

@cowtowncoder
Copy link
Member

Ok. Looks like wiring of above is actually quite easy: PVB._findMissing() has all the info. But unfortunately NullValueProvider assigned is just the deserializer, not empty value provider, so something else is not properly wired I think.

This is pretty severe shortcoming as it looks like case of null-value conversion is only tested via setter/field, but not constructor parameters. Clear oversight from 2.9 tests for the new feature.

@cowtowncoder
Copy link
Member

cowtowncoder commented Sep 23, 2019

Looks like somehow CreatorProperty is missing PropertyMetadata.getValueNulls(), from resolve() of deserializer associated with property: this is different from MethodProperty receiving same info somehow. Creator properties are created using different code path than other kinds, but obviously should not matter in this respect.

Also found #2280 that is perhaps related...

@cowtowncoder
Copy link
Member

Ok. I think I see what is happening. It is in fact due to different construction paths.

For non-creator properties, POJOPropertyBuilder instance (per property, managed by POJOPropertiesCollector) handles collection of PropertyMetadata, and finds necessary pieces. For creator properties (CreatorProperty), PropertyMetadata is collected in BaseDeserializerFactory.constructCreatorProperty(). Latter was not augmented with access to merge-info it seems, and needs to be.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants