LocalDate 的 JSF 转换不断让我出现异常

JSF Conversion of a LocalDate keep getting me Exceptions

我有一个 xhtml 页面,您可以在其中输入您的姓名、生日和性别。

我的任务是将传入的字符串转换为 LocalDate,以便在 (JSF) 验证器中使用它来检查此人是否超过 18 岁。我要转换的字符串已经采用正确的格式(例如。 01.01.2022),但是只要我的 dateTimeFormatter 应该将 String 转换为 LocalDate,格式就会发生变化,就会抛出异常。我不明白为什么转换不起作用以及为什么日志会说一些关于 DateTimeConverter 的事情。

这是我的验证器:


<h:body>
    <h:form id="inputForm">

         <h:outputText id="birthdateOutput" value="Birthdate:: " />
         <h:inputText id="birthdate" value="#{form.birthdate}" rquired="true">
            <f:converter converterId="dateConverter" />
            <f:validator validatorId="ageValidator" />
         </h:inputText>
    <br />
    </h:form>
</ui:define>

这是我的转换器:

@FacesConverter(value = "dateConverter")
public class DateConverter implements Converter<LocalDate> {

    @Override
    public String getAsString(FacesContext context, UIComponent component, LocalDate value) {
        return value.toString();
    }

    @Override
    public LocalDate getAsObject(FacesContext context, UIComponent component, String value) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
        LocalDate returnDate = LocalDate.parse(value, dateTimeFormatter);
        return returnDate;
    }
}

那是我的错误日志:

javax.servlet.ServletException: j_idt8:j_idt10: Could not convert '2022-01-10' to a string.
    at javax.faces.api@3.0.0.SP04//javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:725)
    at javax.faces.api@3.0.0.SP04//javax.faces.webapp.FacesServlet.service(FacesServlet.java:451)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletChain.handleRequest(ServletChain.java:68)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.core@2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.core@2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.core@2.2.8.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.core@2.2.8.Final//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.core@2.2.8.Final//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.core@2.2.8.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.core@2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.core@2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
    at io.undertow.core@2.2.8.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.access0(ServletInitialHandler.java:78)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.call(ServletInitialHandler.java:133)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.call(ServletInitialHandler.java:130)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create[=12=](SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=12=](UndertowDeploymentInfoService.java:1535)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=12=](UndertowDeploymentInfoService.java:1535)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=12=](UndertowDeploymentInfoService.java:1535)
    at org.wildfly.extension.undertow@24.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=12=](UndertowDeploymentInfoService.java:1535)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.access[=12=]0(ServletInitialHandler.java:78)
    at io.undertow.servlet@2.2.8.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:99)
    at io.undertow.core@2.2.8.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:387)
    at io.undertow.core@2.2.8.Final//io.undertow.server.HttpServerExchange.run(HttpServerExchange.java:841)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at org.jboss.xnio@3.8.4.Final//org.xnio.XnioWorker$WorkerThreadFactory.run(XnioWorker.java:1280)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.faces.convert.ConverterException: j_idt8:j_idt10: Could not convert '2022-01-10' to a string.
    at javax.faces.api@3.0.0.SP04//javax.faces.convert.DateTimeConverter.getAsString(DateTimeConverter.java:551)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getFormattedValue(HtmlBasicRenderer.java:491)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getFormattedValue(HtmlBasicRenderer.java:509)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:330)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:143)
    at javax.faces.api@3.0.0.SP04//javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:595)
    at javax.faces.api@3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1654)
    at javax.faces.api@3.0.0.SP04//javax.faces.render.Renderer.encodeChildren(Renderer.java:152)
    at javax.faces.api@3.0.0.SP04//javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:566)
    at javax.faces.api@3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1647)
    at javax.faces.api@3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650)
    at javax.faces.api@3.0.0.SP04//javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:468)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:170)
    at javax.faces.api@3.0.0.SP04//javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:132)
    at javax.faces.api@3.0.0.SP04//javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:132)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:102)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.lifecycle.Phase.doPhase(Phase.java:76)
    at com.sun.jsf-impl@2.3.14.SP04//com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:199)
    at javax.faces.api@3.0.0.SP04//javax.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:708)
    ... 50 more
Caused by: java.lang.IllegalArgumentException: Cannot format given Object as a Date
    at java.base/java.text.DateFormat.format(DateFormat.java:338)
    at java.base/java.text.Format.format(Format.java:158)
    at javax.faces.api@3.0.0.SP04//javax.faces.convert.DateTimeConverter$FormatWrapper.format(DateTimeConverter.java:495)
    at javax.faces.api@3.0.0.SP04//javax.faces.convert.DateTimeConverter$FormatWrapper.access0(DateTimeConverter.java:470)
    at javax.faces.api@3.0.0.SP04//javax.faces.convert.DateTimeConverter.getAsString(DateTimeConverter.java:544)
    ... 69 more

您不需要自定义转换器。只需使用内置的 <f:convertDateTime>。从 2.3 版本开始,它原生支持 java.time.* 类型,例如 LocalDate。您只需要将 <f:convertDateTime>type 属性设置为符合 documentation 并将 pattern 属性设置为所需的模式。

因此,完全删除 DateConverter 并按如下方式重写您的 XHTML 文件:

<h:inputText ... value="#{bean.localDate}">
    <f:convertDateTime type="localDate" pattern="dd.MM.yyyy" />
    ...
</h:inputText>

请注意,转换器在之前运行所有验证器,因此任何验证器中的 Object value 参数将代表已经转换的 LocalDate 实例,因此不是 String.