I tried everything but I'm still stuck on this. I'm using the jackson annotation @JsonUnwrapped to flatten my request while using inheritance and generic types at the same time. The fact is that I don't want to use a custom deserializer.
Reproduction step :
{
"bar1": "12",
"bar2": "bar2",
"foo1": "foo1",
"foo2": "123"
}
@Slf4j
@Validated
@RestController
@RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public class MyController {
@PostMapping("/bar")
public void test(@Valid @RequestBody final Bar1 bar1) {
log.info("{}", bar1);
}
}
public abstract class AbstractBar<F extends AbstractFoo> {
@Pattern(regexp = "\\d{2}")
protected final String bar1;
@Valid
@JsonUnwrapped
protected final F foo;
protected AbstractBar(final String bar1, final F foo) {
this.bar1 = bar1;
this.foo = foo;
}
public String getBar1() {
return this.bar1;
}
public F getFoo() {
return this.foo;
}
}
public abstract class AbstractFoo {
protected final String foo1;
@Pattern(regexp = "\\d{3}")
protected final String foo2;
protected AbstractFoo(final String foo1,
final String foo2) {
this.foo1 = foo1;
this.foo2 = foo2;
}
public String getFoo1() {
return this.foo1;
}
public String getFoo2() {
return this.foo2;
}
}
public class Bar1 extends AbstractBar<Foo1> {
@NotBlank
private final String bar2;
@JsonCreator
public Bar1(final String bar1,
final String bar2,
final String foo1,
final String foo2) {
super(bar1, new Foo1(foo1, foo2));
this.bar2 = bar2;
}
@Override
public @NotBlank String getBar1() {
return this.bar1;
}
@Override
public @NotNull Foo1 getFoo() {
return this.foo;
}
}
public class Foo1 extends AbstractFoo {
public Foo1(final String foo1,
final String foo2) {
super(foo1, foo2);
}
@Override
public @NotBlank String getFoo1() {
return this.foo1;
}
@Override
public @Nullable String getFoo2() {
return this.foo2;
}
}
When I send the json, my Bar1 JsonCreator is well understood
But entering the getter, i get null values which ends as constraint validation error through my Foo1 @NotBlank on foo1 field
I'm using spring boot 3.4.0 which means jackson 2.18.1 dependencies. Thank you very much for your time ❤
The field F foo
has been set by the constructor protected AbstractBar(final String bar1, final F foo)
, and then Jackson sets it again (using FieldProperty.deserializeAndSet
), at this time, the fields of Foo1
are all null. You can use @JsonProperty(access = JsonProperty.Access.READ_ONLY)
on the field to avoid it.
UPDATE
Another way is to remove final
, JsonCreator
, constructor, and then use the default constructor and setter.
Note: Adding the annotation JsonCreator
to the constructor of Foo1
does not work either, it seems that the data has been read and cannot be read again.