Skip to content

Fix :@Schema(type) emitting wrong type under OpenAPI 3.1 and ALL_OF sibling modes (#5233, #5235) - #5304

Open
ewaostrowska wants to merge 8 commits into
masterfrom
issue-type
Open

Fix :@Schema(type) emitting wrong type under OpenAPI 3.1 and ALL_OF sibling modes (#5233, #5235) #5304
ewaostrowska wants to merge 8 commits into
masterfrom
issue-type

Conversation

@ewaostrowska

@ewaostrowska ewaostrowska commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Pull Request

Description

In OpenAPI 3.1 mode, properties annotated with @Schema(type = "number" | "integer" | "boolean") were serialized as type: "string" instead of the declared type. The same bug appeared in OAS 3.0 ALL_OF / ALL_OF_REF sibling resolution modes.

Fixes: #5233
Fixes: #5235

What was broken

Issue #5233: OAS 3.1 scalar type lands in types as ["string"]

AnnotationsUtils.getSchemaFromAnnotation called schemaObject.setType(schema.type()) in OAS 3.1 mode. That set the legacy type field correctly, but a separate path populated types from type inference and produced ["string"]. Because the OAS 3.1 serializer reads types, not type, the explicit scalar was silently discarded.

// Before: @Schema(type = "number") on BigDecimal field, openapi31=true
// getType()  = "number"    <- correct but ignored by 3.1 serializer
// getTypes() = ["string"]  <- wrong, used by 3.1 serializer -> emits "string"

// After:
// getType()  = null
// getTypes() = ["number"]  ✓

Issue #5235: ALL_OF sibling mode — ctxSchema.type().getClass() always returns String.class

In ddTypeWhenSiblingsAllowed, the branch for an explicit @Schema(type) called aType.setType(ctxSchema.type().getClass()). String#getClass() always returns String.class regardless of the annotation value, so "number", "integer", and "boolean" all resolved to String type.

// Before
aType.setType(ctxSchema.type().getClass());  // always String.class

// After
Type schemaType = getSchemaType(ctxSchema, true);
if (schemaType != null) {
    aType.setType(schemaType);               // correct type ✓
}

What changed

AnnotationsUtils.getSchemaFromAnnotation: when openapi31=true and no implementation is set, now calls schemaObject.setTypes(singleton(schema.type())) instead of setType(schema.type()), so the 3.1 serializer reads the correct type from the types set. The OAS 3.0 path is unchanged.

AnnotationsUtils.ddTypeWhenSiblingsAllowed: replaces ctxSchema.type().getClass() with getSchemaType(ctxSchema, true) (the existing helper that maps annotation type strings to Java Type objects), guarded by a null check.


Scope

Two related issues are out of scope and tracked separately in #5240:

  • Integer-related formats (int32, int64, etc.) are not handled when @Schema(type) overrides the inferred type.
  • Enum and $ref leakage when the resolved type is string or ["string", "null"]: extra enum values or unintended $ref entries can appear alongside the scalar type.

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

ewaostrowska and others added 8 commits August 31, 2026 09:13
Under OpenAPI 3.1 an explicit @Schema(type = ...) was applied via the legacy
scalar setType(), while the 3.1 serializer reads the types set. The set kept its
default ("string"), so number/integer/boolean fields were rendered as string.
Populate the types set when openapi31 is enabled, mirroring the handling of the
plural types() attribute directly below.

Fixes #5233
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant