We had an integration test which creates a spring ClassPathXmlApplicationContext and while doing so the test blew up with a NoSuchMethodError. It turned out that we had conflicting versions of dependencies on Spring artifacts. This in itself is not an unusual problem – such problems are addressed with the maven dependency plugin using the verbose option. However, what do you do when the maven plugin is wrong?
Investigation: We started to dig in and we found that the AbstractAutowireCapableBeanFactory in its getTypeForFactoryMethod method tries to access the GenericTypeResolver resolveReturnTypeForGeneric method and fails on a java.lang.NoSuchMethodError: org.springframework.core.GenericTypeResolver.resolveReturnTypeForGenericMethod(Ljava/lang/reflect/Method;.
Initial investigation and googling we found that the method was added in 3.2.0 while we’re supposed to be running with 3.1.1.
Further investigation determined that spring-data-mongodb depends on spring framework in range 1 and because maven takes the latest available version given that range 2 it tried to take 3.2.2.
Note that the above changes a bit given a conflict between an explicit version dependency and a range dependency but, IINM, when determining the dependencies of spring mongo there is no conflict.
The problem was further masked by two symptoms:
We have other projects that use this pattern and have no problem- This was explained by the fact that the conflict-resolving mechanism of maven chooses the nearest version it finds by default 3 and since all other projects which need spring-data-mongodb depend on this project they were lucky enough to grab the 3.1.1 version and not 3.2.2
dependency:tree shows it brings 3.1.1 while bringing 3.2.2- Since the stack trace showed other results I wrote a test which checks from which jar each of the above classes comes from and verified that indeed the AbstractAutowireCapableBeanFactory class arrives from spring-beans 3.2.2 and not 3.1.1 as “mvn dependency:tree” showed (a big thanks to http://bit.ly/10zD1iV for the code snippet of finding the jar of a class in runtime).
Maven dependency:tree output showing spring-beans:3.1.1 is used in the artifact
Depend on spring-data-mongodb while excluding spring-beans like so:
Update: Thanks to @Samuel_Langlois we confirmed that the “open question mark” is indeed a Maven Dependency Plugin bug which was resolved in 2.5 and so using 2.7 and forward will show you the correct info.
1. 0.7-4) [1. http://repo1.maven.org/maven2/org/springframework/data/spring-data-mongodb-parent/1.0.1.RELEASE/spring-data-mongodb-parent-1.0.1.RELEASE.pom ↩
2. http://www.maestrodev.com/better-builds-with-maven/creating-applications-with-maven/resolving-dependency-conflicts-and-using-version-ranges/ ↩
3. http://www.maestrodev.com/better-builds-with-maven/creating-applications-with-maven/resolving-dependency-conflicts-and-using-version-ranges/ ↩
This post was written by Ittai Zeidman
You can follow him on Twitter