设置当前线程上下文 class 加载程序后出现 JSF VisitContextFactory 错误

JSF VisitContextFactory error after setting current thread context class loader

我正在使用 GlassFish 4.1、Mojarra 2.2.7、PrimeFaces 5.2。我正在尝试在 JSF 操作中动态启动 JPA 实体管理器。实体管理器需要加载 JPA 实体 classes 才能执行查询。我在运行时创建并构建了 JPA JAR,所以我尝试将它添加到当前线程中的 class 加载程序:

File jpaJar = getMyJpaJarFile();
ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
URLClassLoader urlClassLoader = new URLClassLoader(
  new URL[]{jpaJar.toURI().toURL()}
, currentThreadClassLoader
);
Thread.currentThread().setContextClassLoader(urlClassLoader);

这使我能够执行 JPQL 查询,但它让我陷入了这个 JSF 混乱:

Severe:   Unable to obtain InjectionProvider from init time FacesContext. Does this container implement the Mojarra Injection SPI?
Severe:   Application was not properly initialized at startup, could not find Factory: javax.faces.component.visit.VisitContextFactory. Attempting to find backup.
Severe:   Error Rendering View[/my.xhtml]
java.lang.IllegalStateException: Could not find backup for factory javax.faces.component.visit.VisitContextFactory. 
  at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:1135)
  at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:379)
  at javax.faces.component.visit.VisitContext.createVisitContext(VisitContext.java:219)
  at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.saveView(FaceletPartialStateManagementStrategy.java:468)
  at com.sun.faces.application.StateManagerImpl.saveView(StateManagerImpl.java:89)
  at javax.faces.application.StateManager.getViewState(StateManager.java:593)
  at com.sun.faces.context.PartialViewContextImpl.renderState(PartialViewContextImpl.java:483)
  at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:325)
  at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:60)
  at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:219)
  at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:1004)
  at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856)
  at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:430)
  at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:133)
  at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
  at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
  at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)

如何在不破坏 JSF 的情况下修改 class 加载程序,或解决此问题?

我重现了它,当我将 GlassFish 捆绑的 Mojarra 2.2.7 升级到当前可用的 2.2.11(只需替换 /modules 文件夹中的 javax.faces.jar 时,问题就消失了。事实证明,它已经根据 issue 3341 "Mojarra not resilient to ThreadContextClassLoader replacement".

在 Mojarra 2.2.9 中得到确认和修复