I'm trying to boot-up Undertow with Mojarra, but an exception occurs. How to fix this error and work with JSF?
Here is similar question, but this solution does not affect mine.
HelloWorldServer.java
(refs Undertow Servlet):
public class HelloWorldServer {
public static void main(String[] args) throws ServletException {
DeploymentInfo servletBuilder = Servlets.deployment()
.setClassLoader(HelloWorldServer.class.getClassLoader())
.setContextPath("/myapp")
.setDeploymentName("test.war")
.addServlets(Servlets.servlet("FacesServlet", FacesServlet.class)
.addMapping("*.xhtml")
.setLoadOnStartup(1));
DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder);
manager.deploy();
PathHandler path = Handlers.path(Handlers.redirect("/myapp"))
.addPrefixPath("/myapp", manager.start());
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(path)
.build();
server.start();
}
}
pom.xml
:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<undertow.version>2.0.9.Final</undertow.version>
</properties>
<dependencies>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-core</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>io.undertow</groupId>
<artifactId>undertow-servlet</artifactId>
<version>${undertow.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.faces</artifactId>
<version>2.3.5</version>
</dependency>
</dependencies>
exception:
Jul 07, 2018 9:57:50 PM javax.faces.FactoryFinderInstance copyInjectionProviderFromFacesContext
SEVERE: Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?
Jul 07, 2018 9:57:50 PM javax.faces.FactoryFinderInstance logNoFactory
SEVERE: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory. Attempting to find backup.
[WARNING]
java.lang.IllegalStateException: Could not find backup for factory javax.faces.context.FacesContextFactory.
at javax.faces.FactoryFinderInstance.notNullFactory (FactoryFinderInstance.java:548)
at javax.faces.FactoryFinderInstance.getFactory (FactoryFinderInstance.java:231)
at javax.faces.FactoryFinder.getFactory (FactoryFinder.java:303)
at javax.faces.webapp.FacesServlet.acquireFacesContextFactory (FacesServlet.java:524)
at javax.faces.webapp.FacesServlet.init (FacesServlet.java:364)
at io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed (LifecyleInterceptorInvocation.java:117)
at io.undertow.servlet.core.ManagedServlet$DefaultInstanceStrategy.start (ManagedServlet.java:300)
at io.undertow.servlet.core.ManagedServlet.createServlet (ManagedServlet.java:140)
at io.undertow.servlet.core.DeploymentManagerImpl$2.call (DeploymentManagerImpl.java:584)
at io.undertow.servlet.core.DeploymentManagerImpl$2.call (DeploymentManagerImpl.java:555)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call (ServletRequestContextThreadSetupAction.java:42)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call (ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.core.DeploymentManagerImpl.start (DeploymentManagerImpl.java:597)
at com.github.yukihane.java.undertow.HelloWorldServer.main (HelloWorldServer.java:27)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke (Method.java:564)
at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:282)
at java.lang.Thread.run (Thread.java:844)
Implement same as FacesInitializer#onStartup, so main
method is like:
DeploymentInfo servletBuilder = Servlets.deployment()
.setClassLoader(HelloWorldServer.class.getClassLoader())
.setContextPath("/myapp")
.setDeploymentName("test.war")
.addServlets(Servlets.servlet("FacesServlet", FacesServlet.class)
.addMappings("/faces/*", "*.jsf", "*.faces", "*.xhtml")
.setLoadOnStartup(1))
.addServletContextAttribute(RIConstants.FACES_INITIALIZER_MAPPINGS_ADDED, Boolean.TRUE)
.addListener(new ListenerInfo(com.sun.faces.config.ConfigureListener.class))
.setResourceManager(new ClassPathResourceManager(HelloWorldServer.class.getClassLoader(), "static"));
2.
Managed Beans are scanned by AnnotationScanTask
with DelegatingAnnotationProvider
, that is default AnnotationProvider
implementation.
Because DelegatingAnnotationProvider
does not scan root class path (but only /WEB-INF/classes
(?)), I need implement custom AnnotationProvider
.
MyAnnotationProvider.java
:
package com.github.yukihane.java.undertow.service;
public class MyAnnotationProvider extends DelegatingAnnotationProvider {
public MyAnnotationProvider(ServletContext sc) {
super(sc);
}
@Override
public Map<Class<? extends Annotation>, Set<Class<?>>> getAnnotatedClasses(Set<URI> urls) {
Map<Class<? extends Annotation>, Set<Class<?>>> parentRes = super.getAnnotatedClasses(urls);
// simplified implementation, without annotations scan
Map<Class<? extends Annotation>, Set<Class<?>>> ret = new HashMap<>(parentRes);
Set<Class<?>> parentSet = ret.get(ManagedBean.class);
Set<Class<?>> set = (parentSet == null) ? new HashSet<>() : new HashSet<>(parentSet);
set.add(Hello.class);
ret.put(ManagedBean.class, set);
return ret;
}
}
META-INF/services/com.sun.faces.spi.annotationprovider
(refs AnnotationProviderFactory
):
com.github.yukihane.java.undertow.service.MyAnnotationProvider
Here is complete sources: https://github.com/yukihane/hello-undertow-mojarra