Wednesday, May 23, 2018

JBoss Deployment Error: java.lang.LinkageError: loader constraint violation

Getting deployment errors are inevitable. One can't escape from it. Recently I have got a deployment error i.e. java.lang.LinkageError: loader constraint violation while deploying my Maven based application in JBoss. Good news is, I have solved this issue. Along with the root cause of the issue and it's solutions, today we would also discuss the approach that I have used to solve this issue because using similar approach one could troubleshoot many other similar issues.

Let me share the technology stack and deployment logs first before getting in much details. Also one information, I haven't got any Maven error while building the application.

1. Technology Stack

- JDK 7
- Apache Maven 3.5.2
- JBoss-6.1.0.Final

2. Deployment Logs

16:06:22,202 INFO  [TomcatDeployment] deploy, ctxPath=/QuartzScheduler
16:06:22,249 INFO  [[/QuartzScheduler]] QuartzInitializer: Quartz Initializer Servlet loaded, initializing Scheduler...
16:06:22,249 ERROR [[/QuartzScheduler]] StandardWrapper.Throwable: java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory(
)Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/jboss/classloader/spi/base/BaseClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/jboss/cl
assloader/spi/base/BaseClassLoader) for resolved class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type taticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory; used
 in the signature
        at org.slf4j.LoggerFactory.getILoggerFactory( [:1.6.6]
        at org.slf4j.LoggerFactory.getLogger( [:1.6.6]
        at org.slf4j.LoggerFactory.getLogger( [:1.6.6]
        at org.quartz.impl.StdSchedulerFactory.( [:]
        at [:]
        at [:]
        at org.apache.catalina.core.StandardWrapper.loadServlet( [:6.1.0.Final]
        at org.apache.catalina.core.StandardWrapper.load( [:6.1.0.Final]
        at org.apache.catalina.core.StandardContext.loadOnStartup( [:6.1.0.Final]
        at org.apache.catalina.core.StandardContext.start( [:6.1.0.Final]
        at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeployInternal( [:6.1.0.Final]
        at org.jboss.web.tomcat.service.deployers.TomcatDeployment.performDeploy( [:6.1.0.Final]
        at org.jboss.web.deployers.AbstractWarDeployment.start( [:6.1.0.Final]
        at org.jboss.web.deployers.WebModule.startModule( [:6.1.0.Final]
        at org.jboss.web.deployers.WebModule.start( [:6.1.0.Final]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.7.0]
        at sun.reflect.NativeMethodAccessorImpl.invoke( [:1.7.0]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke( [:1.7.0]
        at java.lang.reflect.Method.invoke( [:1.7.0]
        at [:6.0.0.GA]
        at [:6.0.0.GA]
        at [:6.0.0.GA]
        at [:6.0.0.GA]
        at [:6.0.0.GA]
        at org.jboss.system.microcontainer.ServiceProxy.invoke( [:2.2.0.SP2]
        at $Proxy41.start(Unknown Source)  

3. Analyzing the Logs

Logs are true saviour for any developer. If one could analyze the logs properly more then more than half of the job is already done. See the highlighted part of the above logs, we have got some useful information about the error:
- the error was due to method resolution as the class loader of the current class and the class loader for the resolved class have different class objects.
- also the error was related to slf4j jar

But wait, have I used slf4j related jar as my dependency in POM.xml? 
The answer would No. Although I have used log4j as my direct dependency in POM.xml but I haven't used slf4j related any jar as my direct dependency in POM.xml.

Then again two questions arises if we though about the cause of the error,
Q1: My application must be getting slf4j related jar as indirect dependency from somewhere which is conflicting with JBoss libraries at run time. Is it so or not?
Q2: Is it because of two libraries i.e. log4j & slf4j, JBoss is throwing Linkage error at run time? 

Therefore if we have to find the exact jar from the application which has slf4j related jar as its indirect dependency and exclude it from that jar then problem should get solved. Let's try out this.

4. Solution

  • Find out the dependency tree of the application
    One could use mvn dependency:tree command to get the dependency tree of any Maven projects. Let's run it and see the output. See, quartz related jar has slf4j-api jar as it's indirect dependency.
    mvn dependency:tree
    Building QuartzScheduler_Maven 1.0-SNAPSHOT
    +- javax.transaction:javax.transaction-api:jar:1.2:provided
    +- org.quartz-scheduler:quartz:jar:2.2.1:compile
    |  +- c3p0:c3p0:jar:
    |  \- org.slf4j:slf4j-api:jar:1.6.6:compile
    +- log4j:log4j:jar:1.2.17:compile
    \- junit:junit:jar:4.10:test
       \- org.hamcrest:hamcrest-core:jar:1.1:test
    Total time: 2.181 s
    Finished at: 2018-05-22T16:41:58+05:30
    Final Memory: 9M/22M
  • Dependency Exclusion in Maven
    Let's exclude slf4j-api jar from quartz then again build & deploy the application and see whether it solves the issue.
    Built and deployed the application again, it worked and now the deployment logs are clean. 

5. Conclusion

Even though, if one doesn't get any kind of Maven errors while building the application, it doesn't imply that the application would be successfully deployed always. One could get many deployment errors either due to multiple versions of the same jars(direct & indirect dependencies) or due to multiple jars conflict or due to jar conflict between the container's jar and compile time provided jar. In all such instances, it's better to go through the dependency tree of the project (use  mvn dependency:tree command) and if any conflicts found then exclude it. Happy Learning!!