17 ответов:
это означает, что вы внесли некоторые несовместимые двоичные изменения в библиотеку без перекомпиляции клиентского кода. Спецификация Языка Java §13 подробно все такие изменения, наиболее заметно, изменяя не -
staticне частные поля / методы должны бытьstaticили наоборот.перекомпиляции клиентского кода против новой библиотеки, и вы должны быть хорошо идти.
обновление: при публикации публичной библиотеки следует избегать создания несовместимых двоичных файлов изменения как можно больше, чтобы сохранить то, что известно как "двоичная обратная совместимость". Обновление только банок зависимостей в идеале не должно нарушать приложение или сборку. Если вам нужно сломать двоичную обратную совместимость, это рекомендовано для увеличения основного номера версии (например, от 1.x. y до 2.0.0) перед выпуском изменения.
ваша недавно упакованная библиотека отсутствует обратная двоичная совместимость (BC) со старой версией. По этой причине некоторые клиенты библиотеки, которые не перекомпилируются, могут вызвать исключение.
Это полное список изменений в API библиотеки Java, которые могут привести к тому, что клиенты, построенные со старой версией библиотеки, будут выбрасывать java.ленг.IncompatibleClassChangeError если они работают на новый (т. е. ломать До н. э.):
- неокончательное поле становится статичным,
- непостоянное поле становится нестатическим,
- класс становится интерфейсом,
- интерфейс стал класс
- если вы добавляете новое поле в класс / интерфейс (или добавляете новый супер-класс / супер-интерфейс), то статическое поле из супер-интерфейса клиентского класса C может скрывать добавленное поле (с тем же именем), унаследованное от супер-класса C (очень редко случай.)
Примечание: есть много другие исключения вызвано другими несовместимыми изменениями:NoSuchFieldError,NoSuchMethodError,IllegalAccessError,InstantiationError,VerifyError, NoClassDefFoundError и AbstractMethodError.
Лучшая статья о BC-это " развитие Java-API 2: достижение API Binary Compatibility" автор Джим де Ривьер.
есть также некоторые автоматические инструменты для обнаружения таких изменений:
использование japi-compliance-checker для вашего библиотека:
japi-compliance-checker OLD.jar NEW.jarиспользование инструмента clirr:
java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jarудачи!
хотя все эти ответы верны, решение проблемы часто бывает сложнее. Это, как правило, результат двух слегка разных версий одной и той же зависимости от пути к классам и почти всегда вызвано либо другим суперклассом, чем было первоначально скомпилировано против нахождения на пути к классам или некоторый импорт транзитивного закрытия отличается, но обычно при создании экземпляра класса и вызове конструктора. (После успешной загрузки класса и конструктор вызов, вы получите
NoSuchMethodExceptionили еще что-то.)Если поведение выглядит случайным, это, скорее всего, результат многопоточной программы classloading различных транзитивных зависимостей на основе того, какой код был поражен первым.
чтобы решить эти проблемы, попробуйте запустить виртуальную машину с помощью
-verboseв качестве аргумента, посмотрите на классы, которые были загружены, когда исключение происходит. Вы должны увидеть удивительную информацию. Например, наличие нескольких копий одной и той же зависимости и версии, которые вы никогда не ожидали или приняли бы, если бы знали, что они были включены.разрешение дубликатов банок с Maven лучше всего делать с комбинацией Maven-dependency-plugin и Maven-enforcer-plugin под Maven (или SBT Плагин Графика Зависимостей, затем добавьте эти банки в раздел вашего POM верхнего уровня или как импортированные элементы зависимостей в SBT (чтобы удалить эти зависимости).
хорошее удачи!
Я также обнаружил, что при использовании JNI, вызывая метод Java из C++, если вы передаете параметры вызываемому методу Java в неправильном порядке, вы получите эту ошибку при попытке использовать параметры внутри вызываемого метода (потому что они не будут правильным типом). Я был изначально озадачен тем, что JNI не делает эту проверку для вас как часть проверки подписи класса при вызове метода, но я предполагаю, что они не делают такой проверки, потому что вы можете быть передавая полиморфные параметры, они должны предполагать, что вы знаете, что делаете.
пример кода C++ JNI:
void invokeFooDoSomething() { jobject javaFred = FredFactory::getFred(); // Get a Fred jobject jobject javaFoo = FooFactory::getFoo(); // Get a Foo jobject jobject javaBar = FooFactory::getBar(); // Get a Bar jobject jmethodID methodID = getDoSomethingMethodId() // Get the JNI Method ID jniEnv->CallVoidMethod(javaFoo, methodID, javaFred, // Woops! I switched the Fred and Bar parameters! javaBar); // << Insert error handling code here to discover the JNI Exception >> // ... This is where the IncompatibleClassChangeError will show up. }Пример Кода Java:
class Bar { ... } class Fred { public int size() { ... } } class Foo { public void doSomething(Fred aFred, Bar anotherObject) { if (name.size() > 0) { // Will throw a cryptic java.lang.IncompatibleClassChangeError // Do some stuff... } } }
У меня была та же проблема, и позже я понял, что я запускаю приложение на Java версии 1.4, в то время как приложение компилируется на версии 6.на самом деле, причиной было наличие дубликата библиотеки, один из которых находится в пути к классам, а другой включен в файл jar, который находится в пути к классам.
другая ситуация, когда эта ошибка может появиться, - это покрытие кода Emma.
Это происходит при назначении объекта интерфейсу. Я думаю, это как-то связано с тем, что объект инструментируется и больше не совместим с двоичными файлами.
http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351
к счастью, эта проблема не происходит с Cobertura, поэтому я добавил cobertura-maven-плагин в моем отчеты Плагины моего пом.xml
я столкнулся с этой проблемой при развертывании и повторном развертывании войны с glassfish. Моя классовая структура была такой,
public interface A{ } public class AImpl implements A{ }и он был изменен на
public abstract class A{ } public class AImpl extends A{ }после остановки и перезапуска домена, он работал нормально. Я использовал glassfish 3.1.43
У меня есть веб-приложение, которое отлично развертывается на tomcat моей локальной машины(8.0.20). Однако, когда я поместил его в среду qa (tomcat - 8.0.20), он продолжал давать мне IncompatibleClassChangeError, и он жаловался, что я расширяюсь на интерфейсе. Этот интерфейс был изменен на абстрактный класс. И я скомпилировал родительские и дочерние классы, и все же я продолжал получать ту же проблему. Наконец, я хотел отладить, поэтому я изменил версию на родительском x.0.1-снимок, а затем скомпилировал все, и теперь он работает. Если кто-то все еще сталкивается с проблемой после выполнения ответов, приведенных здесь, пожалуйста, убедитесь, что версии в вашем pom.XML-это тоже правильно. Менять версии, чтобы увидеть, если это работает. Если да, то исправьте проблему с версией.
мой ответ, я полагаю, будет Intellij конкретным.
я перестроил чистый, даже дойдя до того, чтобы вручную удалить "out" и "target" dirs. Intellij имеет "недействительный кэш и перезапуск", который иногда очищает нечетные ошибки. На этот раз ничего не вышло. Все версии зависимостей выглядели правильно в меню настройки проекта- > модули.
окончательный ответ состоял в том, чтобы вручную удалить мою зависимость от проблемы из моего локального РЕПО maven. Старую версию после установки BouncyCastle был виновником (я знал, что только что изменил версии, и это будет проблемой), и хотя старая версия не обнаружила, где в том, что строилось, она решила мою проблему. Я использовал intellij версии 14, а затем обновился до 15 во время этого процесса.
в моем случае, я столкнулся с этой ошибкой сюда.
pom.xmlмоего проекта определены две зависимостиAиB. И обаAиBопределенная зависимость от одного и того же артефакта (назовите егоC) но разные его версии (C.1иC.2). Когда это происходит, для каждого класса вCmaven может выбрать только одну версию класса из двух версий (при создании uber-jar). Он выберет "ближайшую" версию на основе ее зависимость посредничество правила и выведет предупреждение "у нас есть дубликат класса..." если сигнатура метода/класса изменяется между версиями, это может вызватьjava.lang.IncompatibleClassChangeErrorисключение, если во время выполнения используется неверная версия.Дополнительно: Если
Aдолжен использовать v1 изCиBдолжен использовать v2 изC, то мы должны ПМЖCнаAиB' s poms, чтобы избежать конфликта классов (у нас есть повторяющееся предупреждение класса) при построении окончательный проект, который зависит от обоихAиB.
пожалуйста, проверьте, не состоит ли ваш код из двух проектов модулей, которые имеют одинаковые имена классов и определения пакетов. Например, это может произойти, если кто-то использует copy-paste для создания новой реализации интерфейса на основе предыдущей реализации.
Если это запись возможных случаев этой ошибки, то:
Я только что получил эту ошибку на WAS (8.5.0.1), во время загрузки CXF (2.6.0) конфигурации spring (3.1.1_release), где BeanInstantiationException свернул CXF ExtensionException, свернув IncompatibleClassChangeError. Следующий фрагмент кода показывает суть трассировки стека:
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.apache.cxf.bus.spring.SpringBus]: Constructor threw exception; nested exception is org.apache.cxf.bus.extension.ExtensionException at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:162) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:76) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:990) ... 116 more Caused by: org.apache.cxf.bus.extension.ExtensionException at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:167) at org.apache.cxf.bus.extension.Extension.getClassObject(Extension.java:179) at org.apache.cxf.bus.extension.ExtensionManagerImpl.activateAllByType(ExtensionManagerImpl.java:138) at org.apache.cxf.bus.extension.ExtensionManagerBus.<init>(ExtensionManagerBus.java:131) [etc...] at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147) ... 118 more Caused by: java.lang.IncompatibleClassChangeError: org.apache.neethi.AssertionBuilderFactory at java.lang.ClassLoader.defineClassImpl(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:284) [etc...] at com.ibm.ws.classloader.CompoundClassLoader.loadClass(CompoundClassLoader.java:586) at java.lang.ClassLoader.loadClass(ClassLoader.java:658) at org.apache.cxf.bus.extension.Extension.tryClass(Extension.java:163) ... 128 moreв этом случае решение состояло в том, чтобы изменить порядок пути к классам модуля в моем файле war. Что is, откройте приложение war в консоли WAS и выберите клиентский модуль(ы). В конфигурации модуля установите загрузку класса как "родительская последняя".
Это находится в консоли WAS:
- Applicatoins - > Типы Приложений - > WebSphere Enterprise Applications
- нажмите ссылку, представляющую ваше приложение (война)
- Нажмите кнопку "Управление модулями" в разделе "модули"
- нажмите на ссылку для базового модуль(ы)
- изменить " порядок загрузчика классов "на"(родительский последний)".
документирование другого сценария после сжигания слишком много времени.
убедитесь, что у вас нет jar зависимостей, который имеет класс с аннотацией EJB на нем.
У нас был общий файл jar, который имел
@localПримечание. Этот класс позже был перемещен из этого общего проекта в наш основной проект EJB jar. Наши объекты EJB jar и наш общий сосуд-оба в комплекте в ухо. Версия нашей общей зависимости jar не была обновлена. Таким образом 2 класса пытаются быть что-то с несовместимыми изменениями.
все вышеперечисленное-по какой-то причине я делал какой-то большой рефактор и начинал получать это. Я переименовал пакет, в котором был мой интерфейс, и это очистило его. Надеюсь, это поможет.
по какой-то причине такое же исключение также возникает при использовании JNI и передаче аргумента jclass вместо jobject при вызове
Call*Method().Это похоже на ответ из Ogre Psalm33.
void example(JNIEnv *env, jobject inJavaList) { jclass class_List = env->FindClass("java/util/List"); jmethodID method_size = env->GetMethodID(class_List, "size", "()I"); long size = env->CallIntMethod(class_List, method_size); // should be passing 'inJavaList' instead of 'class_List' std::cout << "LIST SIZE " << size << std::endl; }Я знаю, что немного поздно отвечать на этот вопрос через 5 лет после того, как его спросили, но это один из лучших хитов при поиске
java.lang.IncompatibleClassChangeErrorпоэтому я хотел задокументировать этот особый случай.
добавить мои 2 цента .Если вы используете scala и sbt и Scala-logging в качестве зависимости ;то это может произойти, потому что более ранняя версия scala-logging имела имя scala-logging-api.So; по существу, разрешения зависимостей не происходят из-за разных имен, приводящих к ошибкам времени выполнения при запуске приложения scala.
дополнительная причина этой проблемы, если у вас есть
Instant Runвключено для Android Studio.исправления
если вы обнаружите, что вы начинаете получать эту ошибку, выключите
Instant Run.
- основные настройки Android Studio
- Сборка, Выполнение, Развертывание
- Мгновенный Запуск
- снимите флажок " Включить мгновенный запуск..."
почему
Instant Runизменяет большое количество вещей во время разработки, чтобы сделайте это быстрее, чтобы предоставить обновления для вашего запущенного приложения. Отсюда мгновенный бег. Когда это работает, это действительно полезно. Однако, когда вопрос такого рода, как это кажется, лучшее, что можно сделать-отключитьInstant Runдо следующей версии релизов Android Studio.
Comments