Consider below sample, which checks if fromDate
and toDate
are valid dates and if fromDate
is less than toDate
:
@CustomValidator(type = "DateValidator",
fieldName = "fromDate",
shortCircuit = true),
@CustomValidator(type = "DateValidator",
fieldName = "toDate",
shortCircuit = true),
@CustomValidator(type = "CompareDatesValidator",
message = "validate.date.jalali.same.or.before",
shortCircuit = true,
parameters = {
@ValidationParameter(name = "fromDateParam", value = "${fromDate}"),
@ValidationParameter(name = "toDateParam", value = "${toDate}")
})
The DateValidator
extends the FieldValidatorSupport
and the CompareDatesValidator
extends the ValidatorSupport
Although I have shortCircuit
the DateValidator
s, but the CompareDatesValidator
always run, which is not correct. Can I fix this ?!
As explained in the documentation.
Plain validator takes precedence over field-validator. They get validated first in the order they are defined and then the field-validator in the order they are defined. Failure of a particular validator marked as short-circuit will prevent the evaluation of subsequent validators and an error (action error or field error depending on the type of validator) will be added to the ValidationContext of the object being validated.
Then your actual execution order is:
fromDate
)toDate
)The problem is that it will be executed first, but since its check is a composite check based on two fields, the atomic check on the fields itself should be performed first.
But this is how the framework works, so you need to workaround it.
If your plain validator is still this one (even if with some modification), you could avoid the check and ignore the error in case the input is not valid, letting this validation happen where it belongs, in the Field Validators:
public final class CompareDatesValidator extends ValidatorSupport {
private String fromDate; // getter and setter
private String toDate; // getter and setter
@Override
public void validate(Object o) throws ValidationException {
Date d1 = (Date)parse(fromDate, Date.class);
Date d2 = (Date)parse(toDate, Date.class);
if (d1==null || d2==null){
LOG.debug("Silently disabling Plain Validator. Check performed by Field ones");
} else if (d2.before(d1)){
addActionError(getDefaultMessage());
}
}
}
You only need to remember to always put the Field Validators in the same validation stack of the CompareDatesValidator, or the "Date not valid" errors will be silently swallowed.