Stuart Watt
Stuart Watt

Reputation: 5401

Inexplicably unresolvable IncompatibleClassChangeError in jetty-maven-plugin with Spring

I'm working on a Restlet application issue and thought it would be great to set up a Github repository containing a cut-down version of the application to test out. However, it's never that easy...

The repository is here: https://github.com/morungos/restlet-spring-static-files

Basically, the problem is that whenever I try to run it using mvn jetty:run-war (which I actually need to do to test out the restlet issue) I get the following backtrace:

java.lang.IncompatibleClassChangeError: class org.springframework.cglib.core.DebuggingClassWriter has interface org.springframework.asm.ClassVisitor as super class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:455)
at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
at java.net.URLClassLoader$1.run(URLClassLoader.java:367)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:415)
at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:377)
at org.springframework.cglib.core.DefaultGeneratorStrategy.getClassVisitor(DefaultGeneratorStrategy.java:30)

The part that's interesting is that the original application -- even when I had it use the exact same pom.xml, did not show the same problem for the same command. Both seem to be fine with mvn jetty:run, but the Restlet issue needs a war file to test against.

Now I've seen this issue and it usually an ASM/CGLIB conflict, and when I checked the dependencies, both Jetty and Spring do use different ASM systems, but I figure where or how to set the dependencies right to make this work. And even if I could, I can't figure out why it works in one application and not in a slightly smaller version (which sadly I can't yet show).

Any thoughts on how to resolve this? I've tried adding an exclusion to the Jetty dependency that's causing the issue (jetty-annotations) but then Jetty failed hideously, so it's clearly required.

Upvotes: 0

Views: 355

Answers (2)

John R
John R

Reputation: 2096

I took a look at your pom using mvn dependency:tree. You have a mix of Spring 3.2 and 3.1 JARs. The Spring 3.2 JARs are being pulled in by Restlet.

[INFO] +- org.restlet.jee:org.restlet:jar:2.3.1:compile
[INFO] +- org.restlet.jee:org.restlet.ext.servlet:jar:2.3.1:compile
[INFO] +- org.restlet.jee:org.restlet.ext.spring:jar:2.3.1:compile
[INFO] |  +- cglib:cglib-nodep:jar:2.2:compile
[INFO] |  +- commons-logging:commons-logging:jar:1.1.3:compile
[INFO] |  +- org.springframework:spring-beans:jar:3.2.6.RELEASE:compile
[INFO] |  +- org.springframework:spring-core:jar:3.2.6.RELEASE:compile
[INFO] |  +- org.springframework:spring-expression:jar:3.2.6.RELEASE:compile
[INFO] |  +- org.springframework:spring-web:jar:3.2.6.RELEASE:compile
[INFO] |  |  \- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:3.2.6.RELEASE:compile
[INFO] +- javax.servlet:javax.servlet-api:jar:3.0.1:compile
[INFO] +- org.springframework:spring-context:jar:3.1.4.RELEASE:runtime
[INFO] |  +- org.springframework:spring-aop:jar:3.1.4.RELEASE:compile
[INFO] |  \- org.springframework:spring-asm:jar:3.1.4.RELEASE:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] +- org.slf4j:slf4j-jdk14:jar:1.7.7:compile
[INFO] \- junit:junit:jar:4.9:test
[INFO]    \- org.hamcrest:hamcrest-core:jar:1.1:test

Upvotes: 1

Stuart Watt
Stuart Watt

Reputation: 5401

Hmmm, my fault for carelessly letting Spring and Restlets resolve their differences. Explicitly bringing in all the Spring dependencies, rather than just the few I needed, made all the difference. A runtime scope for Spring had also crept in.

All I did was add the following top-level dependencies to the POM:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>

When I went back carefully, I could see the app was bringing in versions 3.1.4 and 3.2.6, and mixing them. The surprising thing was that everything seemed to work fine except for Jetty, and only when invoked on a WAR.

Long-range interactions between components are always the harder ones to debug, I guess...

Upvotes: 0

Related Questions