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.
Brak komentarzy:
Prześlij komentarz