Search code examples
javajarjbossclassloading

JBoss classloading IncompatibleClassChangeError


I'm migrating a project from JBoss 5 to 6.4. In the process I've updated several jar files in my build. I had several ClassCastExceptions which I resolved by taking the version of the specific classes from a jar in the JBoss system modules and using that in my app build. I've done so with two jars, jbossweb-7.5.26.Final-redhat-1.jar and jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar which contain the classes org.apache.catalina.connector.Request and javax.servlet.http.HttpServletRequest respectively. I'm using both of those jars as libs in my app build and all is compiling without error or warning. I've confirmed that when I remove those libs the app fails to compile as it can't find the included refernced classes, so I know I'm not actually referencing some other copy of those classes in my build. The app is deploying fine, but when I try hitting it I get an exception

JBWEB001018: An exception or error occurred in the container during the request processing: java.lang.IncompatibleClassChangeError: Class org.apache.catalina.connector.Request does not implement the requested interface javax.servlet.http.HttpServletRequest

When I look at the class definitions from the jars in my editor (JDeveloper 12c) I can see that org.apache.catalina.connector.Request as defined in jbossweb-7.5.26.Final-redhat-1 does in fact implement javax.servlet.http.HttpServletRequest as defined in jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar.

I turned on verbose logging of classloading (JAVA_OPT -verbose:class), and confirmed that as JBoss is loading those two classes they are in fact being loaded from those two jar files, not some other one I didn't know about. I can see in my developer tool that the .class files I'm including in my project are from those same two jar files.

Possibly relevant, the classloading logs say JBoss is loading org.apache.catalina.connector.Request from RedHat/JBoss/EAP-6.4.0/modules/system/layers/base/.overlays/layer-base-jboss-eap-6.4.18.CP/org/jboss/as/web/main/. I'm not sure why it's using that copy/location rather than RedHat\JBoss\EAP-6.4.0\modules\system\layers\base\org\jboss\as\web\main.

So what gives? What I read on the error would suggest to me that jboss-servlet-api_3.0_spec-1.0.2.Final-redhat-2.jar was compiled against a different version of HttpServletRequest than jbossweb-7.5.26.Final-redhat-1 includes.

Is that interpretation or the error correct? Does JBoss 6.4 really ship with incompatible jar files in its system modules? If so what versions of these jars do I need and how to I check compatibility? And can I safely switch to a different jar file without introducing more incompatibilities with other jars? What other causes might I be missing? Any help much appreciated here.


Solution

  • Looks like the issue was that I was not using the modules.xml correctly. I needed to add dependencies for the two packages in my module.xml file

       <dependencies>
          <module name="org.jboss.as.web"/>
          <module name="javax.servlet.api"/>
       </dependencies>
    

    I had previously added those modules to my war file's jboss-deployment-structure.xml and that did not do the trick and left me with ClassNotFoundExceptions. My Jboss-deployment-structure.xml now just references my own custom module as a dependency, which in turn has dependencies of its own.

    I still don't understand what was causing the previous error, as it's all the same versions of the jar files in question so I don't know where a conflict was, but this got the error to go away and no more ClassNotFoundExceptions.