Проблема:
У нас был интеграционный тест, который создает пружинный ClassPathXmlApplicationContext
и при этом тест NoSuchMethodError
с NoSuchMethodError
. Оказалось, что у нас были конфликтующие версии зависимостей от артефактов Spring. Само по себе это не является необычной проблемой — такие проблемы решаются с помощью подключаемого модуля зависимостей maven с использованием опции verbose. Тем не менее, что вы делаете, когда плагин Maven не так?
Изучение:
Мы начали копаться и обнаружили, что AbstractAutowireCapableBeanFactory
в его методе getTypeForFactoryMethod
пытается получить доступ к GenericTypeResolver
resolveReturnTypeForGeneric
и происходит сбой в java.lang.NoSuchMethodError: org.springframework.core.GenericTypeResolver.resolveReturnTypeForGenericMethod(Ljava/lang/reflect/Method;
,
Первоначальное исследование и поиск в Google показали, что метод был добавлен в 3.2.0, в то время как мы должны работать с 3.1.1. Дальнейшие исследования показали, что spring-data-mongodb
зависит от структуры пружины в диапазоне [3.0.7-4) 1 и потому, что maven использует последнюю доступную версию, учитывая, что диапазон 2 он пытался взять 3.2.2.
Обратите внимание, что вышеприведенное немного меняется, учитывая конфликт между явной зависимостью от версии и зависимостью от диапазона, но, IINM, при определении зависимостей Spring Mongo конфликта не возникает.
Проблема была также замаскирована двумя симптомами:
- У нас есть другие проекты, которые используют этот шаблон и у нас нет проблем. Это объясняется тем, что механизм разрешения конфликтов maven выбирает ближайшую версию, которую он находит по умолчанию 3, и поскольку все другие проекты, которым требуется spring-data-mongodb, зависят от В этом проекте им повезло захватить версию 3.1.1, а не 3.2.2
- Зависимость: дерево показывает, что оно приносит 3.1.1, в то время как приносит 3.2.2. Поскольку трассировка стека показала другие результаты, я написал тест, который проверяет, из какого jar происходит каждый из вышеперечисленных классов, и проверял, действительно ли класс AbstractAutowireCapableBeanFactory прибывает из Spring-Beans. 3.2.2, а не 3.1.1, как показала «mvn dependency: tree» (большое спасибо http://bit.ly/10zD1iV за фрагмент кода для поиска jar класса во время выполнения).
Зависимость Maven: вывод дерева, показывающий spring-bean: в артефакте используется 3.1.1.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
>:mvn dependency:tree -Dverbose -Dincludes=org.springframework ... (omitted for clarity) ... [INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ wix-feature-toggle-administration --- [INFO] artifact org.springframework:spring-beans: checking for updates from central [INFO] artifact org.springframework:spring-beans: checking for updates from snapshots [INFO] artifact org.springframework:spring-expression: checking for updates from central [INFO] artifact org.springframework:spring-expression: checking for updates from snapshots [INFO] artifact org.springframework:spring-tx: checking for updates from central [INFO] artifact org.springframework:spring-tx: checking for updates from snapshots [INFO] com.wixpress.common:wix-feature-toggle-administration:jar:2.180.0-SNAPSHOT ... [INFO] +- org.springframework.data:spring-data-mongodb:jar:1.0.1.RELEASE:compile [INFO] | +- org.springframework:spring-beans:jar:3.1.1.RELEASE:compile [INFO] | | \- (org.springframework:spring-core:jar:3.2.2.RELEASE:compile - omitted for conflict with 3.1.1.RELEASE) [INFO] | +- org.springframework:spring-expression:jar:3.1.1.RELEASE:compile [INFO] | | \- (org.springframework:spring-core:jar:3.2.2.RELEASE:compile - omitted for conflict with 3.1.1.RELEASE) [INFO] | \- org.springframework.data:spring-data-commons-core:jar:1.2.1.RELEASE:compile [INFO] | +- (org.springframework:spring-beans:jar:3.1.1.RELEASE:compile - omitted for duplicate) [INFO] | \- (org.springframework:spring-tx:jar:3.1.1.RELEASE:compile - omitted for duplicate) [INFO] +- com.wixpress.common:wix-framework:jar:2.180.0-SNAPSHOT:compile [INFO] | +- org.springframework:spring-core:jar:3.1.1.RELEASE:compile [INFO] | | \- org.springframework:spring-asm:jar:3.1.1.RELEASE:compile ... I've removed additional outputs for clarity. The additional outputs were all 3.1.1 and were further down the tree (so irrelevant due to maven conflict resolving mechanism) |
Тест, который доказывает наличие бинов: 3.2.2 используется в артефакте (утверждая, что говорил jvm в ошибке)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.wixpress.springVersionBug; import org.junit.*; import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; import org.springframework.core.GenericTypeResolver; import java.security.CodeSource; import static org.hamcrest.Matchers.endsWith; /** * @author ittaiz * @since 3/24/13 */ public class SpringVersionTest { @Test public void verifySpringBeans311InClasspath(){ verifyCorrectSpringVersionInClasspathFor(AbstractAutowireCapableBeanFactory. class , "spring-beans-3.1.1.RELEASE.jar" ); } @Test public void verifySpringCore311InClasspath(){ verifyCorrectSpringVersionInClasspathFor(GenericTypeResolver. class , "spring-core-3.1.1.RELEASE.jar" ); } public void verifyCorrectSpringVersionInClasspathFor(Class springClass,String expectedJarFileName){ CodeSource springClassCodeSource = springClass.getProtectionDomain().getCodeSource(); Assert.assertNotNull( "expecting " +expectedJarFileName+ " to be loaded by non-system class loader" ,springClassCodeSource); Assert.assertThat(springClassCodeSource.getLocation().toString(),endsWith(expectedJarFileName)); } } |
Аргумент spring-core
появился в 3.1.1, когда spring-beans
был 3.2.2, в том, что наша среда явно зависит от spring-core
и этот артефакт явно зависит от платформы. Это означает, что spring-core
3.1.1 из каркаса составляет 2 прыжка, что короче, чем 3.2.2 из spring-data-mongodb
.
Решение:
Зависит от spring-data-mongodb
, исключая spring-beans
например так:
01
02
03
04
05
06
07
08
09
10
11
|
< dependency > < groupId >org.springframework.data</ groupId > < artifactId >spring-data-mongodb</ artifactId > < version >1.0.1.RELEASE</ version > < exclusions > < exclusion > < groupId >org.springframework</ groupId > < artifactId >spring-beans</ artifactId > </ exclusion > </ exclusions > </ dependency > |
Открытый вопросительный знак:
Почему зависимость: дерево (в подробном режиме) не показывало, что оно приносит Spring-bean-компоненты в 3.2.2, но в 3.1.1, в то же время явно указав, что spring-core 3.2.2 был удален из-за конфликта? Я объясняю это ошибкой в плагине зависимостей.
- 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 ↩
- http://www.maestrodev.com/better-builds-with-maven/creating-applications-with-maven/resolving-dependency-conflicts-and-using-version-ranges/ ↩
- http://www.maestrodev.com/better-builds-with-maven/creating-applications-with-maven/resolving-dependency-conflicts-and-using-version-ranges/ ↩