How to define entity inheritance in a SpringBoot openapi type definition when POST-ing a @RequestBody
containing an object map of polymorphic entities?
Shouldn’t it be sufficient to set anyOf = { PolarParrot.class, NorvegianParrot.class}, discriminatorProperty = "parrotType"
in order to type hint which concrete Parrot
instance must be used to resolve the RequestBody
?
import java.lang.Override;
import java.net.URI;
import java.util.Map;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
@RestController
public class PolyParrot {
@PostMapping(value = {"/create"}, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> create(@Valid @RequestBody Flock flock) {
return ResponseEntity.created(URI.create("/flock/42")).build();
}
}
@Schema(additionalProperties = Schema.AdditionalPropertiesValue.TRUE)
class Flock {
@Schema
Map<String, Parrot> birds;
public Map<String, Parrot> getBirds() {
return birds;
}
public void setBirds(Map<String, Parrot> birds) {
this.birds = birds;
}
}
@Schema(anyOf = {
PolarParrot.class,
NorvegianParrot.class,
}, discriminatorProperty = "parrotType")
interface Parrot {
String getParrotType();
String getPlummage();
}
@Schema()
class PolarParrot implements Parrot {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, defaultValue = "polar", example = "polar")
String parrotType;
@Override
public String getParrotType() {
return parrotType;
}
@Override
public String getPlummage() {
return "red";
}
}
@Schema()
class NorvegianParrot implements Parrot {
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, defaultValue = "norvegian", example = "norvegian")
String parrotType;
@Override
public String getParrotType() {
return parrotType;
}
@Override
public String getPlummage() {
return "blue";
}
}
According to docs and examples it appears that anyOf
+ discriminatorProperty
should be enough, yet, when POST-ing a valid payload instead of a deserialized flock
object it throws:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `Parrot`
(no Creators, like default constructor, exist):
abstract types either need to be mapped to concrete types,
have custom deserializer, or contain additional type information
Doesn’t Parrot
contain enough ‘additional type information’ already?
Which essential part did I miss here?
You need to sign in to view this answers