Skip to content

OpenAPI 3.2 model support: SpecVersion.V32 platform + $self/Parameter/additionalOperations/MediaType fields - #5326

Open
khayashi4337 wants to merge 16 commits into
swagger-api:masterfrom
khayashi4337:oas32-full-support
Open

khayashi4337 wants to merge 16 commits into
swagger-api:masterfrom
khayashi4337:oas32-full-support

Conversation

@khayashi4337

@khayashi4337 khayashi4337 commented Sep 22, 2026 •

Copy link
Copy Markdown

Status: Ready for review — includes #5253, #5254, #5255

This PR builds on three open PRs from other contributors, and includes their
commits with authorship preserved:

Either order works for me:

  1. Review and merge feat: support the OpenAPI 3.2 QUERY method in PathItem and the JAX-RS reader #5253/test: use SpecVersion enum in tests in preparation for OAS 3.2 #5254/refactor: use SpecVersion enum in ObjectMapperFactory in preparation for OAS 3.2 #5255 first (in whatever form the maintainers
    prefer). I'll then rebase this PR on the merged result and drop the
    duplicate commits.
  2. Review this PR as the combined OAS 3.2 model change.

I've moved it out of draft because the 3.2 model work hasn't had a review yet
(the oldest prerequisite, #5253, was opened 2026-07-24), and draft PRs are easy
to miss. Downstream, swagger-api/swagger-parser#2402 and
OpenAPITools/openapi-generator#24982 are waiting on a swagger-core release that
includes these models.

What this adds (on top of #5253/#5254/#5255)

Working toward full OpenAPI 3.2 model support (tracked in #2248):

  • SpecVersion.V32 and a 3.2 Jackson mapper/gating platform (Json32/
    Yaml32), following the existing 3.0/3.1 mixin pattern. Wires up
    PathItem.query (from feat: support the OpenAPI 3.2 QUERY method in PathItem and the JAX-RS reader #5253) so it's actually serialized for 3.2 documents
    instead of being unconditionally hidden.
  • OpenAPI.$self (root document canonical-URI field)
  • Parameter 3.2 additions: in: querystring (new QueryStringParameter
    type) and style: cookie
  • MediaType/Encoding nested encoding: prefixEncoding, itemEncoding
  • PathItem.additionalOperations (arbitrary-named operations beyond the 8
    fixed HTTP methods), following the minimal-addition option from a design
    memo evaluated separately (kept fixed fields, added a side map — avoids an
    API/serializer redesign that would diverge further from feat: support the OpenAPI 3.2 QUERY method in PathItem and the JAX-RS reader #5253's approach)
  • MediaType.$ref (Reference Object semantics) + Components.mediaTypes
  • Simpler fixed-field additions: Server.name, Tag.summary/parent/kind,
    ApiResponse.summary, Example.dataValue/serializedValue,
    SecurityScheme.deprecated/oauth2MetadataUrl, OAuth device-flow fields,
    XML.nodeType, Discriminator.defaultMapping

Known limitations (disclosed, not blocking this draft)

  • The openapi31 boolean's meaning is widened to "3.1-family or later" as a
    stopgap; once SpecVersion gains more structure upstream this should be
    revisited.
  • 3.2 output is currently only reachable by calling Json32/Yaml32
    directly — SwaggerConfiguration, the jaxrs2 SwaggerSerializers, and the
    Maven/Gradle plugins don't yet select the 3.2 mapper. Wiring that up is a
    separate, larger change.
  • A handful of generators/consumers that call PathItem.readOperationsMap()
    directly (bypassing higher-level traversal) will now also see QUERY as a
    legitimate enum value, which is a natural consequence of feat: support the OpenAPI 3.2 QUERY method in PathItem and the JAX-RS reader #5253 rather than
    something this PR introduces.

Testing

Full reactor mvn clean install: 21 modules, all green. swagger-core
module 842 tests, swagger-jaxrs2 module 232 tests, 0 failures. New coverage
added across OpenAPI3_2SerializationTest, ValidationAnnotationsUtilsTest,
and QueryMethodTest.


🤖 Generated with Claude Code

CommanderGeek and others added 16 commits July 24, 2026 17:42
Add the `query` HTTP method introduced in OpenAPI 3.2 to PathItem:
field, accessors and fluent builder, HttpMethod.QUERY enum constant,
and wiring in readOperations, readOperationsMap, operation(), equals,
hashCode and toString. Adds model tests plus a swagger-core
serialization round-trip.

Refs swagger-api/swagger-parser#2248 (swagger-api/swagger-parser#2248)
  Route the "query" method in Reader.setPathItemOperation onto
  PathItem.query(), and include query operationIds in
  extractOperationIdFromPathItem. Adds QueryMethodTest.
  No new public API: ReaderUtils.getHttpMethodFromCustomAnnotations
  already resolves any @HttpMethod-meta-annotated annotation, so an
  application's own @query binding maps with no further support. The
  @query here is a test fixture standing in for that binding
  Refs swagger-api/swagger-parser#2248 (swagger-api/swagger-parser#2248)
…athItem.query for 3.2

Builds on the SpecVersion-based mapper selection introduced by cherry-picked
upstream PRs swagger-api#5255 (ObjectMapperFactory refactor) and
swagger-api#5254 (test refactor), and on the PathItem.query model
from CommanderGeek's swagger-api#5253.

- SpecVersion.V32 added to io.swagger.v3.oas.models.SpecVersion
- ObjectMapperFactory: case V32 shares the 3.1 serializer modifier
  (Schema31Serializer/MediaTypeSerializer/ExampleSerializer), the 3.1 mixin
  set, and registers DeserializationModule32; PathItem gets PathItem32Mixin
  (query not ignored) while 3.0/3.1 keep PathItemMixin (@JsonIgnore query).
  All three specVersion switches now throw on unknown versions, matching
  SpecVersionMappers
- New Json32/Yaml32 utility classes and createJson32/createYaml32 factories
- Deserializer family: protected boolean openapi31 kept (deprecated) for
  subclass compatibility; version now flows through overridable specVersion()
  + mapper() (SpecVersionMappers resolves Json/Json31/Json32 singletons)
- New *32Deserializer variants (Paths/Callback/ApiResponses/Parameter/
  SecurityScheme/Model) + OpenAPI32Deserializer setting specVersion V32;
  DeserializationModule32 wires them
- ModelDeserializer: inner JsonSchema conversions now use mapper() so the
  ambient version propagates (previously hardcoded to the 3.1 mapper; needed
  for V32, no behavior change for 3.0/3.1 documents)
- Existing "3.1 or later" version predicates widened to cover V32, using the
  codebase's != V30 convention: OpenAPI.toString (webhooks/
  jsonSchemaDialect), Schema.toString (3.1 JSON Schema keywords),
  ValidationAnnotationsUtils.applyDecimal{Min,Max}Constraint

Tests: OpenAPI3_2SerializationTest (12 tests) verifies query round-trips in
3.2 JSON and YAML, stays hidden in 3.0/3.1, binds in nested PathItems
(webhooks/components.pathItems/callbacks), the V32 deserializer family binds
parameters/responses/schemas/securitySchemes, and toString prints
webhooks/jsonSchemaDialect for V32 but not V30.
Full reactor: mvn clean install, 21 modules, all tests pass.
Adds the fixed fields introduced by OpenAPI 3.2 to the model, serialized
and deserialized only under SpecVersion.V32:

- Server.name
- Tag.summary, Tag.parent, Tag.kind
- ApiResponse.summary
- Example.dataValue, Example.serializedValue (with dataValueSetFlag,
  mirroring valueSetFlag so an explicit null dataValue can be emitted)
- MediaType.itemSchema
- SecurityScheme.deprecated, SecurityScheme.oauth2MetadataUrl
- OAuthFlows.deviceAuthorization and OAuthFlow.deviceAuthorizationUrl
- XML.nodeType
- Discriminator.defaultMapping

A new @OpenAPI32 marker annotation documents the new accessors, matching
the existing @OpenAPI30/@OpenAPI31 convention. Fields deprecated by the
3.2 specification (Example.value, XML.attribute, XML.wrapped) are kept
without @deprecated since they remain valid for 3.0/3.1 documents;
mutual-exclusion rules are documented in javadoc only.

Version gating follows the existing mixin pattern: new *30Mixin classes
hide the 3.2 fields for the V30 and V31 mappers (registered for both
cases, as DateSchemaMixin already is), while V32 keeps the regular
mixin. Discriminator gains a dedicated Discriminator32Mixin since the
31 mixin is shared with V32 today. SecuritySchemeDeserializer parses
deprecated/oauth2MetadataUrl only when specVersion() == V32.
OpenAPI.$self declares the canonical URI of the root document (OpenAPI
3.2). Serialized/deserialized only under V32 via the new OpenAPI32Mixin;
OpenAPIMixin and OpenAPI31Mixin ignore it so 3.0/3.1 output and parsing
are unchanged.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add ParameterIn.QUERYSTRING annotation enum value and
Parameter.StyleEnum.COOKIE. New QueryStringParameter model binds
in: querystring under the V32 deserializer only; earlier versions
keep the existing unknown-in behavior (null). Semantic constraints
(content required, no schema/style/explode/allowReserved, uniqueness)
are documented on the model and left to parser-side validation,
consistent with the lenient model convention.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
MediaType gains prefixEncoding (list) and itemEncoding; Encoding gains
nested encoding map plus prefixEncoding and itemEncoding for recursion.
All gated to V32: MediaType30Mixin hides the new MediaType fields and a
new Encoding30Mixin hides the new Encoding fields for 3.0/3.1 output and
parsing (and the V30-style converter mapper). Mutual-exclusion rules
with 'encoding' are documented on the model; enforcement is parser-side.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
PathItem gains additionalOperations, a Map<String, Operation> for HTTP
methods beyond the fixed fields (minimal approach per the design memo:
fixed fields stay, no internal map rework). Keys keep original case for
round-trip; duplicate fixed-method keys are kept leniently with
enforcement left to parser-side validation. readOperations() now
includes the additional operations so existing traversal picks them up.
Hidden from 3.0/3.1 (and the converter mapper) via PathItemMixin.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
OpenAPI 3.2 allows content-related maps (Parameter/Header/RequestBody/
ApiResponse content) to hold Reference Objects, and adds a reusable
Components.mediaTypes map. MediaType gains a '$ref' property (minimum-change
approach: Content stays Map<String,MediaType>) and Components gains
'mediaTypes'.

V30/V31/converter mappers hide both via MediaType30Mixin, ComponentsMixin and
Components31Mixin; a new Components32Mixin exposes mediaTypes for 3.2.
SpecFilter now copies mediaTypes and collects schema refs inside mediaTypes
entries and itemSchema so unreferenced pruning keeps needed schemas.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- SpecFilter clones component schemas with the document's version
  (Json32 for 3.2) instead of always 3.0/3.1, and collects
  discriminator.defaultMapping references during unreferenced pruning
- MediaType $ref no longer masks sibling schema/itemSchema/encoding
  references during pruning, fixing a pre-3.2 regression
- style: cookie is rejected by pre-3.2 serializers like it already is
  by pre-3.2 deserializers
- jaxrs2 Reader routes custom HTTP methods to additionalOperations
  preserving declared case, matches fixed methods case-insensitively,
  and gates in: querystring on OpenAPI 3.2 through the whole annotation
  processing chain

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@Mattias-Sehlstedt

Copy link
Copy Markdown
Contributor

For the Tags changes I also have master...Mattias-Sehlstedt:swagger-core:support-oas-32-tags since before, which should basically be a full implementation (but not rebased). But I have not done a PR or similar for it since I am waiting on swagger-core to inform us of how they want to handle the openapi31 boolean and how to harmonize the OAS versioning in general (now different components handle it very differently).

@khayashi4337

Copy link
Copy Markdown
Author

Thanks for the heads up @Mattias-Sehlstedt, good to know the Tags work exists.

I'm in the same boat on the openapi31 boolean / versioning question -- this PR hasn't had maintainer input yet either, so I don't have a stronger answer than you do on how they want to harmonize it. If your Tags branch is otherwise in reasonable shape, I'd lean toward opening it as a PR anyway (even as a draft) so the maintainers have something concrete to react to when they do pick this up -- easier to discuss against real code than against a comparison link. Happy to coordinate once there's more signal from their side.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants