Recognize OpenAPI 3.2.x version strings, routed through the 3.1 model path

KH
2mo ago
+236-7

Pull Request

Thank you for contributing to swagger-parser!

Please fill out the following checklist to help us review your PR efficiently.


Description

OpenAPI 3.2 builds on the 3.1 data model. This PR makes swagger-parser recognize
"openapi": "3.2.x" version strings and route them through the existing 3.1-family
code path (deserializer, resolver/dereferencer), instead of rejecting them outright.

This is a narrow, incremental step toward #2248, not a full 3.2 implementation:

  • 3.2-only members (query operation, additionalOperations, $self, in: querystring parameters) are still reported as attribute ... is unexpected /
    is not of type validation messages and are not reproduced in the parsed
    model, so resolved output can differ from a fully 3.2-aware parser. Full support
    needs the model changes proposed in swagger-api/swagger-core#5253 (currently
    awaiting design-question answers from the 2026-07-23 comment on #2248) plus a
    SpecVersion.V32 value -- this change's widening of the openapi31 flag's
    meaning ("3.1-family or later") is a stopgap for that.
  • Dynamic reference resolution ($dynamicRef/$dynamicAnchor) is out of scope
    here, consistent with the note on #2248 that it was the one gap left in both
    reference implementations (scalar's TypeScript PR and Microsoft OpenAPI.NET's
    PR, both linked from that issue).

What this PR actually changes:

  • OpenAPIDeserializer.parseRoot accepts "3.2" as a loose prefix (matching the
    existing convention for "3.0"/"3.1") and sets the openapi31 flag
  • the dotted-form warning check gains "3.2." so a bare "3.2" is accepted but
    reported as not a valid version field, same as bare "3.0"/"3.1"
  • OpenAPIV3Parser.resolve and OpenAPIDereferencer31.canDereference route 3.2
    documents through the 3.1 dereferencer
  • ResolverCache treats 3.2 as openapi31 so the 3.1 (JSON Schema 2020-12)
    Jackson mapper is selected for external-ref deserialization. This is
    load-bearing only for direct OpenAPIResolver callers (public API): the
    internal resolve() path routes 3.1/3.2 through OpenAPIDereferencer31 and
    never constructs a ResolverCache for them
  • canDereference gains a null guard on getOpenapi()

Tests: OAI32DeserializationTest (10 cases) covers 3.2.0/3.2.1 parsing,
unexpected-attribute recording for 3.2-only fields, resolveFully actually
resolving refs, routing through the 3.1 dereferencer via components.pathItems,
bare "3.2" acceptance-with-warning, loose-prefix "3.20.0" acceptance-with-warning
(a prefix-match artifact, not true 3.x support), 3.3.0 genuinely rejected
(contrast with the 3.20.0 case), and malformed "3.2." -- which parses without a
warning, an inherited quirk of the pre-existing convention that this change extends
rather than fixes, asserted explicitly so it doesn't silently drift later.

Relates to: #2248 (does not fully close it -- see scope note above)

Type of Change

  • ๐Ÿ› Bug fix
  • โœจ New feature
  • โ™ป๏ธ Refactor (non-breaking change)
  • ๐Ÿงช Tests
  • ๐Ÿ“ Documentation
  • ๐Ÿงน Chore (build or tooling)

Checklist

  • I have added/updated tests as needed
  • I have added/updated documentation where applicable
  • The PR title is descriptive
  • The code builds and passes tests locally
  • I have linked related issues (if any)

Screenshots / Additional Context

No UI change. Full local mvn test run: 706 tests in swagger-parser-v3, 78 in
swagger-parser-v2-converter, 47 in swagger-parser-safe-url-resolver -- all
passing, zero failures.


๐Ÿค– Generated with Claude Code