Skip to content

Incorrect inclusion of javax/jakarta validation annotations with groups property set #4804

Open
@mc1arke

Description

@mc1arke

The javax/jakarta annotations contain a groups property that can be used to enable different combinations of validation on a model depending on which group is currently active - https://jakarta.ee/learn/docs/jakartaee-tutorial/current/beanvalidation/bean-validation-advanced/bean-validation-advanced.html#_grouping_constraints.

When executed against a model, swagger-core currently treats any of the supported javax/jakarta annotations as applying a constraint to the schema, even where the annotated field/attribute specifies groups and is therefore is not mandatory on all requests. By default, swagger-core should only set fields as mandatory/constrained based on annotations where no groups are specified, but provide a way of the end-user adding other validation groups into the constraints where they want to treat certain groups as always being enabled.

Replication Steps

        @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);
        }


        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;
        }

The above replicate a validator being run in default mode, e.g. Validation.buildDefaultValidatorFactory().getValidator().validate(new CustomClass());, which is the default way that frameworks such as Spring invoke validators. Users using something similar to
Validation.buildDefaultValidatorFactory().getValidator().validate(new CustomClass(), ValidationGroup.class); would add the annotations with ValidationGroup in the groups property into the enforced validation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions