Skip to content

Add swagger-annotations(-jakarta) to springdoc-openapi-bom for annotation-only consumers #3325

Description

@rearl

Is your feature request related to a problem? Please describe.

We have a multi-module Maven build. Some modules depend on
springdoc-openapi-starter-webmvc-ui and correctly receive the Swagger
annotations transitively at the matching version — no action needed there.

Other modules only put Swagger annotations (@Schema, @Operation, …) on their
DTOs/controllers but do not depend on springdoc at all. They still need
io.swagger.core.v3:swagger-annotations-jakarta on the compile classpath, and
its version must match the swagger-core version that springdoc pulls in
elsewhere, otherwise we risk mixing annotation versions across the application.

Today, because springdoc-openapi-bom does not manage any Swagger artifact,
the only way to keep these modules in sync is to hardcode the version in our
own POM and remember to bump it manually on every springdoc upgrade (we even
have to disable Renovate for these artifacts to prevent drift). A BOM-managed
entry would let these modules declare swagger-annotations-jakarta without a
version
and stay automatically in lockstep with springdoc.

This is a follow-up to #3212 ("Add swagger version to BOM"), which was closed
with the recommendation to override swagger-core-jakarta before importing the
BOM. That workaround does not cover this use case (details under Alternatives
and Additional context). The use case sounds similar to #2044.

What is the actual result using OpenAPI Description (yml or json)? — Not
applicable: this is a build / dependency-management concern (Maven & Gradle
version alignment), not about the generated OpenAPI description output.

Describe the solution you'd like

Add the Swagger annotation artifact — and optionally swagger-core-jakarta /
swagger-models-jakarta — to springdoc-openapi-bom's <dependencyManagement>,
versioned via the existing swagger-api.version:

<dependency>
    <groupId>io.swagger.core.v3</groupId>
    <artifactId>swagger-annotations-jakarta</artifactId>
    <version>${swagger-api.version}</version>
</dependency>
<!-- optionally swagger-core-jakarta / swagger-models-jakarta as well -->

This lets any consumer that already imports springdoc-openapi-bom declare
swagger-annotations-jakarta without a version and stay in lockstep with the
springdoc release — exactly what a BOM is for — without dragging in
swagger-core or a second Jackson version.

If a managed entry on the existing BOM is genuinely undesirable, the "separate
parent/BOM project" mentioned in #3212 would work just as well for us — the
essential ask is simply a published, version-managed coordinate for the
annotations artifact tied to the springdoc release
.

What is the expected result using OpenAPI Description (yml or json)? — Not
applicable (same reason as above); the generated OpenAPI output is unchanged.

Describe alternatives you've considered

  1. Manually pinning the annotation version and disabling Renovate for it
    (our current approach): works, but is error-prone on every springdoc bump.

  2. The Add swagger version to BOM #3212 workaround — declaring swagger-core-jakarta with
    ${swagger-api.version} before the BOM import:

    <dependency>
        <groupId>io.swagger.core.v3</groupId>
        <artifactId>swagger-core-jakarta</artifactId>
        <version>${swagger-api.version}</version>
    </dependency>

    Two problems for us:

    • It still requires the consumer to define the version: importing
      springdoc-openapi-bom does not make swagger-api.version available
      (BOM import copies <dependencyManagement>, not <properties>), so
      ${swagger-api.version} is unresolved unless we declare it ourselves —
      manual override, not reuse. It also does not work under Gradle, which
      rejects a dependency whose version is an undefined property (as
      @HenrikPublic noted in Add swagger version to BOM #3212).
    • It targets swagger-core-jakarta, which is far more than annotation-only
      modules need — it pulls ~13 transitive dependencies including a
      Jackson 2.x stack, whereas our modules run on Jackson 3.
  3. Importing the springdoc-openapi parent pom (instead of the BOM) +
    depending on swagger-core-jakarta: auto-syncs the version, but forces the
    heavy swagger-core transitive tree (incl. Jackson 2.x) onto annotation-only
    modules.

Additional context

Question about the "breaking change" concern from #3212. The request there was
declined with:

Adding this to the existing BOM would be a breaking change, as it would force
users to specify the versions manually.

We'd appreciate clarification, because on the face of it this seems backwards: a
managed <dependencyManagement> entry lets consumers omit the version, not
specify it. Our best guess at the intended meaning is that BOM-managed versions
override transitive resolution in the importing project, so an existing user
who imports springdoc-openapi-bom and resolves a different Swagger version
through another path would see it change, and would then have to add an explicit
override to keep the old one. If that is the concern, could you confirm? For the
Swagger artifacts specifically we'd gently push back: any project using springdoc
already resolves springdoc's Swagger version transitively, so pinning the BOM to
that same version would not change what those users get — it would only help
consumers that currently have no managed version at all.

Test results (springdoc-openapi 3.1.0, swagger-api.version 2.2.52).

  • A — import the BOM, use ${swagger-api.version} without defining it:
    fails; the property is not wired up by the BOM import:

    [ERROR] 'dependencies.dependency.version' for io.swagger.core.v3:swagger-core-jakarta
            must be a valid version but is '${swagger-api.version}'
    
  • B — same, but with swagger-api.version defined by the consumer (2.2.40):
    works, but only because the consumer supplied the number (override, not reuse):

    \- io.swagger.core.v3:swagger-core-jakarta:jar:2.2.40
       +- io.swagger.core.v3:swagger-annotations-jakarta:jar:2.2.40
    
  • C — import the springdoc-openapi parent pom, nothing defined: the
    version flows through automatically (2.2.52), confirming the parent already
    manages this — but it only manages swagger-core-jakarta and pulls its full
    transitive tree:

    \- io.swagger.core.v3:swagger-core-jakarta:jar:2.2.52
       +- io.swagger.core.v3:swagger-annotations-jakarta:jar:2.2.52
    

Environment. spring-boot-starter-parent 4.1.0; springdoc-openapi 3.1.0 (swagger-api.version = 2.2.52); Maven 3.9.x.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions