You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

springdoc-openapi生成的OAS文档缺失additionalProperties配置问题及替代方案咨询

springdoc-openapi生成的OAS文档缺失additionalProperties配置问题及替代方案咨询

你好呀!针对你遇到的springdoc-openapi生成OAS文档时缺失additionalProperties的问题,我来帮你梳理下可能的原因、解决办法,还有合适的替代方案:

一、为什么springdoc没生成additionalProperties

springdoc-openapi默认对实体类的解析逻辑中,对于既有固定字段(比如你的timestamp)又包含动态键值对的类,不会自动识别并映射到OpenAPI的additionalProperties配置上——除非你通过注解或者自定义配置明确告知它。而你用openapi-generator能生成正确的Map<String, Schema2>,是因为代码生成工具直接遵循了OAS的原始定义,但springdoc是从Java代码反向生成OAS,所以需要额外的提示。

二、修复additionalProperties显示的办法

1. 用@Schema注解手动声明(最推荐)

在你的Schema1实体类上,直接通过@SchemaadditionalProperties属性指定值的类型,同时配合Jackson的@JsonAnyGetter@JsonAnySetter来实现动态属性的序列化/反序列化,这样springdoc就能准确解析并生成对应的OAS配置了。

示例代码:

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;

@Schema(additionalProperties = @Schema(implementation = Schema2.class))
public class Schema1 {
    private OffsetDateTime timestamp;

    // 存储额外属性的Map
    private final Map<String, Schema2> dynamicProperties = new HashMap<>();

    // 固定字段的getter/setter
    public OffsetDateTime getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(OffsetDateTime timestamp) {
        this.timestamp = timestamp;
    }

    // 动态属性的Jackson注解
    @JsonAnyGetter
    public Map<String, Schema2> getDynamicProperties() {
        return dynamicProperties;
    }

    @JsonAnySetter
    public void setDynamicProperty(String key, Schema2 value) {
        this.dynamicProperties.put(key, value);
    }
}

配置后,springdoc生成的/v3/api-docs里就会包含additionalProperties的引用了。

2. 升级springdoc版本+检查序列化配置

如果你的springdoc-openapi版本比较旧,可能存在解析混合实体(固定字段+Map)的bug,建议升级到最新的稳定版试试。另外,确保Jackson的序列化配置没有禁用相关的动态属性解析。

3. 自定义OpenApiCustomiser手动添加配置

如果无法修改实体类注解(比如类来自第三方jar),可以通过OpenApiCustomiser在OAS文档生成后,手动给Schema1追加additionalProperties配置:

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Schema;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OpenApiConfig {
    @Bean
    public OpenApiCustomiser additionalPropertiesCustomiser() {
        return openApi -> {
            Schema<?> schema1 = openApi.getComponents().getSchemas().get("Schema1");
            if (schema1 != null) {
                // 手动指定additionalProperties引用Schema2
                schema1.setAdditionalProperties(new Schema<>().$ref("#/components/schemas/Schema2"));
            }
        };
    }
}

三、additionalProperties的替代方案

其实additionalProperties是OpenAPI规范中专门用来定义“固定结构+动态键值对”场景的标准方式,如果你想换一种实现,也可以考虑:

  • patternProperties:如果你的动态键需要符合特定正则规则,可以用patternProperties替代,比如允许键为字母数字:
    Schema1:
      type: object
      properties:
        timestamp:
          type: string
          format: date-time
      patternProperties:
        "^[a-zA-Z0-9]+$":
          $ref: "#/components/schemas/Schema2"
    
    但如果不需要键的规则限制,additionalProperties依然是最优选择。
  • 让实体类继承HashMap:让Schema1继承HashMap<String, Schema2>,然后添加固定字段,但这种方式需要注意Jackson序列化时避免把固定字段当成map的键,需要额外配置@JsonIgnoreProperties或者调整序列化策略,代码可读性不如@JsonAnyGetter/Setter的方式。

总结

最推荐的方案还是通过@Schema(additionalProperties = ...)配合@JsonAnyGetter/Setter的方式,既符合OpenAPI规范,又能让springdoc正确生成文档,同时代码实现清晰易维护。

备注:内容来源于stack exchange,提问作者ferenc

火山引擎 最新活动