Search before asking
Describe the bug
@JacksonInject documents useInput = OptBoolean.FALSE as "input value (if any) will be ignored", and the @return javadoc spells it out further: "OptBoolean.FALSE if injected value will always be used regardless of input".
That holds for Creator properties. CreatorProperty.isInjectionOnly() reports it and the property-based-Creator loops act on it (the [databind#1381] checks in BeanDeserializer, BuilderBasedDeserializer, BeanAsArrayDeserializer and BeanAsArrayBuilderDeserializer), with PropertyValueBuffer._inject() supplying the value afterwards.
It does not hold for a property backed by a Field or a Setter. SettableBeanProperty.getInjectionDefinition() returns null for those, so isInjectionOnly() is always false and the property stays in the settable set. Injection for them goes through ValueInjector instead, and injectValues() runs right after the bean is constructed, before any property is read, so a matching name in the document just overwrites the injected value.
The practical consequence is for code that uses @JacksonInject to pin a server-side value onto a POJO, say a tenant id, a principal, or a request id: with useInput = OptBoolean.FALSE the caller has asked for that value to be non-overridable, and the document overrides it anyway.
JacksonInject1381Test already asserts the intended behavior ("input YES, injectable YES, useInput DEFAULT|FALSE => injected"), but every fixture in it reaches the value through a Creator, so the Field/Setter path is not covered.
Version Information
3.1, 3.2, 3.x (also 2.22.2)
Reproduction
public class Doc {
@JacksonInject(value = "tenant", useInput = OptBoolean.FALSE)
public String tenant = "unset";
public String title = "";
}
ObjectMapper mapper = JsonMapper.builder()
.injectableValues(new InjectableValues.Std().addValue("tenant", "tenant-42"))
.build();
Doc doc = mapper.readValue("{\"tenant\":\"tenant-99\",\"title\":\"x\"}", Doc.class);
System.out.println(doc.tenant); // prints "tenant-99", expected "tenant-42"
The same holds for a @JacksonInject-annotated setter, for @JsonFormat(shape = Shape.ARRAY) types, for @JsonPOJOBuilder builders, for @JsonUnwrapped values, and on the readerForUpdating() path.
Moving the same declaration onto a Creator parameter gives the documented result:
public class Doc {
public final String tenant;
public final String title;
@JsonCreator
public Doc(@JacksonInject(value = "tenant", useInput = OptBoolean.FALSE) String tenant,
@JsonProperty("title") String title) {
this.tenant = tenant;
this.title = title;
}
}
// doc.tenant is "tenant-42"
Expected behavior
A Field- or Setter-backed property annotated with @JacksonInject(useInput = OptBoolean.FALSE) should keep the injected value and drop any matching value from input, the same as the Creator case.
Only the explicit OptBoolean.FALSE setting is at issue here. DEFAULT and TRUE should keep behaving as they do now.
Additional context
Related: #1381 (where useInput handling was introduced) and #2678.
Search before asking
Describe the bug
@JacksonInjectdocumentsuseInput = OptBoolean.FALSEas "input value (if any) will be ignored", and the@returnjavadoc spells it out further: "OptBoolean.FALSEif injected value will always be used regardless of input".That holds for Creator properties.
CreatorProperty.isInjectionOnly()reports it and the property-based-Creator loops act on it (the[databind#1381]checks inBeanDeserializer,BuilderBasedDeserializer,BeanAsArrayDeserializerandBeanAsArrayBuilderDeserializer), withPropertyValueBuffer._inject()supplying the value afterwards.It does not hold for a property backed by a Field or a Setter.
SettableBeanProperty.getInjectionDefinition()returnsnullfor those, soisInjectionOnly()is always false and the property stays in the settable set. Injection for them goes throughValueInjectorinstead, andinjectValues()runs right after the bean is constructed, before any property is read, so a matching name in the document just overwrites the injected value.The practical consequence is for code that uses
@JacksonInjectto pin a server-side value onto a POJO, say a tenant id, a principal, or a request id: withuseInput = OptBoolean.FALSEthe caller has asked for that value to be non-overridable, and the document overrides it anyway.JacksonInject1381Testalready asserts the intended behavior ("input YES, injectable YES, useInput DEFAULT|FALSE => injected"), but every fixture in it reaches the value through a Creator, so the Field/Setter path is not covered.Version Information
3.1, 3.2, 3.x (also 2.22.2)
Reproduction
The same holds for a
@JacksonInject-annotated setter, for@JsonFormat(shape = Shape.ARRAY)types, for@JsonPOJOBuilderbuilders, for@JsonUnwrappedvalues, and on thereaderForUpdating()path.Moving the same declaration onto a Creator parameter gives the documented result:
Expected behavior
A Field- or Setter-backed property annotated with
@JacksonInject(useInput = OptBoolean.FALSE)should keep the injected value and drop any matching value from input, the same as the Creator case.Only the explicit
OptBoolean.FALSEsetting is at issue here.DEFAULTandTRUEshould keep behaving as they do now.Additional context
Related: #1381 (where
useInputhandling was introduced) and #2678.