Undertow 可以与 JSF 一起使用吗?

Does Undertow work with JSF?

我正在尝试使用 Mojarra 启动 Undertow,但出现异常。 如何修复此错误并使用 JSF?

,但是这个方案对我的没有影响

HelloWorldServer.java(参考 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>

异常:

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.call (DeploymentManagerImpl.java:584)
    at io.undertow.servlet.core.DeploymentManagerImpl.call (DeploymentManagerImpl.java:555)
    at io.undertow.servlet.core.ServletRequestContextThreadSetupAction.call (ServletRequestContextThreadSetupAction.java:42)
    at io.undertow.servlet.core.ContextClassLoaderSetupAction.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.run (ExecJavaMojo.java:282)
    at java.lang.Thread.run (Thread.java:844)

请勿使用 Mojarra 2.4.0 尚未,截至发帖时尚未发布。它必须放在 maven 中才能从 Oracle 过渡到 Eclipse。

http://balusc.omnifaces.org/2018/04/do-not-use-orgglassfish-mojarra-240.html

因此请使用最新的 2.3.x 版本(撰写本文时为 2.3.5)

1.

实现方式与FacesInitializer#onStartup相同,所以main方法如下:

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.

托管 Bean 由 AnnotationScanTask with DelegatingAnnotationProvider 扫描,这是默认的 AnnotationProvider 实现。 因为 DelegatingAnnotationProvider 不扫描根 class 路径(但只扫描 /WEB-INF/classes(?)),我需要实现自定义 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(参考 AnnotationProviderFactory):

com.github.yukihane.java.undertow.service.MyAnnotationProvider

这里是完整的来源: https://github.com/yukihane/hello-undertow-mojarra