4 Replies Latest reply on May 23, 2013 11:45 AM by epborcyk

    java.lang.NoClassDefFoundError encountered when using custom module

    epborcyk

      Hello-

       

      I am using JBoss 7.1.1 and am receiving a java.lang.NoClassDefFoundError when trying to instantiate a class that exists in a module that is a dependency of my application WAR.

       

      My application WAR contains a jboss-deployment-structure.xml file that declares the module 'com.acme.triggers' as a dependency.

       

      <?xml version="1.0" encoding="UTF-8"?>

      <jboss-deployment-structure>

                <deployment>

             <dependencies>

               <module name="com.acme.triggers"/>

            </dependencies>

                </deployment>

      </jboss-deployment-structure>

       

      The com.acme.triggers module contains a jar with a single java class:

       

      package com.acme.trigger;

      import com.company.triggers.impl.AbstractTrigger;

       

      public class Trigger extends AbstractTrigger {

      }

       

      I compiled my Trigger class with the triggers-api.jar which contains the com.company.triggers.impl.AbstractTrigger class from my application but do not include it in the JBoss module.

       

      The AbstractTrigger class is packaged in my application WAR in the WEB-INF/lib directory as follows WEB-INF/lib/triggers-api.jar. 

       

      In my application code I am trying to instantiate the Trigger class using:

       

      Class.forName("com.acme.trigger.Trigger");

       

      Below is the stacktrace that I receive:

       

      10:02:43,129 WARN  [org.jboss.modules] (http-hostname-10.64.89.69-9080-2) Failed to define class com.acme.trigger.Trigger in Module "com.acme.triggers:main" from local module loader @2adb1d4 (roots: C:\jboss-as-7.1.1.Final\modules,C:\jboss-as-7.1.1.Final\sl\modules): java.lang.LinkageError: Failed to link com/acme/trigger/Trigger (Module "com.acme.triggers:main" from local module loader @2adb1d4 (roots: C:\jboss-as-7.1.1.Final\modules,C:\jboss-as-7.1.1.Final\sl\modules))

                at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:396)

                at org.jboss.modules.ModuleClassLoader.loadClassLocal(ModuleClassLoader.java:243)

                at org.jboss.modules.ModuleClassLoader$1.loadClassLocal(ModuleClassLoader.java:73)

                at org.jboss.modules.Module.loadModuleClass(Module.java:517)

                at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:182)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)

                at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)

                at com.company.web.triggers.TriggerDefinition$CustomClassLoader.loadClass(TriggerDefinition.java:381) [app-core-10.5.jar:]

                at java.lang.ClassLoader.loadClass(ClassLoader.java:247) [rt.jar:1.6.0_43]

                at com.company.web.triggers.TriggerDefinition.setTriggerClass(TriggerDefinition.java:351) [sl-core-10.5.jar:]

                at com.company.web.triggers.TriggerDefinition.<init>(TriggerDefinition.java:73) [sl-core-10.5.jar:]

                at com.company.service.triggers.TriggerMgmtBlBean.processTriggerDefinitionElement(TriggerMgmtBlBean.java:369) [sl-core-10.5.jar:]

                at com.company.service.triggers.TriggerMgmtBlBean.loadTriggerDefinitions(TriggerMgmtBlBean.java:337) [sl-core-10.5.jar:]

                at com.company.service.triggers.TriggerMgmtBlBean.loadConfig(TriggerMgmtBlBean.java:276) [sl-core-10.5.jar:]

                at com.company.service.triggers.TriggerMgmtBlBean.loadConfig(TriggerMgmtBlBean.java:252) [sl-core-10.5.jar:]

                at com.company.service.triggers.TriggerMgmtBlBean.getTriggerSet(TriggerMgmtBlBean.java:229) [sl-core-10.5.jar:]

                at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_43]

                at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_43]

                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_43]

                at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_43]

                at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317) [spring-aop-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) [spring-aop-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) [spring-aop-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) [spring-tx-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) [spring-aop-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204) [spring-aop-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at com.sun.proxy.$Proxy92.getTriggerSet(Unknown Source)

                at com.company.service.triggers.TriggerMgmtCommandProcessor.getTriggerSet(TriggerMgmtCommandProcessor.java:98) [sl-core-10.5.jar:]

                at com.company.web.triggers.Controller.getTriggerSet(Controller.java:115) [sl-core-10.5.jar:]

                at com.company.system.controller.HttpCommandDispatcher.processTriggers(HttpCommandDispatcher.java:488) [sl-core-10.5.jar:]

                at com.company.system.controller.HttpCommandDispatcher.executeCommand(HttpCommandDispatcher.java:237) [sl-core-10.5.jar:]

                at com.company.system.controller.ServletController.doPost(ServletController.java:84) [sl-core-10.5.jar:]

                at javax.servlet.http.HttpServlet.service(HttpServlet.java:754) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]

                at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]

                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]

                at com.company.commons.usercontext.web.UserContextFilter$1.executeWithinContext(UserContextFilter.java:91) [sl-core-10.5.jar:]

                at com.company.commons.usercontext.web.UserContextFilter$1.executeWithinContext(UserContextFilter.java:87) [sl-core-10.5.jar:]

                at com.company.commons.usercontext.UserContextProvider.executeWithinContext(UserContextProvider.java:36) [sl-core-10.5.jar:]

                at com.company.commons.usercontext.web.UserContextFilter.doFilter(UserContextFilter.java:87) [sl-core-10.5.jar:]

                at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) [spring-web-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) [spring-web-3.2.0.RELEASE.jar:3.2.0.RELEASE]

                at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]

                at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]

                at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]

                at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]

                at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]

                at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]

                at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]

                at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_43]

      Caused by: java.lang.NoClassDefFoundError: com/company/triggers/impl/AbstractTrigger

                at java.lang.ClassLoader.defineClass1(Native Method) [rt.jar:1.6.0_43]

                at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) [rt.jar:1.6.0_43]

                at java.lang.ClassLoader.defineClass(ClassLoader.java:615) [rt.jar:1.6.0_43]

                at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) [rt.jar:1.6.0_43]

                at org.jboss.modules.ModuleClassLoader.doDefineOrLoadClass(ModuleClassLoader.java:327)

                at org.jboss.modules.ModuleClassLoader.defineClass(ModuleClassLoader.java:391)

                ... 56 more

      Caused by: java.lang.ClassNotFoundException: com.company.triggers.impl.AbstractTrigger from [Module "com.acme.triggers:main" from local module loader @2adb1d4 (roots: C:\jboss-as-7.1.1.Final\modules,C:\jboss-as-7.1.1.Final\sl\modules)]

                at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:190)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:468)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:456)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClassChecked(ConcurrentClassLoader.java:423)

                at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:398)

                at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:120)

                ... 62 more

       

      Thanks

       

      -Eric

        • 1. Re: java.lang.NoClassDefFoundError encountered when using custom module
          epborcyk

          So I am curious does anyone out there allow their customers to write custom code based on application provided APIs?  If so that is what I am trying to do here.  It seems to me that the only way that I can support this functionality is to deploy the custom code as a JBoss Module and designate the custom module as a dependency of my application war.

          • 2. Re: java.lang.NoClassDefFoundError encountered when using custom module
            nickarls

            Does the AbstractTrigger contain anything useful? I guess for this scenario, you would have to include all required jar:s in the module and then declare a war->module dep. You will probably also have to use slots when the API matures and you'll have different versions (the drawback of outside-war-dependencies)

            • 3. Re: java.lang.NoClassDefFoundError encountered when using custom module
              epborcyk

              Hi Nicklas-

               

              The AbstractTrigger really just implements the Trigger Interface methods (mainly accessor methods) and sets of log4j logger up with the applications BaseLog class.

               

              I tried adding the application jar that has the AbstractTrigger class in it to the module but that is creating other problems.  Since the classloading precedence is System, User, Local, Inter.  The AbstractTrigger is now loaded from the module classloader instead of the application classloader so now I am getting an IllegalAccessError exception as the jar for the BaseLog is not included with the module. I don't want to add the jar for the BaseLog class to the module as that contains some of our applications core code and brings along many dependencies.

               

              I did try to add the war as a dependency to the module but JBoss ended up hanging.  I am guessing I created a circular dependency as the Application already depends on the module and then I made the module dependent on the Application.

               

              In JBoss 5.1 I just created a CustomClassLoader that had a parent of  Thread.currentThread().getContextClassLoader() and added the clients jar to the classloader by adding a directory to the CLASSPATH and searching that directory for client jars

               

              -Eric

              • 4. Re: java.lang.NoClassDefFoundError encountered when using custom module
                epborcyk

                 

                I was unable to implement the above using JBoss Modules.  However, I found an excellent article called Module Compatible Classloading Guide by Jason Greene.  It seems that our application takes advantage of the notion of Hierarchical Classloaders (explanation below).  So in order to support the current functionality using JBoss 7.1.1 I had to write a Custom Classloader that loads the additional classes.

                 

                 

                Hierarchical Emulation - This is a worst case workaround that should only be used as a last resort. In the unfortunate case where a framework expects both deployment classes and it's own classes to be on the same classloader,  a custom classloader can be created which delegates first to the deployment classsloader and second to frameworks defining classloader. This classloader can the be swapped to the TCCL as described above, or somehow passed to the framework via a mechnism it exposes. This has the undesirable effect of a possible conflict between a user's implementation choices and the frameworks. However, it at least does not pollute the deployment module.

                 

                https://community.jboss.org/wiki/ModuleCompatibleClassloadingGuide