diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java index 8662312474..1cb9e12bbf 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java @@ -1495,59 +1495,54 @@ protected void applyBeanValidatorAnnotations(Schema property, Annotation[] annot } } if (annos.containsKey("javax.validation.constraints.Min")) { - if ("integer".equals(property.getType()) || "number".equals(property.getType())) { + if (isNumberSchema(property)) { Min min = (Min) annos.get("javax.validation.constraints.Min"); property.setMinimum(new BigDecimal(min.value())); } } if (annos.containsKey("javax.validation.constraints.Max")) { - if ("integer".equals(property.getType()) || "number".equals(property.getType())) { + if (isNumberSchema(property)) { Max max = (Max) annos.get("javax.validation.constraints.Max"); property.setMaximum(new BigDecimal(max.value())); } } if (annos.containsKey("javax.validation.constraints.Size")) { Size size = (Size) annos.get("javax.validation.constraints.Size"); - if ("integer".equals(property.getType()) || "number".equals(property.getType())) { + if (isNumberSchema(property)) { property.setMinimum(new BigDecimal(size.min())); property.setMaximum(new BigDecimal(size.max())); - } else if (property instanceof StringSchema) { - StringSchema sp = (StringSchema) property; - sp.minLength(Integer.valueOf(size.min())); - sp.maxLength(Integer.valueOf(size.max())); - } else if (property instanceof ArraySchema) { - ArraySchema sp = (ArraySchema) property; - sp.setMinItems(size.min()); - sp.setMaxItems(size.max()); + } + if (isStringSchema(property)) { + property.setMinLength(Integer.valueOf(size.min())); + property.setMaxLength(Integer.valueOf(size.max())); + } + if (isArraySchema(property)) { + property.setMinItems(size.min()); + property.setMaxItems(size.max()); } } if (annos.containsKey("javax.validation.constraints.DecimalMin")) { DecimalMin min = (DecimalMin) annos.get("javax.validation.constraints.DecimalMin"); - if (property instanceof NumberSchema) { - NumberSchema ap = (NumberSchema) property; - ap.setMinimum(new BigDecimal(min.value())); - ap.setExclusiveMinimum(!min.inclusive()); + if (isNumberSchema(property)) { + property.setMinimum(new BigDecimal(min.value())); + property.setExclusiveMinimum(!min.inclusive()); } } if (annos.containsKey("javax.validation.constraints.DecimalMax")) { DecimalMax max = (DecimalMax) annos.get("javax.validation.constraints.DecimalMax"); - if (property instanceof NumberSchema) { - NumberSchema ap = (NumberSchema) property; - ap.setMaximum(new BigDecimal(max.value())); - ap.setExclusiveMaximum(!max.inclusive()); + if (isNumberSchema(property)) { + property.setMaximum(new BigDecimal(max.value())); + property.setExclusiveMaximum(!max.inclusive()); } } if (annos.containsKey("javax.validation.constraints.Pattern")) { Pattern pattern = (Pattern) annos.get("javax.validation.constraints.Pattern"); - - if (property instanceof StringSchema) { + if (isStringSchema(property)) { property.setPattern(pattern.regexp()); } - - if(property.getItems() != null && property.getItems() instanceof StringSchema) { + if(property.getItems() != null && isStringSchema(property.getItems())) { property.getItems().setPattern(pattern.regexp()); } - } } @@ -3009,6 +3004,18 @@ protected boolean isObjectSchema(Schema schema) { return (schema.getTypes() != null && schema.getTypes().contains("object")) || "object".equals(schema.getType()) || (schema.getType() == null && schema.getProperties() != null && !schema.getProperties().isEmpty()); } + protected boolean isArraySchema(Schema schema){ + return "array".equals(schema.getType()) || (schema.getTypes() != null && schema.getTypes().contains("array")); + } + + protected boolean isStringSchema(Schema schema){ + return "string".equals(schema.getType()) || (schema.getTypes() != null && schema.getTypes().contains("string")); + } + + protected boolean isNumberSchema(Schema schema){ + return "number".equals(schema.getType()) || (schema.getTypes() != null && schema.getTypes().contains("number")) || "integer".equals(schema.getType()) || (schema.getTypes() != null && schema.getTypes().contains("integer")); + } + protected Schema buildRefSchemaIfObject(Schema schema, ModelConverterContext context) { if (schema == null) { return null; diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/ModelResolverOAS31Test.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/ModelResolverOAS31Test.java index 8b5ce8b67a..12e2ca78fc 100644 --- a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/ModelResolverOAS31Test.java +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/v31/ModelResolverOAS31Test.java @@ -2,6 +2,7 @@ import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.core.converter.ModelConverterContextImpl; +import io.swagger.v3.core.converter.ModelConverters; import io.swagger.v3.core.jackson.ModelResolver; import io.swagger.v3.core.matchers.SerializationMatchers; import io.swagger.v3.core.resolving.SwaggerTestBase; @@ -10,10 +11,14 @@ import io.swagger.v3.core.resolving.v31.model.AnnotatedArray; import io.swagger.v3.core.resolving.v31.model.ModelWithDependentSchema; import io.swagger.v3.core.resolving.v31.model.ModelWithOAS31Stuff; -import io.swagger.v3.core.resolving.v31.model.ModelWithOAS31StuffMinimal; -import io.swagger.v3.core.util.Yaml31; import io.swagger.v3.oas.models.media.Schema; import org.testng.annotations.Test; +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; +import java.util.List; +import java.util.Map; public class ModelResolverOAS31Test extends SwaggerTestBase { @@ -231,4 +236,115 @@ public void testFieldArraySchemaAnnotation() { " type: string\n" + " maxItems: 10"); } + + @Test(description = "@Pattern correctly handled in type parameters of properties using collections when using oas 3.1.0") + public void testModelUsingCollectionTypePropertyHandlesPatternAnnotationForOas31() { + String expectedYaml = "ClassWithUsingPatternOnCollection:\n" + + " type: object\n" + + " properties:\n" + + " myField:\n" + + " type: array\n" + + " items:\n" + + " pattern: myPattern\n" + + " type: string"; + + Map stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingPatternOnCollection.class); + SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml); + } + + private static class ClassWithUsingPatternOnCollection { + private List<@Pattern(regexp = "myPattern") String> myField; + + public List getMyField() { + return myField; + } + + public void setMyField(List myField) { + this.myField = myField; + } + } + + @Test(description = "@Size correctly handled in properties using collections when using oas 3.1.0") + public void testModelUsingCollectionTypePropertyHandleSizeAnnotationForOas31() { + String expectedYaml = "ClassWithUsingSizeOnCollection:\n" + + " type: object\n" + + " properties:\n" + + " myField:\n" + + " maxItems: 100\n" + + " minItems: 1\n" + + " type: array\n" + + " items:\n" + + " type: string"; + + Map stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingSizeOnCollection.class); + SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml); + } + + private static class ClassWithUsingSizeOnCollection { + @Size(min = 1, max = 100) + private List myField; + + public List getMyField() { + return myField; + } + + public void setMyField(List myField) { + this.myField = myField; + } + } + + @Test(description = "@Size correctly handled for field type String using OAS 3.1.0") + public void testSizeAnnotationOnFieldForOAS31() { + String expectedYaml = "ClassWithUsingSizeOnField:\n" + + " type: object\n" + + " properties:\n" + + " myField:\n" + + " type: string\n" + + " maxLength: 100\n" + + " minLength: 1"; + + Map stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingSizeOnField.class); + SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml); + } + + private static class ClassWithUsingSizeOnField { + @Size(min = 1, max = 100) + private String myField; + + public String getMyField() { + return myField; + } + + public void setMyField(String myField) { + this.myField = myField; + } + } + + @Test(description = "@DecimalMax/Min annotations correctly handled for field type Number using OAS 3.1.0") + public void testDecimalAnnotationsOnField() { + String expectedYaml = "ClassWithUsingDecimalAnnotationsOnField:\n" + + " type: object\n" + + " properties:\n" + + " myField:\n" + + " type: number\n" + + " maximum: 100\n" + + " minimum: 1"; + + Map stringSchemaMap = ModelConverters.getInstance(true).readAll(ClassWithUsingDecimalAnnotationsOnField.class); + SerializationMatchers.assertEqualsToYaml31(stringSchemaMap, expectedYaml); + } + + private static class ClassWithUsingDecimalAnnotationsOnField { + @DecimalMin("1") + @DecimalMax("100") + private Number myField; + + public Number getMyField() { + return myField; + } + + public void setMyField(Number myField) { + this.myField = myField; + } + } }