[Bug]: Explicit @Schema(type = "number"|"integer"|"boolean") is emitted as "string" under OpenAPI 3.1
Description of the problem/issue
When generating an OpenAPI 3.1 schema, an explicit @Schema(type = "...") on a property is resolved incorrectly. The scalar type is set correctly on the Schema object, but the types set is populated with ["string"]. Since the 3.1 serializer reads the types set, the property is emitted as type: "string" regardless of the declared type.
- Goal: produce a correct OpenAPI 3.1 document for DTOs that use explicit
@Schema(type = ...). - Annotation misbehaving:
@Schema— an explicittype = "number" | "integer" | "boolean"is emitted as"string". - Correct case: properties relying on type inference (no explicit
typein@Schema) serialize correctly. Only an explicitly declared scalartypeis affected. - Framework: reproduces on plain swagger-core (
ModelConverters+Json31); also observed via springdoc-openapi withspringdoc.api-docs.version=openapi_3_1. - Not examples-related: it reproduces on fields with no
example, so it is distinct from #5061 / #5062 (numeric example serialization). - Downstream: the resulting spec misreports field types, which breaks OpenAPI-based type/client generation (numbers/booleans generated as
string).
Under OpenAPI 3.0 (openapi31 = false) the same DTO serializes correctly, so this is specific to 3.1 generation.
Affected Version
2.2.47
Earliest version the bug appears in (if known): Not fully bisected. Confirmed present in 2.2.47 and still present in 2.2.52 (latest release at time of filing).
Steps to Reproduce
Add a DTO with explicit
@Schema(type = ...)properties and resolve it in OpenAPI 3.1 mode:import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.core.converter.ModelConverters; import io.swagger.v3.core.converter.ResolvedSchema; import io.swagger.v3.core.util.Json31; import io.swagger.v3.oas.annotations.media.Schema; import java.math.BigDecimal; public class Repro { enum Freq { DAY, WEEK, MONTH } static class Dto { @Schema(title = "Inferred") public BigDecimal inferred; // no explicit type (control) @Schema(title = "Amount", type = "number") public BigDecimal amount; @Schema(title = "Count", type = "integer") public Integer count; @Schema(title = "Flag", type = "boolean") public Boolean flag; @Schema(title = "Unit") public Freq unit; // enum (control) } public static void main(String[] args) { ModelConverters converters = new ModelConverters(true); // openapi31 = true ResolvedSchema resolved = converters.resolveAsResolvedSchema(new AnnotatedType(Dto.class)); // root cause: scalar type is correct, but the "types" set is ["string"] resolved.schema.getProperties().forEach((name, s) -> System.out.println(name + " -> getType()=" + s.getType() + " getTypes()=" + s.getTypes())); System.out.println(Json31.pretty(resolved.schema)); } }Resolve with
new ModelConverters(true)(OpenAPI 3.1 mode) and serialize withJson31.Observe the serialized output and inspect the resolved
Schemaobjects.
Expected Behavior
The declared type is preserved:
{
"properties": {
"inferred": { "type": "number" },
"amount": { "type": "number" },
"count": { "type": "integer" },
"flag": { "type": "boolean" },
"unit": { "type": "string", "enum": ["DAY", "WEEK", "MONTH"] }
}
}Actual Behavior
Every property with an explicit scalar type collapses to "string":
{
"properties": {
"inferred": { "type": "number" }, // OK (inferred, control)
"amount": { "type": "string" }, // WRONG, declared "number"
"count": { "type": "string" }, // WRONG, declared "integer"
"flag": { "type": "string" }, // WRONG, declared "boolean"
"unit": { "type": "string", "enum": ["DAY", "WEEK", "MONTH"] } // OK (enum, control)
}
}inferred (inferred type) and unit (enum) serialize correctly — the defect is limited to an explicitly declared scalar type.
Inspecting the resolved (pre-serialization) Schema objects shows the root cause — the scalar type is right, the types set is wrong:
amount -> getType()="number" getTypes()=["string"]
count -> getType()="integer" getTypes()=["string"]
flag -> getType()="boolean" getTypes()=["string"]Logs / Stack Traces
No exception or log output — the schema is generated silently with the wrong type.
Additional Context
- The same DTO serialized under OpenAPI 3.0 (
new ModelConverters(false)) produces correct types, confirming this is a 3.1-generation regression. - Likely related to #4679 (
@Schematype/implementation ignored under OpenAPI 3.1). - Distinct from #5061 / #5062, which concern numeric
exampleserialization; this issue is about the propertytypeand reproduces with noexamplepresent. - Current workaround: a post-processing pass that re-syncs each schema's
typesset to its scalartypeproduces a correct 3.1 document.
Checklist
- I have searched the existing issues and this is not a duplicate.
- I have provided sufficient information for maintainers to reproduce the issue.
Source: swagger-api/swagger-core