jackson-databind
jackson-databind copied to clipboard
constructorDetector seems to invalidate defaultSetterInfo for nullability
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?)
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.
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?
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.
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.
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 withInvalidNullException
). - For POJO: Not fixed yet.