You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringDoc/Swagger继承场景下必填属性的正确配置问询

解决SpringDoc中DTO子类必填属性在OpenAPI中位置错误的问题

问题原因

SpringDoc默认会将父类和子类的@NotNull注解对应的必填属性,合并到OpenAPI Schema的根节点required数组中,而非子类对应的allOf子对象内,导致TypeScript客户端生成工具(如orval)无法正确识别子类的必填属性。

解决方案

1. 为子类属性显式添加@Schema(requiredMode = REQUIRED)

直接在子类的必填属性上添加该注解,强制SpringDoc将该属性的必填标记绑定到子类对应的Schema中:

public class ParentDto {
    @NotNull
    private String parentProp;

    // getter/setter
}

public class ChildADto extends ParentDto {
    @NotNull
    @Schema(requiredMode = Schema.RequiredMode.REQUIRED)
    private String childAProp;

    // getter/setter
}

这种方式简单直接,适合单个子类或少量属性的场景。

2. 全局配置自定义ModelConverter

如果有大量子类需要处理,可以实现ModelConverter来调整继承关系下的必填属性位置:

import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverterContext;
import io.swagger.v3.oas.models.media.Schema;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

@Component
public class InheritanceRequiredFixer implements ModelConverter {
    @Override
    public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) {
        Schema schema = chain.next().resolve(type, context, chain);
        if (schema != null && schema.getAllOf() != null && !schema.getAllOf().isEmpty()) {
            // 提取根节点的required属性,清空根节点的required
            List<String> rootRequired = new ArrayList<>(schema.getRequired() != null ? schema.getRequired() : Collections.emptyList());
            schema.setRequired(new ArrayList<>());

            // 将父类的必填属性绑定到第一个allOf节点(对应父类Schema)
            if (!rootRequired.isEmpty()) {
                Schema parentSchema = schema.getAllOf().get(0);
                parentSchema.setRequired(rootRequired);
            }
        }
        return schema;
    }
}

这个转换器会自动将根节点的required属性移到父类对应的allOf子节点中,子类的必填属性则会保留在自身的Schema片段里。

3. 改用OpenAPI的allOf注解声明继承(替代Java继承)

如果允许调整DTO的结构,可以不用Java的extends,而是用@Schema(allOf = ParentDto.class)来声明继承关系,这样子类的属性和必填项会被单独放在对应的Schema中:

public class ParentDto {
    @NotNull
    private String parentProp;

    // getter/setter
}

@Schema(allOf = ParentDto.class)
public class ChildADto {
    @NotNull
    private String childAProp;

    // getter/setter
}

这种方式会让OpenAPI的结构更清晰,子类的required属性不会和父类的合并到根节点,但需要手动处理父类属性的传递(比如通过构造器或工具类复制)。

验证

调整后重新生成OpenAPI JSON,检查子类的必填属性是否出现在allOf对应的子对象的required数组中,而非根节点。此时用orval生成的TypeScript客户端就能正确识别子类的必填属性。

内容的提问来源于stack exchange,提问作者Xavier Portebois

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:30:24