跨字段 Java Bean 验证不验证来自 JSF 的字段
Cross-field Java Bean Validation doesn't validate field from JSF
我正在尝试实现类似 DateRange 验证器的东西来验证开始日期是否早于结束日期。我已经为验证、验证器 class 等定义了注解。不幸的是,当我尝试访问或设置经过验证的对象(通过 UI)中的某些内容时,不会调用验证。我究竟做错了什么 ?我定义了以下 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;
}
}
我使用 Primefaces 日历元素来选择开始日期和结束日期。这个片段是:
<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;
}
}
可能是因为没有直接设置 dateRange 对象 - 只设置了它的一个字段。如果是这样,如何更改它以达到预期效果(对 DateRange 对象进行验证以确保开始日期始终早于结束日期)
经过一些研究,我意识到对于这种跨领域验证,使用 JSR303 bean 验证,需要 class 级别的验证。不幸的是,在 JSF 2.3 版本之前,此选项不可用,如 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 中所述。将此解决方案应用到我的任务中就像在带有日历元素的表单中添加 <o:validateBean value="#{pFSBean.dateRange}"/>
一样简单:
<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>
另外 @TimePeriod
注释被移动到 class 级别:
@TimePeriod
public class DateRange {
....
....
}
并且 TYPE
的注释目标应该添加到注释定义中。就这样。现在将调用验证器 class 中的方法 isValid
。当然这不是完美的解决方案,因为需要额外的工具,但不幸的是没有它是不可能的
我正在尝试实现类似 DateRange 验证器的东西来验证开始日期是否早于结束日期。我已经为验证、验证器 class 等定义了注解。不幸的是,当我尝试访问或设置经过验证的对象(通过 UI)中的某些内容时,不会调用验证。我究竟做错了什么 ?我定义了以下 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;
}
}
我使用 Primefaces 日历元素来选择开始日期和结束日期。这个片段是:
<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;
}
}
可能是因为没有直接设置 dateRange 对象 - 只设置了它的一个字段。如果是这样,如何更改它以达到预期效果(对 DateRange 对象进行验证以确保开始日期始终早于结束日期)
经过一些研究,我意识到对于这种跨领域验证,使用 JSR303 bean 验证,需要 class 级别的验证。不幸的是,在 JSF 2.3 版本之前,此选项不可用,如 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 中所述。将此解决方案应用到我的任务中就像在带有日历元素的表单中添加 <o:validateBean value="#{pFSBean.dateRange}"/>
一样简单:
<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>
另外 @TimePeriod
注释被移动到 class 级别:
@TimePeriod
public class DateRange {
....
....
}
并且 TYPE
的注释目标应该添加到注释定义中。就这样。现在将调用验证器 class 中的方法 isValid
。当然这不是完美的解决方案,因为需要额外的工具,但不幸的是没有它是不可能的