Rich Faces 日历组件出现错误 Omnifaces o:validateOrder

Error Omnifaces o:validateOrder with Rich Faces Calendar component

我在尝试使用 o:validateOrder 验证 rich:calendar 组件时遇到问题。

代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:tablas="http://java.sun.com/jsf/composite/tablas"
    xmlns:o="http://omnifaces.org/ui"
    xmlns:of="http://omnifaces.org/functions"
    xmlns:templates="http://java.sun.com/jsf/composite/templates"
    >

<body>

    <f:metadata>
        <f:event type="preRenderView" listener="#{baseController.iniciarConversacion()}" />
    </f:metadata>

    <ui:composition template="/templates/TemplateABM.xhtml">
        <ui:define name="title">
                #{msgs['facturacion.abm.generacion.factura.individual.pagina.titulo']}
            </ui:define>
        <ui:define name="top">
            <h1>#{msgs['facturacion.abm.generacion.factura.individual.titulo']}</h1>
        </ui:define>
        <ui:define name="content">

            <h:form id="formFacturaIndividual">


                <h:panelGroup id="panelFechas">
                    <h:inputHidden id="fechaInicioFactura" value="#{facturaController.fechaInicioFactura}">
                        <f:convertDateTime type="date" pattern="dd/MM/yy"/>
                    </h:inputHidden>

                    <h:inputHidden id="fechaFinFactura" value="#{facturaController.fechaFinFactura}">
                        <f:convertDateTime type="date" pattern="dd/MM/yy"/>
                    </h:inputHidden>            

                    <h:inputHidden id="fechaEmisionComprobanteUltima" value="#{comprobanteController.fechaEmisionComprobanteUltima}">
                        <f:convertDateTime type="date" pattern="dd/MM/yy"/>
                    </h:inputHidden>            
                </h:panelGroup>

                <o:validateOrder id="validacionFechaFacturaMenorAFechaInicioFactura" type="gte" components="fechaFactura fechaInicioFactura" 
                message="#{msgs['comun.abm.fecha.factura.menor.limite.dia']}" showMessageFor="fechaFactura" />
                <o:validateOrder id="validacionFechaFacturaMayorAFechaFinFactura" type="lte" components="fechaFactura fechaFinFactura" 
                message="#{msgs['comun.abm.fecha.factura.menor.limite.dia']}" showMessageFor="fechaFactura" />                             
                <o:validateOrder id="validacionFechaFacturaMayorAFechaEmisionUltimoComprobante" type="gte" components="fechaFactura fechaEmisionComprobanteUltima" 
                message="#{of:format1(msgs['comun.abm.fecha.factura.menor.ultimo.comprobante'], comprobanteController.fechaEmisionComprobanteUltima)}" showMessageFor="fechaFactura" />

                <o:massAttribute name="disabled" value="#{tipoComprobanteController.entidad == null}">
                    <rich:panel id="panelDatosFactura" header="#{msgs['facturacion.abm.generacion.padron.panel.datos.factura']}">

                        <h:panelGrid id="DatosFactura" columns="3">

                            <h:outputLabel value="#{msgs['facturacion.abm.generacion.padron.fecha.factura']}" for="fechaFactura"/>  
                            <rich:calendar
                                id="fechaFactura"
                                datePattern="dd/MM/yyyy"
                                showWeeksBar="false"
                                enableManualInput="true"
                                value="#{generacionFacturacionIndividualController.facturaBean.fechaFactura}"
                                required="true"
                                requiredMessage="La Fecha de la Factura es Obligatoria" >
    <a4j:ajax event="change" execute="@form"  />
                            </rich:calendar>
                            <h:panelGroup>
                                <rich:message for="fechaFactura"/>
                            </h:panelGroup>

                        </h:panelGrid>

                    </rich:panel>
                </o:massAttribute>


            </h:form>

        </ui:define>
    </ui:composition>

</body>
</html>

异常:

java.lang.IllegalArgumentException: All values must implement java.lang.Comparable.
    at org.omnifaces.component.validator.ValidateOrder.validateValues(ValidateOrder.java:142)
    at org.omnifaces.component.validator.ValidateMultipleFields.validateComponents(ValidateMultipleFields.java:213)
    at org.omnifaces.component.validator.ValidatorFamily.processValidators(ValidatorFamily.java:63)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1216)
    at javax.faces.component.UIForm.processValidators(UIForm.java:253)
    at com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback.visit(PartialViewContextImpl.java:536)
    at org.richfaces.context.MetaComponentProcessingVisitCallback.visit(MetaComponentProcessingVisitCallback.java:73)
    at org.richfaces.context.BaseExtendedVisitContext.invokeVisitCallback(BaseExtendedVisitContext.java:103)
    at org.richfaces.context.ExtendedExecuteVisitContext.invokeVisitCallback(ExtendedExecuteVisitContext.java:55)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1652)
    at javax.faces.component.UIForm.visitTree(UIForm.java:371)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1663)
    at com.sun.faces.context.PartialViewContextImpl.processComponents(PartialViewContextImpl.java:383)
    at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:257)
    at org.richfaces.context.ExtendedPartialViewContext.processPartial(ExtendedPartialViewContext.java:263)
    at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:183)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1162)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at ar.com.filter.HibernateSessionRequestFilter.doFilter(HibernateSessionRequestFilter.java:35)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1074)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String
    at java.lang.String.compareTo(String.java:108)
    at java.util.Collections$ReverseComparator.compare(Collections.java:3578)
    at java.util.Collections$ReverseComparator.compare(Collections.java:3569)
    at java.util.TimSort.countRunAndMakeAscending(TimSort.java:324)
    at java.util.TimSort.sort(TimSort.java:189)
    at java.util.TimSort.sort(TimSort.java:173)
    at java.util.Arrays.sort(Arrays.java:659)
    at java.util.Collections.sort(Collections.java:217)
    at org.omnifaces.component.validator.ValidateOrder$Type.invoke(ValidateOrder.java:99)
    at org.omnifaces.component.validator.ValidateOrder$Type.invoke(ValidateOrder.java:95)
    at org.omnifaces.component.validator.ValidateOrder$Type.validateOrder(ValidateOrder.java:111)
    at org.omnifaces.component.validator.ValidateOrder.validateValues(ValidateOrder.java:139)
    ... 44 more

我调试了代码,问题是 rich:calendar 组件发送的是 String 而不是 Date 类型,我在其他页面中没有发生这种情况,我不知道是 omnifaces 问题还是 richfaces。有什么想法吗?

<o:validateXxx> 组件对其相对于目标输入组件的位置敏感。这对于根据组件自己的转换器和验证器确定验证优先级非常有用。

当放置在目标输入组件之前时,它们将验证未提交的原始值,并且它们将在运行之前 任何组件自己的验证器。

将目标输入组件放在之后,它们将验证转换后的值(如果涉及任何转换器),并且它们将运行 任何组件自己的验证器之后。

在您的特定情况下,您将 <o:validateOrder> 放置在 这些组件之间。这不是推荐的方法。您最终会得到一个 List,其中填充了来自验证器上方组件的 Date 个实例和来自验证器下方组件的 String 个实例。

另见 the ValidateMultipleFields javadoc(强调我的):

This validator can be placed anywhere in the form, but keep in mind that the components will be validated in the order as they appear in the form. So if this validator is been placed before all of the components, then it will be executed before any of the component's own validators. If this validator fails, then the component's own validators will not be fired. If this validator is been placed after all of the components, then it will be executed after any of the component's own validators. If any of them fails, then this validator will not be exeucted. It is not recommended to put this validator somewhere in between the referenced components as the resulting behaviour may be confusing. Put this validator either before or after all of the components, depending on how you would like to prioritize the validation.