Bazując na przykładzie z poprzedniego posta, jeśli w klasie Entity, mamy 2 pary pól do identycznej walidacji, np:
public class Entity {
private Date from;
private Date to;
private Date activeFrom;
private Date activeTo;
}
To użycie tej samej adnotacji walidującej dwa razy jest niedozwolone.
@CheckDates(dateFrom="from", dateTo="to")
@CheckDates(dateFrom="activeFrom", dateTo="activeTo")
public class Entity {
private Date from;
private Date to;
private Date activeFrom;
private Date activeTo;
}
Rozwiązaniem tego problemu jest wykorzystanie kolejnego ograniczenia adnotacji, mówięcego, że parametrem adnotacji może być tylko typ prymitywny, String, Class, enum, inna adnotacja, lub tablica 1-wymiarowa tablica wymienionych wcześniej klas.
Implementacja czegoś takiego mogłba by być następująca:
@Target({ TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = MultiCheckDatesValidator.class)
public @interface MultiCheckDates {
String message() default "{pl.costam.MultiCheckDates}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
CheckDates[] value();
}
I sam walidator, który tak de facto w pętli wywołuje walidator z poprzedniego posta (musimy jedynie dopisać konstruktor):
public class MultiCheckDatesValidator implements ConstraintValidator<MultiCheckDates, Object> {
private CheckDates[] checkDates;
@Override
public void initialize(MultiCheckDates constraintAnnotation) {
checkDates = constraintAnnotation.value();
}
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
boolean isValid = true;
for (CheckDates checkDate : checkDates) {
/**
* tworzymy i wywołujemy walidator dla pojedyńczej pary from-to
*/
if (!new CheckDatesValidator(checkDate).isValid(object, context)) {
isValid = false;
}
}
return isValid;
}
}
I samo wywołanie:
@MultiCheckDates({
@CheckDates(dateFrom = "from", dateTo = "to"),
@CheckDates(dateFrom = "activeFrom", dateTo = "activeTo") })
public class Entity {
Za piękne może to i nie jest, ale warto mieć świadomość limitów wykorzystania adnotacji. Prawdopodobnie lepszym rozwiązaniem byłoby stworzenie osobnej klasy DateRange, jak zasugerował to Michał Gruca w swoim komentarzu.
Choć czasami zastajemy kod taki a nie inny i refaktor bywa bardzo bolesny.