Thursday, March 7, 2013

How does IncompatibleClassChangeError happen (with sample code)


When different teams working separately producing libraries consumed by each other ,you may run into a problem with the java.lang.IncompatibleClassChangeError exception.

What does this exception mean?

IncompatibleClassChangeError means the class in the classloader is not the same format as the one compiled. (class vs interface)

How does this happened?

  • Your application "app" with dependency jar b in class path.
  • A is your code in app which has a reference with class B and compiled with b.
  • The class B in b-beta version was refactored to an interface
  • When you run your application, the code is running and load your dependency with b-beta.
  • Since the B as an interface not same as the one compiled as a class. Bang!~ The application throws the exception.

Sample code with Maven

I made an example to demonstrate how this happened. The code sample can be found here:

The five repos are: version1, version2, framework1, framework2, app

You can run maven clean install with the above sequences in your local box

Version 1 and Version2 have the same group id and artifact id, while the version is not the same (Here in order to simulate multiple version with different code locally, I created two repo for the same group and artifact). version1 has an interface Person, while version2 has a class Person.

Framework1 depends on version1 Person, while Framework2 depends on version2 Person.

The app depends on both framework1 and framework2. When maven loads the dependencies, it has to resolve the conflicts for version1 and version2, because they are having the same artifact and group. Maven uses "nearest win" policy to resolve the conflicts, then version1 wins.

When the app loads Framework2, it was looking for class Person, but the classloader contains an interface Person. The application failed like below.

mvn exec: java inside of app folder.

Caused by: java.lang.IncompatibleClassChangeError: Found interface org.freelance.incomp.core.Person, but class was expected
at org.freelance.version2.SayPerson.sayPerson(

No comments:

Post a Comment