Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bean validation doesn't work with mojarra 2.2.4

I'm trying to use Hibernate Validator 5.0.1 and JSF2.2 but their integration seems to be broken since mojarra version 2.2.3. I've created small app to demonstrate the issue and get exception "javax.servlet.ServletException: Expression Error: Named Object: javax.faces.Bean not found." when running it on Tomcat 7.0.42.

Does anyone else have this problem?

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>

Dependencies:

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

Full stack trace of exception:

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)
like image 364
user2928411 Avatar asked Oct 28 '13 14:10

user2928411


4 Answers

I was able to fix it this way:

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());
}
like image 195
Michail Nikolaev Avatar answered Nov 16 '22 16:11

Michail Nikolaev


The problem seems to occur with Mojarra 2.2.3 to 2.2.6 on servlet containers like Tomcat or Jetty as Mojarra tries to load bean validation via JNDI.

I discussed this with Ed Burns at JavaLand 2014 and this issue should be fixed with Mojarra 2.2.7 (see JAVASERVERFACES-3183).

like image 23
Michi Avatar answered Nov 16 '22 16:11

Michi


Check the following:

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

applicationFactory.getApplication().addDefaultValidatorId(BeanValidator.VALIDATOR_ID);
applicationFactory.getApplication().addValidator(BeanValidator.VALIDATOR_ID, BeanValidator.class.getName());
like image 30
Abarre Avatar answered Nov 16 '22 16:11

Abarre


This is does work with Mojara 2.2.2 but doesn't with newer versions. Thanks to Michail for the hint. Here is another way to preconfigure 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) {

    }
}
like image 29
ievgen Avatar answered Nov 16 '22 16:11

ievgen