如何为使用Jackson接口多态的请求体字段配置Springdoc Schema
如何为使用Jackson接口多态的请求体字段配置Springdoc Schema
我之前在项目里要实现Jackson多态请求体的Swagger文档展示,踩了好几个坑,现在把我整理的可行方案分享给你。首先先看看我用的相关依赖配置(build.gradle里的),这些版本搭配起来稳定性不错:
implementation("org.springframework.boot:spring-boot-starter-web:2.7.18") implementation("org.springdoc:springdoc-openapi-ui:1.8.0") { exclude(group = "org.slf4j", module = "slf4j-api") } implementation("org.springdoc:springdoc-openapi-webmvc-core:1.8.0") { exclude(group = "org.slf4j", module = "slf4j-api") }
之所以排除slf4j-api,是因为Spring Boot的starter已经自带了这个依赖,不排除的话容易出现版本冲突问题。
1. 先配置Jackson的多态注解
首先得给你的父接口/类加上Jackson的多态识别注解,这样Jackson才能根据指定的字段区分不同的子类型。举个实际的例子,比如我定义了一个Animal父接口,还有Cat和Dog两个子类:
@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" // 这个字段用来区分子类型,前端传参时要带上 ) @JsonSubTypes({ @JsonSubTypes.Type(value = Cat.class, name = "cat"), @JsonSubTypes.Type(value = Dog.class, name = "dog") }) public interface Animal { String getSound(); } public class Cat implements Animal { private String sound = "meow"; private String favoriteToy; // Cat特有的字段 // 这里记得加getter和setter,或者用Lombok的@Data注解 } public class Dog implements Animal { private String sound = "woof"; private Boolean isGuardDog; // Dog特有的字段 // getter和setter }
2. 配置Springdoc识别多态Schema
这一步是关键,要让Springdoc生成的Swagger文档里能正确展示多态类型的可选结构,以及区分用的type字段。有三种常用方式,你可以按需选:
方式一:在Controller的请求体参数上直接指定
这种方式适合单个接口的场景,直接在@RequestBody参数上用@Schema的oneOf属性指定所有子类型:
@PostMapping("/pets") public ResponseEntity<String> addPet( @RequestBody @Schema(oneOf = {Cat.class, Dog.class}) Animal animal ) { // 这里写你的业务逻辑,比如存数据库或者处理请求 return ResponseEntity.ok("Added pet that says: " + animal.getSound()); }
方式二:全局配置(用OpenApiCustomizer)
如果你的项目里有很多地方用到这个多态类型,不想每个Controller都写一遍,可以用全局配置类来统一注册:
@Configuration public class SpringdocPolymorphismConfig { @Bean public OpenApiCustomizer openApiCustomizer() { return openApi -> { // 先拿到父类型的Schema Schema<?> animalSchema = openApi.getComponents().getSchemas().get("Animal"); if (animalSchema != null) { // 设置oneOf属性,指定所有子类型的引用 animalSchema.setOneOf(List.of( new Schema().$ref("#/components/schemas/Cat"), new Schema().$ref("#/components/schemas/Dog") )); // 配置discriminator,对应Jackson里的type字段 Discriminator discriminator = new Discriminator() .propertyName("type") .mapping(Map.of( "cat", "#/components/schemas/Cat", "dog", "#/components/schemas/Dog" )); animalSchema.setDiscriminator(discriminator); } }; } }
方式三:直接在父接口上添加@Schema注解
这种方式最直观,把多态的Schema配置直接和Jackson的注解放在一起,维护起来更方便:
@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type" ) @JsonSubTypes({ @JsonSubTypes.Type(value = Cat.class, name = "cat"), @JsonSubTypes.Type(value = Dog.class, name = "dog") }) @Schema( oneOf = {Cat.class, Dog.class}, discriminator = @Discriminator( propertyName = "type", mapping = { @DiscriminatorMapping(value = "cat", schema = Cat.class), @DiscriminatorMapping(value = "dog", schema = Dog.class) } ) ) public interface Animal { String getSound(); }
最后提几个要注意的点
- 一定要保证Spring Boot和Springdoc的版本兼容,我用的2.7.18的Spring Boot搭配1.8.0的Springdoc是经过验证没问题的,如果用更高版本的Spring Boot(比如3.x),要对应升级Springdoc到2.x版本
- 排除
slf4j-api是为了避免依赖冲突,如果你项目里的日志依赖版本和Springdoc自带的不一样,很可能会出问题 - 测试的时候记得打开Swagger UI(默认地址是
/swagger-ui.html),看看请求体的Schema是不是正确展示了所有子类型的字段,以及type下拉选项
内容来源于stack exchange
相关产品推荐
相关产品推荐

