Search code examples
springhibernatespring-mvchibernate-validator

It's so confused with the Hibernate Validator @Email constraint


I want to validate step by step, that is to say, if one constraint is falied, the next one will not be check, I defined the constraints in model like this:

@NotEmpty
@Size(min = 4, max = 40)
private String password;

@NotEmpty
@Email
private String email;

for the two properties, the validate result is different, if the password is empty, the error print is :

Password cant be empty
Password must be between 4 and 40 characters

but for email, the error print is :

Email cant be empty

for the email, the result is what I want, but I didn't know what's the difference between the @Email constraint and others, if there have some especial handler for the @Email constraint in the hibernate internal code?

I want validate step by step, but I didn't find out a perfect approach, the @GroupSequence also isn't a good scheme, I found the @Email have the feature, but I didn't know why @Email perform so especial.


Solution

  • An empty string will not fail the @Email check. So, the email property will only have one error for the @NotEmpty.

    You can achieve something similar to what you want, but not exactly, using one of the following methods:

    1- Enable failfast. This will stop the validation at the first invalid property (other properties will not be validated).

    Validator validator = Validation.byProvider( HibernateValidator.class )
            .configure()
            .failFast( true )
            .buildValidatorFactory()
            .getValidator();
    

    2- Create a composite constraint with @ReportAsSingleViolation annotation. This will stop the validation of a property at the first error, but you can't have different messages for each constraint error.

    @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
    @Retention(RUNTIME)
    @Constraint(validatedBy = { })
    @Documented
    @Size(min = 4, max = 10)
    @NotEmpty
    @ReportAsSingleViolation
    public @interface MyAnnotation {
        String message() default "single.error.message";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    }
    

    3- Use @GroupSequence to control the order of validation, and to stop validating the following groups when the current group fails.