Bean 验证不适用于 mojarra 2.2.4

Posted

技术标签:

【中文标题】Bean 验证不适用于 mojarra 2.2.4【英文标题】:Bean validation doesn't work with mojarra 2.2.4 【发布时间】:2013-11-07 09:56:27 【问题描述】:

我正在尝试使用 Hibernate Validator 5.0.1 和 JSF2.2,但自 mojarra 版本 2.2.3 以来它们的集成似乎被破坏了。我创建了一个小应用程序来演示这个问题并得到异常“javax.servlet.ServletException:Expression Error: Named Object: javax.faces.Bean not found”。在 Tomcat 7.0.42 上运行时。

还有其他人有这个问题吗?

webapp/pages/index.xhtml

  <!DOCTYPE html>
  <html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
  <h:body>
    <h:form>
        <h:messages/>
        <h:inputText value="#theBean.z">
            <f:validateBean/>
        </h:inputText>
        <h:commandButton value="send z"/>
    </h:form>
  </h:body>
  </html>

TheBean.java

package lo.test;

import javax.faces.bean.ManagedBean;
import javax.validation.constraints.Min;

@ManagedBean
public class TheBean 

    @Min(5)
    private Integer z;

    public Integer getZ() 
        return z;
    

    public void setZ(Integer z) 
        this.z = z;
    

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>pages/index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

依赖关系:

"org.hibernate:hibernate-validator:5.0.1.Final"
"com.sun.faces:jsf-impl:2.2.4"
"com.sun.faces:jsf-api:2.2.4"

异常的完整堆栈跟踪:

javax.faces.FacesException: Expression Error: Named Object: javax.faces.Bean not found.
at com.sun.faces.application.ApplicationImpl.createValidator(ApplicationImpl.java:1596)
at com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.createValidator(ValidatorTagHandlerDelegateImpl.java:245)
at com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.applyAttachedObject(ValidatorTagHandlerDelegateImpl.java:133)
at com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.applyNested(ValidatorTagHandlerDelegateImpl.java:212)
at com.sun.faces.facelets.tag.jsf.ValidatorTagHandlerDelegateImpl.apply(ValidatorTagHandlerDelegateImpl.java:88)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
at com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:161)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:980)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:99)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:722)

【问题讨论】:

您还可以添加完整的堆栈跟踪吗? 我在休眠验证器 5.0.1 和 Mojarra >= 2.2.3 中遇到了同样的问题。 2.2.2 也适合我。 【参考方案1】:

Mojarra 2.2.3 到 2.2.6 在 Tomcat 或 Jetty 等 servlet 容器上似乎会出现问题,因为 Mojarra 尝试通过 JNDI 加载 bean 验证。

我在 JavaLand 2014 上与 Ed Burns 讨论了这个问题,应该使用 Mojarra 2.2.7 解决这个问题(请参阅 JAVASERVERFACES-3183)。

【讨论】:

【参考方案2】:

检查以下内容:

ApplicationFactory applicationFactory = (ApplicationFactory) FactoryFinder.getFactory(FactoryFinder.APPLICATION_FACTORY);

applicationFactory.getApplication().addDefaultValidatorId(BeanValidator.VALIDATOR_ID);
applicationFactory.getApplication().addValidator(BeanValidator.VALIDATOR_ID, BeanValidator.class.getName());

【讨论】:

使用 Tomcat Tomcat 6.0.39、JSF 2.2.6 和 Hibernate Bean Validator 4.3.1 为我工作 是的,我也是!这个 bug 快把我逼疯了,我很确定它一定是 JSF 中的许多 bug 之一(叹气!)使用 Tomcat 7.0.53、JSF 2.2.6 和 Hibernate Bean Validator 5.1.1 – Kounavi【参考方案3】:

这适用于 Mojara 2.2.2,但不适用于较新的版本。感谢 Michail 的提示。这是另一种预配置 Faces 的方法:

public class FacesContextBootstrap implements ServletContextListener

    public static final String BEANS_VALIDATION_AVAILABILITY_CACHE_KEY = "javax.faces.BEANS_VALIDATION_AVAILABLE";

    @Override
    public void contextInitialized(ServletContextEvent sce) 
        FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().remove(BEANS_VALIDATION_AVAILABILITY_CACHE_KEY);
        FacesContext.getCurrentInstance().getExternalContext().getApplicationMap()
                .put(BeanValidator.VALIDATOR_FACTORY_KEY, Validation.buildDefaultValidatorFactory());
    

    @Override
    public void contextDestroyed(ServletContextEvent sce) 

    

【讨论】:

这个修复在 Majorra 2.2.6 上似乎对我不起作用 - 您是否将 FacesContextBootstrap 类放在项目层次结构中的特定位置? 在初始化 servlet 容器的那一刻,faces context 似乎没有被初始化【参考方案4】:

我能够通过这种方式修复它:

public static final String BEANS_VALIDATION_AVAILABILITY_CACHE_KEY = "javax.faces.BEANS_VALIDATION_AVAILABLE";

@PostConstruct
private void init() 
    FacesContext.getCurrentInstance().getExternalContext().getApplicationMap().remove(BEANS_VALIDATION_AVAILABILITY_CACHE_KEY);
    FacesContext.getCurrentInstance().getExternalContext().getApplicationMap()
            .put(BeanValidator.VALIDATOR_FACTORY_KEY, Validation.buildDefaultValidatorFactory());

【讨论】:

以上是关于Bean 验证不适用于 mojarra 2.2.4的主要内容,如果未能解决你的问题,请参考以下文章

Bean 验证 @Positive 指令不适用于 Integer @PathVariable

Spring MVC 表单验证不适用于嵌套的复杂类型

Primefaces 动态列不适用于延迟加载

JSF 2.2 h:inputFile 不适用于漂亮的面孔[重复]

JSR 303 Bean 验证 - 为啥使用 getter 而不是 setter?

JSR 303 Bean 验证 - 为啥使用 getter 而不是 setter?