1

I have an application deployed in WAS 9 using custom jsf provider (set to DEFAULT in WAS). Jars are in a shared lib with an isolated class loader. Everything worked fine until we migrated from richfaces to primefaces. We use javax.faces 2.1.29 but for some reason primefaces seems to detect that we are using 2.2 and is making a call to a method that only exists in 2.2 (getPassThroughAttributes). Looking at the stack versions in play seem correct so I'm not sure why the 2.2 method call is being made. Anyone run into this?

> 3/19/19 17:19:07:671 CDT] 00000091 ServletWrappe E com.ibm.ws.webcontainer.servlet.ServletWrapper service SRVE0014E: Uncaught service() exception root cause Faces Servlet: javax.servlet.ServletException: javax/faces/component/UIComponent.getPassThroughAttributes(Z)Ljava/util/Map; (loaded from file:/opt/IBM/WebSphere/AppServer_2/trunkLib/javax.faces-2.1.29-10.jar by 
com.ibm.ws.classloader.CompoundClassLoader@abecddd0[library:trunkLib]
   Local ClassPath: /opt/IBM/WebSphere/AppServer_2/trunkLib/javax.faces-2.1.29-10.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/httpclient-4.5.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/httpcore-4.4.4.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/commons-codec-1.11.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/hk2-api-2.4.0-b34.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/hk2-locator-2.4.0-b34.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/hk2-utils-2.4.0-b34.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/javax.annotation-api-1.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/jaxrs-ri-2.22.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/jersey-guava-2.22.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/validation-api-1.1.0.Final.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/classes:/opt/IBM/WebSphere/AppServer_2/trunkLib/javassist-3.23.1-GA.jar
   Parent: com.ibm.ws.classloader.ProtectionClassLoader@a5c5ece8

and

> Caused by: java.lang.NoSuchMethodError: javax/faces/component/UIComponent.getPassThroughAttributes(Z)Ljava/util/Map; (loaded from file:/opt/IBM/WebSphere/AppServer_2/trunkLib/javax.faces-2.1.29-10.jar by 
com.ibm.ws.classloader.CompoundClassLoader@abecddd0[library:trunkLib]
   Local ClassPath: /opt/IBM/WebSphere/AppServer_2/trunkLib/javax.faces-2.1.29-10.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/httpclient-4.5.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/httpcore-4.4.4.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/commons-codec-1.11.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/hk2-api-2.4.0-b34.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/hk2-locator-2.4.0-b34.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/hk2-utils-2.4.0-b34.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/javax.annotation-api-1.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/jaxrs-ri-2.22.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/jersey-guava-2.22.2.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/validation-api-1.1.0.Final.jar:/opt/IBM/WebSphere/AppServer_2/trunkLib/classes:/opt/IBM/WebSphere/AppServer_2/trunkLib/javassist-3.23.1-GA.jar
   Parent: com.ibm.ws.classloader.ProtectionClassLoader@a5c5ece8
   Delegation Mode: PARENT_LAST) called from class org.primefaces.util.Jsf22Helper (loaded from file:/opt/IBM/WebSphere/AppServer_2/profiles/server1/installedApps/loggerheadNode03Cell/trunk80_war.ear/trunk80.war/WEB-INF/lib/primefaces-6.2.jar
belwood
  • 3,320
  • 11
  • 38
  • 45
seang
  • 11
  • 1

2 Answers2

1

It looks like PrimeFaces searches the classpath for JSF 2.2 classes - and unfortunately in this case PrimeFaces must be finding the those classes in the WAS-provided JSF 2.2 bundle. Moving primefaces-6.2 out of your application trunk80.war and into the isolated shared library trunkLib should resolve this.

wtlucy
  • 704
  • 3
  • 10
0

First lets begin that the PrimeFaces source is OPEN, it is easilly debugged. A simple search in the source (either locally in your IDE or in GitHub) will get you the source of Jsf22Helper.java. You can than inspect where this is being called. Running in debug mode is the easiest, but a search in the PrimeFaces repository in GitHub shows just one location in CoreRenderer.java

protected void renderDynamicPassThruAttributes(FacesContext context, UIComponent component) throws IOException {
    if (PrimeApplicationContext.getCurrentInstance(context).getEnvironment().isAtLeastJsf22()) {
        Jsf22Helper.renderPassThroughAttributes(context, component);
    }
}

Next you should inspect the

PrimeApplicationContext.getCurrentInstance(context).getEnvironment().isAtLeastJsf22()

And the getter for this returns a property that gets its boolean value from

atLeastJsf22 = LangUtils.tryToLoadClassForName("javax.faces.flow.Flow") != null;

In here you see that for determining the 'minimal' version, they try loading a class that is only present in JSF 2.2 or up. This means that no matter whether you use parent first classloading or not or independent of where you put PrimeFaces, if javax.faces.flow.Flow is on the classpath, PrimeFaces will think JSF 2.2 is available. It does not matter if JSF 2.1 is also on the classpath and even before JSF 2.2 since this specific class is not present in JSF2.1 and will always be loaded from the JSF 2.2 jars.

To fix this you have three options

  • Override the PrimeFaces PrimeEnvironment.java (e.g. via reading an explicit context property from the web.xml so you can optionally manually override the version detection and create a pull request for this with PrimeFaces so they can accept it as an improvement
  • 'Correct' the way to override the JSF version similar to How to make websphere 8.5 use mojarra not myfaces
  • Switch to JSF 2.2

The latter would be the best and might even just be working out of the box.

Kukeltje
  • 12,223
  • 4
  • 24
  • 47