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实体类上,直接通过@Schema的additionalProperties属性指定值的类型,同时配合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




