2

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 DateValidators, but the CompareDatesValidator always run, which is not correct. Can I fix this ?!

Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
  • Is this answers your question? From the docs: `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.`. – Aleksandr M Dec 23 '15 at 15:26
  • @AleksandrM thanks I have seen it, but unfortunately it does not helped. The validation should be short circuit but it is not ! – Alireza Fattahi Dec 23 '15 at 15:32
  • `Plain validator takes precedence over field-validator.` - Meaning your `CompareDatesValidator` will be executed first. Meaning short circuit will happen only after that. Convert it to field validator and it should work like you want. – Aleksandr M Dec 23 '15 at 15:39
  • 1
    @AleksandrM *less commenting, more answering* FTW ! :) – Andrea Ligios Dec 23 '15 at 15:53
  • I thought that because i wanted to use more than one field during validaiton, I should use extend `ValidatorSupport`. Well I changed `CompareDatesValidator` to extend `FieldValidatorSupport` but I get `Null pointer` from strust do you need stacktarce ?! – Alireza Fattahi Dec 23 '15 at 16:02

1 Answers1

2

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:

  1. CompareDatesValidator (plain)
  2. DateValidator (field fromDate)
  3. DateValidator (field 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.

Community
  • 1
  • 1
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • 1
    The `DateValidator` are complicated functions, so I end up repeating the `DateValidator` in the `CompareDatesValidator`. Like: `if( !valid(d1) || !valid(d2)) { LOG.debug("Silently disabling Plain Validator. Check performed by Field ones");}` Thanks for the answer – Alireza Fattahi Dec 26 '15 at 04:28