diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java index 843455e7d3..5fd0882073 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.type.TypeFactory; import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter.DefaultValidationAnnotationFilter; import io.swagger.v3.core.util.Json; import io.swagger.v3.core.util.Json31; import io.swagger.v3.oas.models.media.Schema; @@ -51,6 +53,16 @@ public ModelConverters(boolean openapi31, Schema.SchemaResolution schemaResoluti } } + public ModelConverters(boolean openapi31, Schema.SchemaResolution schemaResolution, ValidationAnnotationFilter validationAnnotationFilter) { + converters = new CopyOnWriteArrayList<>(); + if (openapi31) { + converters.add(new ModelResolver(Json31.mapper()).openapi31(true).schemaResolution(schemaResolution).validationAnnotationFilter(validationAnnotationFilter)); + } else { + converters.add(new ModelResolver(Json.mapper()).schemaResolution(schemaResolution).validationAnnotationFilter(validationAnnotationFilter)); + } + } + + public Set getSkippedPackages() { return skippedPackages; } @@ -78,17 +90,21 @@ public static void reset() { } public static ModelConverters getInstance(boolean openapi31, Schema.SchemaResolution schemaResolution) { + return getInstance(openapi31, schemaResolution, new DefaultValidationAnnotationFilter()); + } + + public static ModelConverters getInstance(boolean openapi31, Schema.SchemaResolution schemaResolution, ValidationAnnotationFilter validationAnnotationFilter) { synchronized (ModelConverters.class) { if (openapi31) { if (SINGLETON31 == null) { boolean applySchemaResolution = Boolean.parseBoolean(System.getProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY, "false")) || Boolean.parseBoolean(System.getenv(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY)); - SINGLETON31 = new ModelConverters(openapi31, applySchemaResolution ? schemaResolution : Schema.SchemaResolution.DEFAULT); + SINGLETON31 = new ModelConverters(openapi31, applySchemaResolution ? schemaResolution : Schema.SchemaResolution.DEFAULT, validationAnnotationFilter); init(SINGLETON31); } return SINGLETON31; } if (SINGLETON == null) { - SINGLETON = new ModelConverters(openapi31, schemaResolution); + SINGLETON = new ModelConverters(openapi31, schemaResolution, validationAnnotationFilter); init(SINGLETON); } return SINGLETON; 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 842916cbf8..5d15af9758 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 @@ -31,6 +31,7 @@ import io.swagger.v3.core.converter.AnnotatedType; import io.swagger.v3.core.converter.ModelConverter; import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter.DefaultValidationAnnotationFilter; import io.swagger.v3.core.util.AnnotationsUtils; import io.swagger.v3.core.util.Constants; import io.swagger.v3.core.util.Json; @@ -56,7 +57,6 @@ import io.swagger.v3.oas.models.media.IntegerSchema; import io.swagger.v3.oas.models.media.JsonSchema; import io.swagger.v3.oas.models.media.MapSchema; -import io.swagger.v3.oas.models.media.NumberSchema; import io.swagger.v3.oas.models.media.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; @@ -71,6 +71,9 @@ import javax.validation.constraints.DecimalMin; import javax.validation.constraints.Max; import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; import javax.xml.bind.annotation.XmlAccessType; @@ -111,6 +114,11 @@ public class ModelResolver extends AbstractModelConverter implements ModelConverter { Logger LOGGER = LoggerFactory.getLogger(ModelResolver.class); + + /** + * @deprecated Use {@link ModelResolver#hasNotNullAnnotation(Annotation[], ValidationAnnotationFilter)} instead + */ + @Deprecated public static List NOT_NULL_ANNOTATIONS = Arrays.asList("NotNull", "NonNull", "NotBlank", "NotEmpty"); public static final String SET_PROPERTY_OF_COMPOSED_MODEL_AS_SIBLING = "composed-model-properties-as-sibiling"; @@ -127,6 +135,8 @@ public class ModelResolver extends AbstractModelConverter implements ModelConver private boolean openapi31; + private ValidationAnnotationFilter validationAnnotationFilter = new DefaultValidationAnnotationFilter(); + private Schema.SchemaResolution schemaResolution = Schema.SchemaResolution.DEFAULT; public ModelResolver(ObjectMapper mapper) { @@ -1581,57 +1591,56 @@ protected void applyBeanValidatorAnnotations(Schema property, Annotation[] annot } } if (parent != null && annotations != null && applyNotNullAnnotations) { - boolean requiredItem = Arrays.stream(annotations).anyMatch(annotation -> - NOT_NULL_ANNOTATIONS.contains(annotation.annotationType().getSimpleName()) - ); + boolean requiredItem = hasNotNullAnnotation(annotations, validationAnnotationFilter); if (requiredItem) { addRequiredItem(parent, property.getName()); } } if (annos.containsKey("javax.validation.constraints.Min")) { - if (isNumberSchema(property)) { - Min min = (Min) annos.get("javax.validation.constraints.Min"); + Min min = (Min) annos.get("javax.validation.constraints.Min"); + if (isNumberSchema(property) && validationAnnotationFilter.isMinAnnotationApplicable(min)) { property.setMinimum(new BigDecimal(min.value())); } } if (annos.containsKey("javax.validation.constraints.Max")) { - if (isNumberSchema(property)) { - Max max = (Max) annos.get("javax.validation.constraints.Max"); + Max max = (Max) annos.get("javax.validation.constraints.Max"); + if (isNumberSchema(property) && validationAnnotationFilter.isMaxAnnotationApplicable(max)) { property.setMaximum(new BigDecimal(max.value())); } } if (annos.containsKey("javax.validation.constraints.Size")) { Size size = (Size) annos.get("javax.validation.constraints.Size"); - if (isNumberSchema(property)) { + boolean isApplicable = validationAnnotationFilter.isSizeAnnotationApplicable(size); + if (isApplicable && isNumberSchema(property)) { property.setMinimum(new BigDecimal(size.min())); property.setMaximum(new BigDecimal(size.max())); } - if (isStringSchema(property)) { + if (isApplicable && isStringSchema(property)) { property.setMinLength(Integer.valueOf(size.min())); property.setMaxLength(Integer.valueOf(size.max())); } - if (isArraySchema(property)) { + if (isApplicable && 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 (isNumberSchema(property)) { + if (isNumberSchema(property) && validationAnnotationFilter.isDecimalMinAnnotationApplicable(min)) { 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 (isNumberSchema(property)) { + if (isNumberSchema(property) && validationAnnotationFilter.isDecimalMaxAnnotationApplicable(max)) { 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 (isStringSchema(property)) { + if (isStringSchema(property) && validationAnnotationFilter.isPatternAnnotationApplicable(pattern)) { property.setPattern(pattern.regexp()); } if(property.getItems() != null && isStringSchema(property.getItems())) { @@ -2423,9 +2432,9 @@ protected Set resolveIgnoredProperties(Annotations a, Annotation[] annot Set propertiesToIgnore = new HashSet<>(); JsonIgnoreProperties ignoreProperties = a.get(JsonIgnoreProperties.class); if (ignoreProperties != null) { - if(!ignoreProperties.allowGetters()) { - propertiesToIgnore.addAll(Arrays.asList(ignoreProperties.value())); - } + if(!ignoreProperties.allowGetters()) { + propertiesToIgnore.addAll(Arrays.asList(ignoreProperties.value())); + } } propertiesToIgnore.addAll(resolveIgnoredProperties(annotations)); return propertiesToIgnore; @@ -3087,6 +3096,11 @@ public ModelResolver openapi31(boolean openapi31) { return this; } + public ModelResolver validationAnnotationFilter(ValidationAnnotationFilter validationAnnotationFilter) { + this.validationAnnotationFilter = validationAnnotationFilter; + return this; + } + public boolean isOpenapi31() { return openapi31; } @@ -3134,4 +3148,38 @@ protected boolean applySchemaResolution() { (Boolean.parseBoolean(System.getProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY, "false")) || Boolean.parseBoolean(System.getenv(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY))); } + + + /** + * Check if the parameter has any of the annotations that make it non-optional + * + * @param annotations the annotations to check + * @param validationAnnotationFilter the filters to use to remove annotations that don't match the current group + * @return whether any of the known NotNull annotations are present + */ + public static boolean hasNotNullAnnotation(Annotation[] annotations, ValidationAnnotationFilter validationAnnotationFilter) { + for (Annotation annotation : annotations) { + if (hasNotNullAnnotation(annotation, validationAnnotationFilter)) { + return true; + } + } + return false; + } + + public static boolean hasNotNullAnnotation(Annotation annotation, ValidationAnnotationFilter validationAnnotationFilter) { + if (annotation instanceof NotEmpty && validationAnnotationFilter.isNotEmptyAnnotationApplicable((NotEmpty) annotation)) { + return true; + } + if (annotation instanceof NotBlank && validationAnnotationFilter.isNotBlankAnnotationApplicable((NotBlank) annotation)) { + return true; + } + if (annotation instanceof NotNull && validationAnnotationFilter.isNotNullAnnotationApplicable((NotNull) annotation)) { + return true; + } + if (annotation.annotationType().getSimpleName().equals("NonNull")) { + return true; + } + return false; + } + } diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ValidationAnnotationFilter.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ValidationAnnotationFilter.java new file mode 100644 index 0000000000..a01e12e73d --- /dev/null +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ValidationAnnotationFilter.java @@ -0,0 +1,60 @@ +package io.swagger.v3.core.jackson; + +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +public interface ValidationAnnotationFilter { + + default boolean isNotEmptyAnnotationApplicable(NotEmpty notEmpty) { + return annotationGroupMatches(notEmpty.groups()); + } + + default boolean isNotBlankAnnotationApplicable(NotBlank notBlank) { + return annotationGroupMatches(notBlank.groups()); + } + + default boolean isNotNullAnnotationApplicable(NotNull notNull) { + return annotationGroupMatches(notNull.groups()); + } + + default boolean isMaxAnnotationApplicable(Max max) { + return annotationGroupMatches(max.groups()); + } + + default boolean isMinAnnotationApplicable(Min min) { + return annotationGroupMatches(min.groups()); + } + + default boolean isDecimalMaxAnnotationApplicable(DecimalMax decimalMax) { + return annotationGroupMatches(decimalMax.groups()); + } + + default boolean isDecimalMinAnnotationApplicable(DecimalMin decimalMin) { + return annotationGroupMatches(decimalMin.groups()); + } + + default boolean isSizeAnnotationApplicable(Size size) { + return annotationGroupMatches(size.groups()); + } + + default boolean isPatternAnnotationApplicable(Pattern pattern) { + return annotationGroupMatches(pattern.groups()); + } + + boolean annotationGroupMatches(Class[] annotationGroups); + + class DefaultValidationAnnotationFilter implements ValidationAnnotationFilter { + + @Override + public boolean annotationGroupMatches(Class[] annotationGroups) { + return annotationGroups.length == 0; + } + } +} diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ParameterProcessor.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ParameterProcessor.java index 18e1277328..6971f7318e 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ParameterProcessor.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/ParameterProcessor.java @@ -5,6 +5,8 @@ import io.swagger.v3.core.converter.ModelConverters; import io.swagger.v3.core.converter.ResolvedSchema; import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter.DefaultValidationAnnotationFilter; import io.swagger.v3.oas.annotations.enums.Explode; import io.swagger.v3.oas.annotations.media.ExampleObject; import io.swagger.v3.oas.models.Components; @@ -55,7 +57,20 @@ public static Parameter applyAnnotations( JsonView jsonViewAnnotation, boolean openapi31, Schema.SchemaResolution schemaResolution) { + return applyAnnotations(parameter, type, annotations, components, classTypes, methodTypes, jsonViewAnnotation, openapi31, schemaResolution, new DefaultValidationAnnotationFilter()); + } + public static Parameter applyAnnotations( + Parameter parameter, + Type type, + List annotations, + Components components, + String[] classTypes, + String[] methodTypes, + JsonView jsonViewAnnotation, + boolean openapi31, + Schema.SchemaResolution schemaResolution, + ValidationAnnotationFilter validationAnnotationFilter) { final AnnotationsHelper helper = new AnnotationsHelper(annotations, type); if (helper.isContext()) { return null; @@ -252,7 +267,7 @@ public static Parameter applyAnnotations( } catch (Exception e) { LOGGER.error("failed on " + annotation.annotationType().getName(), e); } - } else if (ModelResolver.NOT_NULL_ANNOTATIONS.contains(annotation.annotationType().getSimpleName())) { + } else if (ModelResolver.hasNotNullAnnotation(annotation, validationAnnotationFilter)) { parameter.setRequired(true); } } diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4804Test.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4804Test.java new file mode 100644 index 0000000000..200b5a7970 --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4804Test.java @@ -0,0 +1,74 @@ +package io.swagger.v3.core.resolving; + +import java.math.BigDecimal; +import java.util.Arrays; + +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +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.matchers.SerializationMatchers; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.Schema.SchemaResolution; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class Ticket4804Test { + + @BeforeMethod + public void beforeTest() { + ModelConverters.reset(); + System.clearProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY); + } + + @Test + public void shouldIncludeOnlyNonGroupedJakartaValidatedFieldsAsMandatoryByDefault() { + ResolvedSchema schema = ModelConverters.getInstance(false).resolveAsResolvedSchema(new AnnotatedType().type(CustomClass.class)); + String expectedJson = "{\"schema\":{\"required\":[\"nonGroupValidatedField\"],\"type\":\"object\",\"properties\":{\"nonGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField\":{\"type\":\"integer\",\"format\":\"int32\"},\"multipleGroupValidatedField\":{\"type\":\"number\"},\"otherGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField2\":{\"type\":\"string\"}}},\"referencedSchemas\":{\"CustomClass\":{\"required\":[\"nonGroupValidatedField\"],\"type\":\"object\",\"properties\":{\"nonGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField\":{\"type\":\"integer\",\"format\":\"int32\"},\"multipleGroupValidatedField\":{\"type\":\"number\"},\"otherGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField2\":{\"type\":\"string\"}}}}}"; + SerializationMatchers.assertEqualsToJson(schema, expectedJson); + } + + @Test + public void shouldIncludeAllJakartaValidatedFieldsAsMandatoryIfFilterAlwaysTrue() { + ResolvedSchema schema = ModelConverters.getInstance(false, SchemaResolution.DEFAULT, annotationGroups -> true).resolveAsResolvedSchema(new AnnotatedType().type(CustomClass.class)); + String expectedJson = "{\"schema\":{\"required\":[\"nonGroupValidatedField\",\"singleGroupValidatedField2\"],\"type\":\"object\",\"properties\":{\"nonGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField\":{\"minimum\":1,\"type\":\"integer\",\"format\":\"int32\"},\"multipleGroupValidatedField\":{\"minimum\":1,\"exclusiveMinimum\":false,\"type\":\"number\"},\"otherGroupValidatedField\":{\"pattern\":\".*\",\"type\":\"string\"},\"singleGroupValidatedField2\":{\"type\":\"string\"}}},\"referencedSchemas\":{\"CustomClass\":{\"required\":[\"nonGroupValidatedField\",\"singleGroupValidatedField2\"],\"type\":\"object\",\"properties\":{\"nonGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField\":{\"minimum\":1,\"type\":\"integer\",\"format\":\"int32\"},\"multipleGroupValidatedField\":{\"minimum\":1,\"exclusiveMinimum\":false,\"type\":\"number\"},\"otherGroupValidatedField\":{\"pattern\":\".*\",\"type\":\"string\"},\"singleGroupValidatedField2\":{\"type\":\"string\"}}}}}"; + SerializationMatchers.assertEqualsToJson(schema, expectedJson); + } + + + @Test + public void shouldIncludeOnlyJakartaValidatedFieldsMatchingConditionInFilter() { + ResolvedSchema schema = ModelConverters.getInstance(false, SchemaResolution.ALL_OF, annotationGroups -> annotationGroups.length == 0 || Arrays.stream(annotationGroups).anyMatch(group -> group == ValidationGroup.class)).resolveAsResolvedSchema(new AnnotatedType().type(CustomClass.class)); + String expectedJson = "{\"schema\":{\"required\":[\"nonGroupValidatedField\",\"singleGroupValidatedField2\"],\"type\":\"object\",\"properties\":{\"nonGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField\":{\"minimum\":1,\"type\":\"integer\",\"format\":\"int32\"},\"multipleGroupValidatedField\":{\"minimum\":1,\"exclusiveMinimum\":false,\"type\":\"number\"},\"otherGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField2\":{\"type\":\"string\"}}},\"referencedSchemas\":{\"CustomClass\":{\"required\":[\"nonGroupValidatedField\",\"singleGroupValidatedField2\"],\"type\":\"object\",\"properties\":{\"nonGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField\":{\"minimum\":1,\"type\":\"integer\",\"format\":\"int32\"},\"multipleGroupValidatedField\":{\"minimum\":1,\"exclusiveMinimum\":false,\"type\":\"number\"},\"otherGroupValidatedField\":{\"type\":\"string\"},\"singleGroupValidatedField2\":{\"type\":\"string\"}}}}}"; + SerializationMatchers.assertEqualsToJson(schema, expectedJson); + } + + + private interface ValidationGroup { + + } + + private interface OtherValidationGroup { + + } + + + private static class CustomClass { + + @NotNull + public String nonGroupValidatedField; + @Min(value = 1, groups = ValidationGroup.class) + public Integer singleGroupValidatedField; + @DecimalMin(value = "1.0", groups = {ValidationGroup.class, OtherValidationGroup.class}) + public BigDecimal multipleGroupValidatedField; + @Pattern(regexp = ".*", groups = OtherValidationGroup.class) + public String otherGroupValidatedField; + @NotEmpty(groups = ValidationGroup.class) + public String singleGroupValidatedField2; + } +} diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/DefaultParameterExtension.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/DefaultParameterExtension.java index 541dda6b52..f9445fa95d 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/DefaultParameterExtension.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/DefaultParameterExtension.java @@ -120,7 +120,11 @@ public ResolvedParameter extractParameters(List annotations, annotations, components, classConsumes == null ? new String[0] : classConsumes.value(), - methodConsumes == null ? new String[0] : methodConsumes.value(), jsonViewAnnotation, openapi31, this.schemaResolution); + methodConsumes == null ? new String[0] : methodConsumes.value(), + jsonViewAnnotation, + openapi31, + this.schemaResolution, + validationAnnotationFilter); if (unknownParameter != null) { if (StringUtils.isNotBlank(unknownParameter.getIn()) && !"form".equals(unknownParameter.getIn())) { extractParametersResult.parameters.add(unknownParameter); @@ -142,7 +146,8 @@ public ResolvedParameter extractParameters(List annotations, methodConsumes == null ? new String[0] : methodConsumes.value(), jsonViewAnnotation, openapi31, - this.schemaResolution); + this.schemaResolution, + validationAnnotationFilter); if (processedParameter != null) { extractParametersResult.parameters.add(processedParameter); } @@ -267,7 +272,8 @@ private boolean handleAdditionalAnnotation(List parameters, List parameters, List annotation extension.setOpenAPI31(Boolean.TRUE.equals(config.isOpenAPI31())); Schema.SchemaResolution curSchemaResolution = config.getSchemaResolution(); extension.setSchemaResolution(config.getSchemaResolution()); + extension.setValidationAnnotationFilter(new DefaultValidationAnnotationFilter()); ResolvedParameter resolvedParameter = extension.extractParameters(annotations, type, typesToSkip, components, classConsumes, methodConsumes, true, jsonViewAnnotation, chain); ((SwaggerConfiguration)config).setSchemaResolution(curSchemaResolution); return resolvedParameter; diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/AbstractOpenAPIExtension.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/AbstractOpenAPIExtension.java index 197e248b24..b0c4b7c30e 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/AbstractOpenAPIExtension.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/AbstractOpenAPIExtension.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonView; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.type.TypeFactory; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter; import io.swagger.v3.jaxrs2.ResolvedParameter; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.Operation; @@ -19,6 +20,7 @@ public abstract class AbstractOpenAPIExtension implements OpenAPIExtension { protected boolean openapi31; protected Schema.SchemaResolution schemaResolution; + protected ValidationAnnotationFilter validationAnnotationFilter; @Override public String extractOperationMethod(Method method, Iterator chain) { @@ -75,4 +77,9 @@ public void setOpenAPI31(boolean openapi31) { public void setSchemaResolution(Schema.SchemaResolution schemaResolution) { this.schemaResolution = schemaResolution; } + + @Override + public void setValidationAnnotationFilter(ValidationAnnotationFilter validationAnnotationFilter) { + this.validationAnnotationFilter = validationAnnotationFilter; + } } diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/OpenAPIExtension.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/OpenAPIExtension.java index b82e8b581d..cdebd401c8 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/OpenAPIExtension.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/ext/OpenAPIExtension.java @@ -1,6 +1,7 @@ package io.swagger.v3.jaxrs2.ext; import com.fasterxml.jackson.annotation.JsonView; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter; import io.swagger.v3.jaxrs2.ResolvedParameter; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.Operation; @@ -36,4 +37,8 @@ default void setOpenAPI31(boolean openapi31) { default void setSchemaResolution(Schema.SchemaResolution schemaResolution) { //todo: override me! } + + default void setValidationAnnotationFilter(ValidationAnnotationFilter validationAnnotationFilter) { + //todo: override me! + } } diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/util/ReaderUtils.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/util/ReaderUtils.java index 581bc0bbb4..40d44b256d 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/util/ReaderUtils.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/v3/jaxrs2/util/ReaderUtils.java @@ -1,6 +1,8 @@ package io.swagger.v3.jaxrs2.util; import com.fasterxml.jackson.annotation.JsonView; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter; +import io.swagger.v3.core.jackson.ValidationAnnotationFilter.DefaultValidationAnnotationFilter; import io.swagger.v3.core.util.ParameterProcessor; import io.swagger.v3.core.util.ReflectionUtils; import io.swagger.v3.jaxrs2.ext.OpenAPIExtension; @@ -47,6 +49,10 @@ public static List collectConstructorParameters(Class cls, Compone * @return the collection of supported parameters */ public static List collectConstructorParameters(Class cls, Components components, javax.ws.rs.Consumes classConsumes, JsonView jsonViewAnnotation, Schema.SchemaResolution schemaResolution) { + return collectConstructorParameters(cls, components, classConsumes, jsonViewAnnotation, schemaResolution, new DefaultValidationAnnotationFilter()); + } + + public static List collectConstructorParameters(Class cls, Components components, javax.ws.rs.Consumes classConsumes, JsonView jsonViewAnnotation, Schema.SchemaResolution schemaResolution, ValidationAnnotationFilter validationAnnotationFilter) { if (cls.isLocalClass() || (cls.isMemberClass() && !Modifier.isStatic(cls.getModifiers()))) { return Collections.emptyList(); } @@ -81,7 +87,10 @@ public static List collectConstructorParameters(Class cls, Compone components, classConsumes == null ? new String[0] : classConsumes.value(), null, - jsonViewAnnotation, false, schemaResolution); + jsonViewAnnotation, + false, + schemaResolution, + validationAnnotationFilter); if (processedParameter != null) { parameters.add(processedParameter); }