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

如何通过Java的@Schema注解生成支持null的OpenAPI引用对象?

解决Swagger中通过注解让引用字段支持null值的问题

问题场景

现有Java类结构如下:

public class User {
  private int age;
  private Address address;
}
public class Address {
  private String city;
}

希望address字段支持三种客户端请求场景:完全省略字段、传入空对象"address": {}、传入"address": null,但遇到以下问题:

  • 未加任何注解时,生成的Swagger中address仅包含对Address的$ref,不支持null值
  • 给address字段添加@Schema(nullable=true)时,该配置会被$ref覆盖,无法生效
  • 已知直接修改Swagger可以用anyOf结合type: null和$ref实现需求,但@Schema的anyOf属性仅支持指定类,无法直接生成type: null的规则
  • 由于Address类结构复杂且为多API共享,不想直接在Address类上添加@Schema(nullable=true)

可行解决方案

方案1:自定义ModelConverter扩展(推荐)

swagger-core允许通过自定义ModelConverter来修改生成的OpenAPI Schema,无需修改共享类即可为指定字段添加anyOf包含null的规则。

自定义Converter代码

import io.swagger.v3.core.converter.ModelConverter;
import io.swagger.v3.core.converter.ModelConverterContext;
import io.swagger.v3.oas.models.media.Schema;
import java.lang.reflect.Type;
import java.util.Iterator;

public class NullableRefModelConverter implements ModelConverter {
    @Override
    public Schema resolve(Type type, ModelConverterContext context, Iterator<ModelConverter> chain) {
        Schema schema = chain.next().resolve(type, context, chain);
        // 根据当前字段名和引用目标判断是否需要处理(示例针对User类的address字段)
        if (schema != null && schema.get$ref() != null) {
            String refPath = schema.get$ref();
            String currentField = context.getCurrentPropertyName();
            if (refPath.contains("Address") && "address".equals(currentField)) {
                // 创建null类型的Schema
                Schema nullSchema = new Schema();
                nullSchema.setType("null");
                // 为当前字段设置anyOf,包含null和原引用类型
                schema.setAnyOf(java.util.List.of(nullSchema, new Schema().$ref(refPath)));
                // 移除原$ref,避免冲突
                schema.set$ref(null);
            }
        }
        return schema;
    }
}

注册Converter

在应用启动时注册自定义Converter:

import io.swagger.v3.core.converter.ModelConverters;

// 启动初始化逻辑中添加
ModelConverters.getInstance().addConverter(new NullableRefModelConverter());

生成的Swagger中address字段会变为:

"address": {
  "anyOf": [
    { "type": "null" },
    { "$ref": "#/components/schemas/Address" }
  ]
}

方案2:使用自定义包装类(略繁琐)

创建一个标记了anyOf的包装类:

@Schema(anyOf = {Address.class, Void.class})
public class NullableAddress {}

修改User类的address字段类型为NullableAddress:

public class User {
  private int age;
  private NullableAddress address;
}

该方案需要修改User类的字段类型,适合字段规则仅在少数场景使用的情况。

方案3:API级别单独配置(局部场景)

如果仅个别API需要该规则,可以在接口方法的@RequestBody中直接指定Schema:

@PostMapping("/users")
public ResponseEntity<User> createUser(
    @RequestBody @Schema(
        properties = {
            @SchemaProperty(name = "age", type = "integer"),
            @SchemaProperty(name = "address", anyOf = {
                @Schema(type = "null"),
                @Schema(ref = "#/components/schemas/Address")
            })
        }
    ) User user
) {
    // 业务逻辑处理
}

该方式无需修改实体类,但需要在每个目标API上单独配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 00:53:14