mojarra icon indicating copy to clipboard operation
mojarra copied to clipboard

Mojarra impl gives NPE if user accidentally uses non-Mojarra API with Mojarra JSF impl

Open aguibert opened this issue 8 years ago • 7 comments
trafficstars

Using Mojarra impl 2.2.14 from: https://mvnrepository.com/artifact/com.sun.faces/jsf-impl/2.2.14

Since the Mojarra JSF implementation only works with the Mojarra set of JSF API, it would be nice if the Mojarra JSF implementation could clearly warn the user if they are not using the Mojarra set of JSF API early on in JSF initialization.

Additionally, it would be nice if some future rev of the JSF spec could come out with an implementation-agnostic set of API.

Here is the stack trace I got when I accidentally used the Mojarra JSF API with MyFaces JSF impl:

Stack Dump = java.lang.NullPointerException
	at com.sun.faces.config.InitFacesContext.cleanupInitMaps(InitFacesContext.java:280)
	at com.sun.faces.config.InitFacesContext.<init>(InitFacesContext.java:106)
	at com.sun.faces.config.FacesInitializer.onStartup(FacesInitializer.java:130)
	at com.ibm.ws.webcontainer.webapp.WebApp.initializeServletContainerInitializers(WebApp.java:2495)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1002)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6574)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:467)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:462)
	at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1123)
	at com.ibm.ws.webcontainer.osgi.WebContainer.access$000(WebContainer.java:105)
	at com.ibm.ws.webcontainer.osgi.WebContainer$2.run(WebContainer.java:935)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:522)
	at java.util.concurrent.FutureTask.run(FutureTask.java:277)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1153)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.lang.Thread.run(Thread.java:785)

aguibert avatar Nov 08 '17 23:11 aguibert

Also, if things are mixed up the other way around (Mojarra API w/ other JSF impl) we get the following error because the javax.faces.FactoryFinderInstance needs to import the com.sun.faces.spi.InjectionProvider class.

[11/8/17 18:08:27:380 CST] 00000028 com.ibm.ws.webcontainer.webapp                               E SRVE0283E: Exception caught while initializing context: java.lang.NoClassDefFoundError: com.sun.faces.spi.InjectionProvider
	at javax.faces.FactoryFinderInstance.copyInjectionProviderFromFacesContext(FactoryFinderInstance.java:174)
	at javax.faces.FactoryFinderInstance.<init>(FactoryFinderInstance.java:157)
	at javax.faces.CurrentThreadToServletContext.getApplicationFactoryManager(CurrentThreadToServletContext.java:150)
	at javax.faces.CurrentThreadToServletContext.getApplicationFactoryManager(CurrentThreadToServletContext.java:91)
	at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:279)
	at org.apache.myfaces.context.servlet.FacesContextImplBase.getApplication(FacesContextImplBase.java:169)
	at org.apache.myfaces.context.servlet.FacesContextImplBase.getELContext(FacesContextImplBase.java:231)
	at javax.faces.component.UIViewRoot.setLocale(UIViewRoot.java:1488)
	at org.apache.myfaces.webapp.AbstractFacesInitializer._createFacesContext(AbstractFacesInitializer.java:529)
	at org.apache.myfaces.webapp.AbstractFacesInitializer.initStartupFacesContext(AbstractFacesInitializer.java:501)
	at org.apache.myfaces.webapp.StartupServletContextListener.contextInitialized(StartupServletContextListener.java:115)
	at com.ibm.ws.webcontainer.webapp.WebApp.notifyServletContextCreated(WebApp.java:2384)
	at com.ibm.ws.webcontainer31.osgi.webapp.WebApp31.notifyServletContextCreated(WebApp31.java:514)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:1012)
	at com.ibm.ws.webcontainer.webapp.WebApp.initialize(WebApp.java:6574)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApp(DynamicVirtualHost.java:467)
	at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost.startWebApplication(DynamicVirtualHost.java:462)
	at com.ibm.ws.webcontainer.osgi.WebContainer.startWebApplication(WebContainer.java:1123)
	at com.ibm.ws.webcontainer.osgi.WebContainer.access$000(WebContainer.java:105)
	at com.ibm.ws.webcontainer.osgi.WebContainer$2.run(WebContainer.java:935)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:522)
	at java.util.concurrent.FutureTask.run(FutureTask.java:277)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1153)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.lang.Thread.run(Thread.java:785)
Caused by: java.lang.ClassNotFoundException: com.sun.faces.spi.InjectionProvider
	at com.ibm.ws.classloading.internal.AppClassLoader.findClassCommonLibraryClassLoaders(AppClassLoader.java:504)
	at com.ibm.ws.classloading.internal.AppClassLoader.findClass(AppClassLoader.java:276)
	at java.lang.ClassLoader.loadClassHelper(ClassLoader.java:797)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:775)
	at com.ibm.ws.classloading.internal.AppClassLoader.findOrDelegateLoadClass(AppClassLoader.java:482)
	at com.ibm.ws.classloading.internal.AppClassLoader.loadClass(AppClassLoader.java:443)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:752)
	... 25 more

aguibert avatar Nov 09 '17 00:11 aguibert

Additionally, it would be nice if some future rev of the JSF spec could come out with an implementation-agnostic set of API.

I'd like to clarify here that JSF API is already implementation agnostic. It's just that MyFaces has chosen to write their own JSF API classes.

BalusC avatar Nov 09 '17 08:11 BalusC

The Mojarra API jar is only intended to be used to compile against. Due to historical reasons the API contains code indeed, which can not easily be undone.

The API jar should not be part of the runtime.

arjantijms avatar Nov 09 '17 08:11 arjantijms

I don't understand how the JSF API could be excluded at runtime, then where would javax.faces.* classes be loaded from? If I am truly misunderstanding this port, then the rest of this comment will all be moot.

I understand that JSF has a long history, and am not asking the API-Impl dependencies to be untangled here. I am just suggesting that a check could be made early on in JSF initialization to warn the user if this situation is detected. For example, checking javax.faces.FactoryFinder.class.getPackage().getImplementationTitle().toUpperCase().contains("MOJARRA")

aguibert avatar Nov 09 '17 14:11 aguibert

I don't understand how the JSF API could be excluded at runtime, then where would javax.faces.* classes be loaded from? If I am truly misunderstanding this port, then the rest of this comment will all be moot.

The only jar that should be on the runtime class path is the full mojarra jar, which contains both the API and implementation classes.

A proper JDK 9 build may make the existence of the API jar obsolete.

I'll try to see if we can do the kind of check you've asked for indeed, but maybe there are much more such places that would need guards. I'll think about this a little. Thx for your report!

arjantijms avatar Nov 09 '17 15:11 arjantijms

Thanks for clarifying Arjan! Where would someone get the full mojarra jar? I've been getting the individual pieces from maven here: https://mvnrepository.com/artifact/com.sun.faces/jsf-api/2.2.14 https://mvnrepository.com/artifact/com.sun.faces/jsf-impl/2.2.14

Side note: In case you are familiar with Liberty (or OpenLiberty), I'm working on a feature called jsfContainer-2.2 which will allow people to plug in a different JSF impl than the default one (MyFaces) and still get CDI integrations. I'm planning to include this check there as well, since people not very familiar with JSF (like myself) can make this mistake.

aguibert avatar Nov 09 '17 15:11 aguibert

Single JARs can be found in org.glassfish:javax.faces repo. https://mvnrepository.com/artifact/org.glassfish/javax.faces/2.2.15

BalusC avatar Nov 09 '17 15:11 BalusC