Walidacja identyczności haseł – Hibernate Validator, Spring Framework


Natknąłem się na problem walidacji identyczności haseł w formularzu rejestracji użytkownika. Korzystam ze Spring Frameworka, a do walidacji wykorzystuję bibliotekę Hibernate Validator w wersji 4.

Pierwszym problemem okazał się brak pola confirmPassword w klasie User. Poszperałem na forach i znalazłem w rozwiązania tego problemu:

  • Stworzyć dodatkowe pole w klasie User – confirmPassword
  • Stworzyć dodatkową klasę, przypuśćmy CreateUserForm, mniej więcej tak:
1
2
3
4
5
class CreateUserForm {
    String confirmPassword;
    User user;
    (... )
}

Rozwiązanie to wydaje mi się “ładniejsze” niż pierwsze, gdyż nie tworzymy w klasie, wykorzystywanej przy każdym requescie pola, które w ogóle nam jest niepotrzebne.

Kolejnym problemem okazała się walidacja. Chcieliśmy w 100% korzystać z funkcjonalności, jakie dają nam adnotacje z Hibernate Validatora. Brakuje jednak tam adnotacji umożliwiającej porównywanie ze sobą 2 pól.

Tutaj też skorzystałem z forów. Jedna osoba z teamu hibernate poleciła mi wykorzystanie ograniczeń (constraints) przypisanych do klas i zmianę domyślnego błędu zwracanego przez ten walidator.

Poniżej przedstawię rozwiązanie od jakiego doszedłem:

Poniżej znajduje się definicja interfejsu odpowiedzialnego za adnotację @SamePassword:

1
2
3
4
5
6
7
8
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = SamePasswordValidator.class)
public @interface SamePassword {
    String message() default "{pl.aetas.gamestore.validator.constraint.SamePassword}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

Sama klasa walidatora wygląda tak:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class SamePasswordValidator implements ConstraintValidator<SamePassword, Object> {

    SamePassword constraintAnnotation;

    public boolean isValid(Object value, ConstraintValidatorContext context) {
        context.disableDefaultConstraintViolation();
        context.buildConstraintViolationWithTemplate(constraintAnnotation.message()).addNode("confirmPassword").addConstraintViolation();
        CreateUserForm u = (CreateUserForm) value;
        if (u.getConfirmPassword().equals(u.getUser().getPassword())) {
            return true;
        }
        return false;
    }

    public void initialize(SamePassword constraintAnnotation) {
        this.constraintAnnotation = constraintAnnotation;
    }
}

Aby skorzystać z w/w rozwiązania wystarczy w klasie CreateUserForm dodać adnotację @SamePassword (na poziomie klasy) i .. tyle.

Mam nadzieję, że komuś się to przyda. W naszym projekcie adnotacje znacznie zwiększyły czytelność kodu, a jest to bardzo istotne przy pracy grupowej.

See also