Files
asmhatreandClaude Sonnet 5 8d0efb0d4b Add openapi-versioning: springdoc-openapi 3.1.1 vs Spring Framework 7 API versioning
Companion module for "springdoc-openapi with Spring Boot 4.1: Generating,
Customising and Versioning Your API Spec". Reuses the ApiVersionConfigurer
setup from the versioning-mechanics companion project and tests what
springdoc-openapi 3.1.1 actually generates for a path with multiple
version-scoped handlers: a default oneOf-merged operation with an
arbitrary operationId, a working GroupedOpenApi + OpenApiCustomizer fix
that collapses it to one clean schema per version, and a check of the
officially-versioning-supported functional-endpoint path (springdoc
v3.0.2's "Add support for Spring Framework API Versioning with Functional
Endpoints"), which turns out to document only one of two registered
versions rather than either version separately.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01M1uZDXWkY1MnTfQgt4HMeQ
2026-09-17 19:31:42 +00:00

35 lines
2.3 KiB
Markdown

# Why the version→schema map in the fix is hand-maintained
[`VersionedOpenApiConfig`](../src/main/java/com/ankurm/openapiversioning/config/VersionedOpenApiConfig.java)
keeps a small, explicit `Map<String, VersionSpec>` from version string to schema name /
operationId / summary, rather than deriving that mapping automatically from the running
application. This is a deliberate limitation, not an oversight, and it's worth being honest about
why: an `OpenApiCustomizer` (`org.springdoc.core.customizers.OpenApiCustomizer`) receives exactly
one argument, the fully-built `io.swagger.v3.oas.models.OpenAPI` document — see
`javap org/springdoc/core/customizers/OpenApiCustomizer.class`:
```
public interface org.springdoc.core.customizers.OpenApiCustomizer {
public abstract void customise(io.swagger.v3.oas.models.OpenAPI);
}
```
By the time a customizer runs, springdoc has already folded the three `HandlerMethod`s into one
merged `Operation` (see the previous chapter) — the association between "this specific handler
method" and "this specific version string" has already been discarded. An `OperationCustomizer`
(`org.springdoc.core.customizers.OperationCustomizer`) does get a `HandlerMethod` argument per
call, which looks more promising, but it still runs once per merged operation, not once per
original handler — it cannot see the three original mappings separately either, because springdoc
folds first and customizes second. There is no supported extension point in 3.1.1 that intercepts
before the fold.
Reflectively pulling the `version` condition back out of Spring's own `RequestMappingInfo` (via
`RequestMappingHandlerMapping.getHandlerMethods()`) would work at the Spring MVC layer — Framework
7 exposes it there in principle — but wiring that into springdoc's generation pipeline means
matching springdoc's internal notion of "this operation" back to Spring's `RequestMappingInfo` by
path and method, which is exactly the kind of implementation-detail-coupled reflection that breaks
silently on the next springdoc minor version. A hand-maintained map keyed by the version strings
you already wrote in your own `@GetMapping(version = ...)` annotations is three lines of
boilerplate per version and it does not break when springdoc changes how it folds operations
internally.