I am trying to implement cross-field validation (JSR-303) with class-level custom annotation. However, the isValid method is not called (but the initialization method).
So my question is: why isn't the isValid method called for this level validator? Define it at the level of properties!
I tried this on JBoss AS 7 and Websphere AS 8.
Here is the JUnit code and test (which works)
Test.java
public class Test { @org.junit.Test public void test() throws ParseException { Person person = new Person(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMDD"); person.setPartyClosingDateFrom(new Date()); person.setPartyClosingDateTo(sdf.parse("20120210")); Set<ConstraintViolation<Person>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(person); for(ConstraintViolation<Person> violation : violations) { System.out.println("Message:- " + violation.getMessage()); } } }
DateCompare.java
import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; @Target({ TYPE}) @Retention(RUNTIME) @Constraint(validatedBy = DateCompareValidator.class) @Documented public @interface DateCompare { String firstDate(); String secondDate(); Class<?>[] constraints() default {}; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; String message() default "totally wrong, dude!"; DateValidator.DateComparisonMode matchMode() default DateValidator.DateComparisonMode.EQUAL; }
DateCompareValidator.java
public class DateCompareValidator implements ConstraintValidator<DateCompare, Object> { private DateValidator.DateComparisonMode comparisonMode; private String firstDateFieldName; private String secondDateFieldName; private String messageKey = "failure"; @Override public void initialize(final DateCompare constraintAnnotation) { this.comparisonMode = constraintAnnotation.matchMode(); this.firstDateFieldName = constraintAnnotation.firstDate(); this.secondDateFieldName = constraintAnnotation.secondDate(); } @Override public boolean isValid(final Object target, final ConstraintValidatorContext context) { boolean isValid = true; final Date valueDate1 = DateCompareValidator.getPropertyValue(Date.class, this.firstDateFieldName, target); final Date valueDate2 = DateCompareValidator.getPropertyValue(Date.class, this.secondDateFieldName, target); if (isValid) { isValid = DateValidator.isValid(valueDate1, valueDate2, this.comparisonMode); } else {
DateValidator.java
public class DateValidator { public enum DateComparisonMode { BEFORE, BEFORE_OR_EQUAL, EQUAL, AFTER_OR_EQUAL, AFTER; } public static boolean isValid(final Date baseDate, final Date valuationDate, final DateComparisonMode comparisonMode) {
In particular, property retrieval was taken from this post question