0

I'm trying to implement something like DateRange validator to validate, if start date is before end date. I've defined annotation for validation, validator class and so on. Unforunatelly when I try to access or set somehing in validated object (via UI) validation is not called. What am I doing wrong ? I've defined following classes :

TimePeriod.java

@Constraint(validatedBy = DateRangeValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TimePeriod {

     String message() default "something";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};

}

DateRangeValidator.java

    public class DateRangeValidator implements ConstraintValidator<TimePeriod, DateRange>{

    TimePeriod constraintAnnotation;

    @Override
    public void initialize(TimePeriod constraintAnnotation) {
        this.constraintAnnotation = constraintAnnotation;
    }

    @Override
    public boolean isValid(DateRange value, ConstraintValidatorContext context) { 
            throw new RuntimeException("Some exception");

    }
}

DateRange.java

public class DateRange {

    private Date startDate;
    private Date endDate;

    public DateRange(Date start, Date end){
        this.startDate = start;
        this.endDate = end;
    }

    public Date getStartDate() {
        return startDate;
    }
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }
    public Date getEndDate() {
        return endDate;
    }
    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

}

I use Primefaces calendar element to choose a start and end dates. Snippet for this is :

<p:calendar id="startdateWizard"    
            value="#{DRBean.dateRange.startDate}"
            showButtonPanel="true"
            required="true"
>

DRBean.java

@Named
@ViewScoped
public class PFSBean implements Serializable {

    @TimePeriod
    private DateRange dateRange = new DateRange(new Date(), new Date()) ;


  public DateRange getDateRange() {
    return dateRange;
  }

  public void setDateRange(DateRange dateRange) {
    this.dateRange = dateRange;
  }
}

Maybe it is because dateRange object is not set directly - only one of it's field is set. If so, how to change it to achieve desired effect (validation on DateRange object to ensure that start date is always before end date)

Artur Skrzydło
  • 1,135
  • 18
  • 37

1 Answers1

1

After some research I've realized that for this kind cross-field validation, using JSR303 bean validation, validation on class level is required. Ufortunately until JSF 2.3 version this option is not available as it state in this post.So with usage only JSF it is not possible. However it is possible to do with little help of Omnifaces. Great example for class level validation can be found on Omnifaces showcase. Applying this solution to my task it is as simple as adding <o:validateBean value="#{pFSBean.dateRange}"/>in a form with calendar elements :

    <h:form>
        <p:messages id="messages" autoUpdate="true"/>
        <p:panel id="panel1">
            <h:panelGrid columns="2">
                <p:calendar id="startdateWizard"    
                            value="#{pFSBean.dateRange.startDate}"
                            showButtonPanel="true"
                            required="true"
                >   
                </p:calendar>
                <p:calendar id="enddateWizard"
                            name="enddateWizard"
                            value="#{pFSBean.dateRange.endDate}"
                                    required="true" showButtonPanel="true"
                >                           
                </p:calendar>
            </h:panelGrid>
        </p:panel>        
        <o:validateBean value="#{pFSBean.dateRange}"/> 
        <p:commandButton process="@(form)" update="@(form)" 
                             value="Process form"/>

   </h:form>

Also @TimePeriod annotation is moved on class level :

@TimePeriod
public class DateRange {
   ....
   ....
}

And annotation target for TYPE should be added in annotation definition. That's all. Now method isValid from validator class will be called. Of course this is not perfect solution because additional tool is needed, but without it ufortunately is not possible

Community
  • 1
  • 1
Artur Skrzydło
  • 1,135
  • 18
  • 37