Search code examples
javaspringvalidationspring-mvcannotations

spring combine two validation annotations in one


I'm using Spring+Hibernate+Spring-MVC.
I want to define a custom constraint combining two other predefined validation annotations: @NotNull @Size like this:

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@NotNull
@Size(min=4)
public @interface JPasswordConstraint {
} // this is not correct. It's just a suggestion.

and I want to use this annotation in my form models.

public class ChangePasswordForm {

  @NotNull
  private String currentPass;

  @JPasswordConstraint
  private String newPass;

  @JPasswordConstraint
  private String newPassConfirm;
}

UserController.java

@RequestMapping(value = "/pass", method = RequestMethod.POST)
public String pass2(Model model, @Valid @ModelAttribute("changePasswordForm") ChangePasswordForm form, BindingResult result) {
    model.addAttribute("changePasswordForm", form);
    try {
        userService.changePassword(form);
    } catch (Exception ex) {
        result.rejectValue(null, "error.objec", ex.getMessage());
        System.out.println(result);
    }
    if (!result.hasErrors()) {
        model.addAttribute("successMessage", "password changed successfully!");
    }
    return "user/pass";
}

But it does not work. It accepts the less than 4 character passwords.
How can I solve this problem?


Solution

  • This is a bit late, but technique of combining validation annotations described in

    https://docs.jboss.org/hibernate/stable/validator/reference/en-US/html_single/?v=5.4#section-constraint-composition

    Maybe it was not available, at the time of writing, but solution is following

    @NotNull
    @Size(min=4)
    @Target({ METHOD, FIELD, ANNOTATION_TYPE })
    @Retention(RUNTIME)
    @Constraint(validatedBy = { })
    @Documented
    public @interface JPasswordConstraint {
        String message() default "Password is invalid";
        Class<?>[] groups() default { };
        Class<? extends Payload>[] payload() default { };
     }