NoSuchMethodError с Hamcrest 1.3 и JUnit 4.11
Еще один пример NoSuchMethodError
для комбинации JUnit & Hamcrest. Оскорбительный код:
assertThat(dirReader.document(0).getFields(), hasItem(
new FeatureMatcher<IndexableField, String>(equalTo("Patisnummer"), "Field key", "Field key") {
@Override
protected String featureValueOf(IndexableField actual) {
return actual.name();
} } ));
Комментированные строки 152–157 в IndexerTest.java (commit ac72ce)
Вызывает NoSuchMethodError (полный вывод см. Http://db.tt/qkkkTE78):
java.lang.NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V
at org.hamcrest.FeatureMatcher.matchesSafely(FeatureMatcher.java:43)
at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55)
at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:25)
at org.hamcrest.core.IsCollectionContaining.matchesSafely(IsCollectionContaining.java:14)
at org.hamcrest.TypeSafeDiagnosingMatcher.matches(TypeSafeDiagnosingMatcher.java:55)
at org.junit.Assert.assertThat(Assert.java:770)
at org.junit.Assert.assertThat(Assert.java:736)
at indexer.IndexerTest.testIndexContainsField(IndexerTest.java:152)
Настройка:
- Юнит 4.11
- Hamcrest 1.3
- Используя плагин Maven's surefire (версия 2.14), который использует свой JUnitCoreProvider
- Java 7 (OpenJDK)
- Смотри Пом (commit ac72ce)
Фон:
NoSuchMethodError
вызывается (скомпилированными) классами, которые вызывают несуществующие методы. Конкретный случай describeMismatch
и комбинация JUnit + Hamcrest часто вызывается несовместимостью между классами Hamcrest, включенными в JUnit, и версиями этих классов в библиотеке Hamcrest.
Попытки решить ошибку NoSuchMethodError:
Пом содержит явную зависимость от Hamcrest-библиотеки 1.3, Hamcrest-core 1.3 и JUnit 4.11 (в таком порядке), как это было предложено Garrett Hall в ответ на получение "NoSuchMethodError: org.hamcrest.Matcher.describeMismatch" при запуске теста в IntelliJ 10,5
Согласно документации JUnit, зависимость JUnit 4.11 Maven больше не включает скомпилированные классы Hamcrest, вместо этого она имеет зависимость от Hamcrest-core 1.3; Итак
NoSuchMethodError
не должно происходить.Проверка дерева зависимостей с помощью
mvn dependency:tree
как предложено Dan в ответе на объявление junit и hamcrest, показывает явные зависимости от Hamcrest 1.3 и JUnit 4.11 и никаких других зависимостей от этих файлов (полный вывод см. на http://db.tt/C2OfTDJB).В другом тесте
NoSuchMethodError
удалось избежать с помощью:assertThat( "Zylab detector not available", d.getDetectors(), hasItem(Matchers.<Detector>instanceOf(ZylabMetadataXmlDetector.class)));
В строках 120–123 файла IndexerTest.java (commit ac72ce) вместо более очевидного:
assertThat( "Zylab detector not available", d.getDetectors(), hasItem(isA(ZylabMetadataDetector.class));
Я не уверен, является ли явный параметр типа
<Detector>
, с помощьюinstanceOf
вместоisA
Явная ссылка на ХамкрестаMatchers
или сочетание тех, кто избежалNoSuchMethodException
; после возни и пробуя разные вещи это сработало.Использование явных параметров типа не помогло решить проблему.
Используя класс, полученный из
BaseMatcher
вместоFeatureMatcher
не решить / избежать ошибки.
Идеи как починить NoSuchMethodError
?
8 ответов
Этот блог помог мне решить ту же проблему:
Внутри зависимостей для Mockito и Junit автор добавил исключение:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<exclusions>
<exclusion>
<artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId>
</exclusion>
</exclusions>
</dependency>
Возможно, один из тех других JAR имеет более старые версии Hamcrest's Matcher
или же BaseMatcher
, Вот список JAR-файлов, которые включают последний, хотя я не знаю, насколько всеобъемлющим этот сайт. Есть ли плагин Maven, который покажет вам все зависимости, которые включают класс, похожий на дерево зависимостей?
Используя подсказку David Harkness и Как мне разбить строку на разделителе в Bash? привел к следующему сценарию bash:
( IFS=":"; for i in `mvn dependency:build-classpath | grep -v '\[INFO\]'`; do jar tf $i | awk "{print \"$i\\t\" \$1}"; done | grep Matcher )
(онлайн на http://www.kaspervandenberg.net/2013/scripts/findDependencyClass.sh)
Который нашел эту зависимость JGlobus-Core-2.0.4
имеет свои версии org.hamcrest.BaseMatcher
, org.hamcrest.CoreMatchers
, а также org.hamcrest.Matcher
,
То, что работало для меня, было изменить порядок зависимостей. Вместо того, чтобы идти mockito, junit, я должен был поставить junit, mockito.
В Mockito 1.9.5 используется Hamcrest 1.1, который несовместим и вызывает проблемы.
Если вы используете Eclipse, инструмент "Открыть тип" (CTRL+SHIFT+T) может помочь вам найти проблемный пакет. Просто найдите имя класса (например, Description), множественные вхождения одного и того же класса из разных JAR-файлов - это красные флаги.
Для проекта с Gradle
в качестве инструмента сборки:
testCompile("junit:junit:4.11") {
exclude group: 'org.hamcrest', module: 'hamcrest-core'
exclude group: 'org.hamcrest', module: 'hamcrest-library'
}
testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3'
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
Если вы используете Eclipse: Для меня в eclipse-> свойства проекта->Java build Path перемещение mockito-all-1.9.5.jar в конец списка 'Order and Export' сделало свое дело. Чуть выше у меня есть junit-4.11.jar и выше этого hamcrest-core-1.3.jar
Я решил это jar hell
проблема в моем Gradle
проект с кодом ниже:
testCompile (group: 'junit', name: 'junit', version: '4+') {
exclude group: 'org.hamcrest'
}
testCompile ('org.mockito:mockito-core:1+') {
exclude group: 'org.hamcrest'
}
testCompile 'org.hamcrest:java-hamcrest:2.0.0.0'