Jetty Maven 插件(码头:运行 目标)+ Weld CDI + JSF 2.2 = ViewScoped bean 上的 NPE

Jetty Maven plugin (jetty:run goal) + Weld CDI + JSF 2.2 = NPE on ViewScoped beans

在 Web 应用程序中使用以下(最新的)组件:

Jetty maven 插件 9.2.6.v20141205

焊接 CDI 2.2。9.Final

Mojarra JSF 2.2.10

该应用的 web.xml 包含以下侦听器:

org.jboss.weld.environment.servlet.BeanManagerResourceBindingListener
com.sun.faces.config.ConfigureListener

第一个侦听器向 JNDI 注册 BeanManager。 第二个侦听器初始化 JSF 并在 JNDI 中查找 BeanManager。

当 jetty maven 插件以 "jetty:run-war" 目标运行时,或者当应用程序 运行 与嵌入式 jetty 独立时,此设置工作正常。

然而,当 运行 它具有 "jetty:run" 目标时,在第一个侦听器中注册的 BeanManager 在 JSF 中不可见,导致 ViewScoped bean 上的 NPE。

在我看来这像是范围或可见性问题,但我无法弄清楚 - jetty:run 和 jetty:run-war.[=13 之间有什么区别=]

我尝试在 web.xml 中添加 "resource-env-ref" 条目并在各种 Jetty 的 xml 文件中创建 BeanManager(jetty.xml、jetty-env.xml、 jetty-context.xml) 但它并没有改变任何东西。

更新:

NPE发生在会话失效时;由于在 JSF 中没有注册 BeanManager,因此无法销毁 ViewScoped bean。请参阅下面的堆栈跟踪:

Caused by: java.lang.NullPointerException at com.sun.faces.application.view.ViewScopeContextManager.destroyBeans(ViewScopeContextManager.java:171) at com.sun.faces.application.view.ViewScopeContextManager.sessionDestroyed(ViewScopeContextManager.java:339) at com.sun.faces.application.view.ViewScopeManager.sessionDestroyed(ViewScopeManager.java:369) at com.sun.faces.application.WebappLifecycleListener.sessionDestroyed(WebappLifecycleListener.java:181) at com.sun.faces.config.ConfigureListener.sessionDestroyed(ConfigureListener.java:399) at org.eclipse.jetty.server.session.AbstractSessionManager.removeSession(AbstractSessionManager.java:772) at org.eclipse.jetty.server.session.AbstractSession.invalidate(AbstractSession.java:326) at com.sun.faces.context.ExternalContextImpl.invalidateSession(ExternalContextImpl.java:783)

Dimitri 在码头项目上提出了一个错误:https://bugs.eclipse.org/bugs/show_bug.cgi?id=462179

错误包含对问题原因的完整描述。简而言之,Weld 使 BeanManager 可用于 JSF 的方式不适用于未组装的 webapps(mvn jetty:run 就是这种情况),仅适用于 war 文件(即 mvn jetty:run-war 会起作用)。

一月

只需使用您的 web.xml 添加此侦听器。我将 openwebbeans 用作 CDI 容器,但它似乎可以与任何其他容器一起使用。

package com.devadmin.computec.config;

import com.sun.faces.RIConstants;

import javax.enterprise.inject.spi.CDI;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class CustomServletContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        sce.getServletContext().setAttribute(RIConstants.CDI_BEAN_MANAGER, CDI.current().getBeanManager());
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }
}