DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

springdoc 3.0.3 文档报 Null key,检查 HATEOAS 展开模型

springdoc3.0.3配合swagger-core2.2.47时,HATEOAS/Kotlin复杂模型可能在JsonUnwrapped展开中丢失Schema名称。确认文档properties的null键,恢复兼容依赖而非删字段。

Spring Boot 4 项目的业务接口正常,访问 /v3/api-docs 却失败,异常链落在 OpenAPI 的 schema properties:

JsonMappingException: Null key for a Map not allowed in JSON

如果组合是 springdoc-openapi 3.0.3、swagger-core-jakarta 2.2.47,并且返回类型使用 Spring HATEOAS 的 EntityModel<T>,检查 @JsonUnwrapped 展开模型后是否生成了 null 属性键。尤其要保留 Kotlin 和非简单属性的模型条件;只有 String、int 的简化 Java DTO 不一定能重现。

null键在文档模型里,不一定在业务Map里

异常链可能依次经过 OpenAPI["components"]、Components["schemas"]、某个 EntityModel schema、JsonSchema["properties"],最后到 Map 的 null 键。这个位置说明失败的是文档模型序列化。不要先把所有业务 Map 里的 null 值删掉:Map 的 null 值与 null 键也不是同一件事。

swagger-core 2.2.47 的 handleUnwrapped() 在没有 prefix/suffix 时取内部 properties 的值,再使用各 Schema 的 getName() 作为新映射的键。Schema 的 name 又被排除在 JSON 序列化外;模型经过 JSON 克隆后,嵌套属性的 name 可能丢失。原属性 Map 的键仍存在,却没有在这条展开路径中用回来,最终便可能生成 null 键。

不是每一次 EntityModel 展开都会触发这条路径。先对照真正失败的控制器返回类型、嵌套 DTO 和依赖树,不要因为项目用了 HATEOAS 就统一删除 @JsonUnwrapped。

先恢复已兼容的文档依赖组合

可控制的过渡方式是将 springdoc starter 回退到已验证可用的 3.0.2 组合。3.0.3 的正式 POM 管理 swagger-core-jakarta 2.2.47,3.0.2 管理 2.2.43;若项目又手动覆盖过 swagger 依赖,只改 starter 版本不会必然恢复整套组合。

回退前保留依赖树和锁定结果,检查 Boot、HATEOAS、Kotlin、Jackson 的兼容约束,之后从最终产物确认解析到的版本。这里描述针对该故障的兼容回退,不要求项目长期停留在旧版;采用后续版本时,应在相同复杂模型上确认正式实现与输出,而不是只看版本号变大。

不建议给 Jackson 全局注册一个把 null 键改成空字符串的 serializer。它可能让文档返回200,却把缺少名称的 schema 属性写成无意义字段,甚至产生冲突。类似地,在 OpenApiCustomizer 中直接删掉 null 项,会把本该描述的属性一起删掉,不能作为保持接口文档完整的通用修复。

用真实模型核对文档完整性

验收至少覆盖原来失败的 Kotlin/HATEOAS 返回类型、其中的非简单属性、分页封装,以及同组普通 DTO。除了 /v3/api-docs 返回成功,还要核对展开后的字段名、required、类型、引用和链接信息,确认生成客户端需要的字段没有被悄悄丢弃。

若异常链指向业务 DTO 的其他 Map,或依赖组合不同,应按它自己的键来源继续定位。恢复文档依赖也不能替代业务接口的序列化验收;保留回退差异,确认接口契约和文档生成都符合原要求。