jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

constructorDetector seems to invalidate defaultSetterInfo for nullability

Open joca-bt opened this issue 2 years ago • 4 comments

Was trying out the new constructor detector feature (https://cowtowncoder.medium.com/jackson-2-12-most-wanted-3-5-246624e2d3d0/) and stumbled upon the following issue.

I had this code which forbids nulls on deserialization:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

public class Input {
    private final Boolean field;

    @JsonCreator
    public Input(Boolean field) {
        this.field = field;
    }
}

ObjectMapper objectMapper = JsonMapper.builder()
    .addModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))
    .defaultSetterInfo(JsonSetter.Value.construct(Nulls.FAIL, Nulls.FAIL))
    .build();

objectMapper.readValue("{ \"field\": null }", Input.class); // throws InvalidNullException, as expected

and was trying to get rid of @JsonCreator with the following

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;

public class Input {
    private final Boolean field;

    // @JsonCreator gone!
    public Input(Boolean field) {
        this.field = field;
    }

    public Boolean field() {
      return field;
    }
}

ObjectMapper objectMapper = JsonMapper.builder()
    .addModule(new ParameterNamesModule(JsonCreator.Mode.PROPERTIES))
    .constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED) // new!
    .defaultSetterInfo(JsonSetter.Value.construct(Nulls.FAIL, Nulls.FAIL))
    .build();

objectMapper.readValue("{ \"field\": null }", Input.class); // no error, field is assigned to null

Although I no longer need to annotate my class with @JsonCreator, my settings for nullability are ignored, which means I can't really use the new feature.

(Might be related with https://github.com/FasterXML/jackson-databind/issues/3227?)

joca-bt avatar Aug 12 '21 12:08 joca-bt

Yes, I can reproduce this. Strange... It is possible this is due to implicit detection of constructors missing some information that would be discovered by explicitly marker ones.

cowtowncoder avatar Aug 25 '21 04:08 cowtowncoder

This is particularly annoying when using records as we need to do something like:

public record Input(Boolean field) {
    @JsonCreator
    public Input {}
}

Do you think this fix can be included in 2.14?

joca-bt avatar Nov 29 '21 11:11 joca-bt

As soon as someone provides a fix, yes, it could probably be included in a 2.13.x patch as well. I haven't had and probably won't have time to work in this in near future.

cowtowncoder avatar Nov 30 '21 00:11 cowtowncoder

Sigh. Yes, I think this is because of the disprepancy between merging of annotations between explicitly annotated and implicitly located Creators: this is a long-standing general problem that manifests in many different ways.

On plus side: if and when property introspection gets rewritten (it is #1 top Big Thing for me to fix) this problem will be resolved. On downside: I have not been able to find enough time to start the rewrite.

cowtowncoder avatar Jun 13 '22 04:06 cowtowncoder

This is particularly annoying when using records as we need to do something like:

public record Input(Boolean field) {
   @JsonCreator
   public Input {}
}
  • For Record: With 2.15.0 (which contains #3724), you no longer need to annotate your Record's canonical constructor with @JsonCreator - it will just work (or rather, fail with InvalidNullException).
  • For POJO: Not fixed yet.

yihtserns avatar May 07 '23 12:05 yihtserns