From fecbdf791593d42a5fec0020374c0e135170e055 Mon Sep 17 00:00:00 2001 From: forhadmethun Date: Wed, 15 Jul 2026 13:30:49 +0300 Subject: [PATCH] fix: apply explicit @Schema(type) to the types set under OpenAPI 3.1 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 --- .../v3/core/util/AnnotationsUtils.java | 6 +- .../v3/core/resolving/v31/Ticket5233Test.java | 60 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/Ticket5233Test.java diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java index 7d758f4f10..dd5eb5e3f2 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java @@ -685,7 +685,11 @@ public static Optional getSchemaFromAnnotation( schemaObject.set$ref(schema.ref()); } if (StringUtils.isNotBlank(schema.type())) { - schemaObject.setType(schema.type()); + if (openapi31) { + schemaObject.setTypes(new LinkedHashSet<>(Arrays.asList(schema.type()))); + } else { + schemaObject.setType(schema.type()); + } } if (schema.types().length > 0) { diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/Ticket5233Test.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/Ticket5233Test.java new file mode 100644 index 0000000000..6109d6045b --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/Ticket5233Test.java @@ -0,0 +1,60 @@ +package io.swagger.v3.core.resolving.v31; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverterContextImpl; +import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.resolving.SwaggerTestBase; +import io.swagger.v3.oas.models.media.Schema; +import org.testng.annotations.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +import static org.testng.Assert.assertEquals; + +/** + * An explicit {@code @Schema(type = "number" | "integer" | "boolean")} must be reflected in the + * OpenAPI 3.1 "types" set, not only in the legacy scalar "type" field. Previously the explicit type + * was applied via {@code setType} (scalar) while the "types" set kept the default {@code ["string"]}, + * so the serialized 3.1 schema rendered every explicitly-typed field as {@code string}. + */ +public class Ticket5233Test extends SwaggerTestBase { + + @Test + public void testExplicitSchemaTypeIsAppliedToTypesSetUnderOpenApi31() { + final ModelResolver modelResolver = new ModelResolver(mapper()).openapi31(true); + final ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver); + final Schema model = context.resolve(new AnnotatedType(Model.class)); + + final Map properties = model.getProperties(); + assertEquals(properties.get("amount").getTypes(), Collections.singleton("number")); + assertEquals(properties.get("count").getTypes(), Collections.singleton("integer")); + assertEquals(properties.get("flag").getTypes(), Collections.singleton("boolean")); + + // controls: inferred type and enum are unaffected + assertEquals(properties.get("inferred").getTypes(), Collections.singleton("number")); + assertEquals(properties.get("unit").getTypes(), Collections.singleton("string")); + assertEquals(properties.get("unit").getEnum(), Arrays.asList("DAY", "WEEK", "MONTH")); + } + + enum Freq {DAY, WEEK, MONTH} + + private static class Model { + @io.swagger.v3.oas.annotations.media.Schema(title = "Inferred") + public BigDecimal inferred; + + @io.swagger.v3.oas.annotations.media.Schema(title = "Amount", type = "number") + public BigDecimal amount; + + @io.swagger.v3.oas.annotations.media.Schema(title = "Count", type = "integer") + public Integer count; + + @io.swagger.v3.oas.annotations.media.Schema(title = "Flag", type = "boolean") + public Boolean flag; + + @io.swagger.v3.oas.annotations.media.Schema(title = "Unit") + public Freq unit; + } +}