web-dev-qa-db-ja.com

Java.lang.IncompatibleClassChangeErrorの原因は何ですか?

私はJavaライブラリをJARとしてパッケージ化しています、そしてそれからメソッドを呼び出そうとするとたくさんのJava.lang.IncompatibleClassChangeErrorsを投げます。これらのエラーはランダムに現れるようです。どのような問題がこのエラーの原因と考えられますか?

203
Zombies

つまり、クライアントコードを再コンパイルせずに、ライブラリに互換性のないバイナリ変更を加えたということです。 Java言語仕様§13 は、そのようなすべての変更を詳しく説明していますが、最も目立つのは、non -static非privateフィールド/メソッドをstaticに、またはその逆に変更することです。

新しいライブラリに対してクライアントコードを再コンパイルすれば、うまくいくはずです。

更新:あなたが公共図書館を公開する場合、「バイナリ下位互換性」として知られているものを保存するために、互換性のないバイナリ変更をできるだけ行わないようにすべきです。依存関係jarだけを更新しても、理想的にはアプリケーションやビルドを中断するべきではありません。バイナリの下位互換性を破る必要がある場合は、メジャーバージョン番号を増やすことをお勧めします(例:1.xyから2.0.0)。変化する。

159
notnoop

あなたの新しくパッケージ化されたライブラリ旧バージョンとの互換性はありません(BC)。このため、再コンパイルされていないライブラリクライアントの中には、例外をスローするものがあります。

これは、JavaライブラリAPIの完全変更のリストで、古いバージョンのライブラリで構築されたクライアントがJava.langをスローする可能性があります。IncompatibleClassChangeError新しいライブラリを実行すると一つ(すなわちBCを壊す):

  1. 非最終フィールドは静的になります、
  2. 非定数フィールドは非静的になります。
  3. クラスはインターフェースになります、
  4. インターフェースはクラスになります、
  5. クラス/インタフェースに新しいフィールドを追加する(または新しいスーパークラス/スーパーインタフェースを追加する)と、クライアントクラスCのスーパーインタフェースからの静的フィールドは、フィールドから継承された(同じ名前の)追加フィールドを隠します。 Cのスーパークラス(非常にまれなケース)。

:他に互換性のない変更が原因で多くのその他の例外 NoSuchFieldError NoSuchMethodError IllegalAccessError InstantiationError / 、 VerifyError NoClassDefFoundError および AbstractMethodError

BCについてのより良い論文は "JavaベースのAPIの進化2:APIのバイナリ互換性の実現" Jim des Riviresによって書かれました。

そのような変更を検出するための自動ツールもあります。

あなたのライブラリのjapi-compliant-checkerの使い方:

japi-compliance-checker OLD.jar NEW.jar

Clirrツールの使い方

Java -jar clirr-core-0.6-uber.jar -o OLD.jar -n NEW.jar

がんばろう!

95
linuxbuild

これらの答えはすべて正解ですが、問題を解決することは多くの場合より困難です。これは一般的にクラスパスに対する同じ依存関係の2つのわずかに異なるバージョンの結果であり、クラスパスまたはにあることに対して元々コンパイルされたものとは異なるスーパークラスによって引き起こされます。推移的閉包は異なりますが、通常はクラスのインスタンス化とコンストラクタの呼び出し時です。 (クラスのロードとコントロールの呼び出しが成功すると、NoSuchMethodExceptionまたはwhatnotが返されます。)

動作がランダムに見える場合は、最初にヒットしたコードに基づいてマルチスレッドプログラムが異なる推移的な依存関係をクラスロードした結果である可能性があります。

これらを解決するには、-verboseを引数としてVMを起動し、例外が発生したときにロードされていたクラスを調べます。あなたはいくつかの驚くべき情報を見るべきです。たとえば、同じ依存関係とバージョンのコピーが複数あること、予期しなかったこと、またはそれらが含まれていることがわかっていれば受け入れたことなどです。

Mavenで重複したjarを解決するには、Mavenで maven-dependency-pluginmaven-enforcer-plugin を組み合わせて使用​​するのが最善です。 (またはSBTの 依存グラフプラグイン をクリックして、それらのjarファイルを最上位のPOMのセクションに追加するか、SBTのインポートされた依存要素として(これらの依存関係を削除します)。

がんばろう!

55
Brian Topping

JNIを使​​用しているときにC++からJavaメソッドを呼び出すときに、呼び出された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...
        }
    }
}
5
Ogre Psalm33

私は同じ問題を抱えていました、そして後で私はアプリケーションがバージョン6でコンパイルされている間、私はJavaバージョン1.4でアプリケーションを実行していることを知りました。

実際、その理由は、ライブラリが重複しているためです。1つはクラスパス内にあり、もう1つはクラスパス内にあるjarファイルの中に含まれています。

5
Eng.Fouad

私の場合、com.nimbusdsにデプロイされたアプリケーションにWebsphere 8.5ライブラリを追加したときにエラーが発生しました。
次の例外が発生しました:

原因:Java.lang.IncompatibleClassChangeError:org.objectweb.asm.AnnotationVisitor

解決策は、asm jarをライブラリから除外することでした。

<dependency>
    <groupId>com.nimbusds</groupId>
    <artifactId>nimbus-jose-jwt</artifactId>
    <version>5.1</version>
    <exclusions>
        <exclusion>
            <artifactId>asm</artifactId>
            <groupId>org.ow2.asm</groupId>
        </exclusion>
    </exclusions>
</dependency>
1
amine

私の答えは、Intellijに固有のものになると思います。

手動で "out"と "target"のディレクトリを削除することさえしても、私はクリーンに再構築しました。 Intellijには「キャッシュを無効にして再起動する」機能があり、奇妙なエラーを解消することがあります。今回はうまくいきませんでした。依存関係のバージョンはすべてプロジェクト設定 - >モジュールメニューで正しいように見えました。

最後の答えは私の地元のmavenリポジトリから手動で問題の依存関係を削除することでした。 bouncycastleの古いバージョンが原因でした(私はバージョンを変更したばかりなのでそれが問題になるだろうと思いました)。私はintellijバージョン14を使用していて、それからこのプロセスの間に15にアップグレードしました。

1
David Nickerson

このエラーが発生する可能性があるもう1つの状況は、Emma Code Coverageの場合です。

これは、オブジェクトをインタフェースに割り当てるときに起こります。これはインストゥルメントされているオブジェクトと関係があり、バイナリ互換ではなくなったと思います。

http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351

幸い、この問題はCoberturaでは起こらないので、私のpom.xmlのレポートプラグインにcobertura-maven-pluginを追加しました。

1
stivlo

Glassfishとの戦争をアンデプロイおよび再デプロイしているときに、この問題に直面しました。私のクラス構造はこんな感じでした、

public interface A{
}

public class AImpl implements A{
}

そしてそれはに変更されました

public abstract class A{
}

public class AImpl extends A{
}

ドメインを停止して再起動した後、正常に動作しました。私はグラスフィッシュを使っていました3.1.43

1
Nerrve

私は自分のローカルマシンのTomcat(8.0.20)に完璧にデプロイできるWebアプリケーションを持っています。しかし、私がそれをqa環境(Tomcat - 8.0.20)に入れたとき、それは私にIncompatibleClassChangeErrorを与え続け、それが私がインターフェース上で拡張していると不満でした。このインタフェースは抽象クラスに変更されました。そして、私は親クラスと子クラスをまとめました、それでも私は同じ問題を受け続けました。最後に、デバッグしたかったので、親のバージョンをx.0.1-SNAPSHOTに変更してからすべてをコンパイルしたところ、動作しています。ここに記載されている回答に従っても問題が解決しない場合は、pom.xmlのバージョンも正しいことを確認してください。それが機能するかどうかを確認するためにバージョンを変更します。もしそうなら、バージョンの問題を修正してください。

1
Jobin Thomas

私の場合は、このエラーに遭遇しました。私のプロジェクトのpom.xmlは、2つの依存関係ABを定義しました。そしてABの両方が同じ成果物への依存関係を定義しました(Cと呼びます)が、バージョンは異なります(C.1C.2)。これが起こると、C mavenの各クラスに対して、2つのバージョンからクラスの1つのバージョンしか選択できません( ber-jar の構築中)。それは、 依存関係の調停 規則に基づいて "最も近い"バージョンを選択し、警告を出力します "重複クラスがあります..." メソッド/クラスのシグネチャが変更された場合バージョン間で誤ったバージョンが実行時に使用されると、Java.lang.IncompatibleClassChangeError例外が発生する可能性があります。

詳細:Aにv1 [_ SOME_VARIABLE] _を、Cにv2のBを使用する必要がある場合は、 relocateC inを使用する必要があります。 CおよびABの両方に依存する最終的なプロジェクトをビルドするときには、クラスの競合を避けるためにABが使用されます。

1
morpheus

私の2セントを追加します。依存関係としてscalaとsbtおよびscala-loggingを使用している場合、scala-loggingの以前のバージョンの名前がscala-logging-api.Soであったために、これが発生する可能性があります。 scalaアプリケーションの起動中にランタイムエラーにつながる名前。

0
sourabh

何らかの理由で、JNIを使​​用してCall*Method()を呼び出すときにjobjectの代わりにjclass引数を渡すと、同じ例外がスローされます。

これは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を検索するときのトップヒットの1つなので、この特別な場合を文書化したいと思いました。

0

これがこのエラーの可能性のある記録であるならば:

このエラーは、WAS(8.5.0.1)で、Spring(3.1.1_release)構成のCXF(2.6.0)ロード中に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ファイル内のモジュールのクラスパスの順序を変更することでした。つまり、WASコンソールでwarアプリケーションを開き、クライアントモジュールを選択します。モジュール構成で、クラスローディングを "parent last"に設定します。

これはWASコンソールにあります。

  • アプリケーション - >アプリケーションタイプ - > WebSphere Enterprise Applications
  • あなたのアプリケーションを表すクリックリンク(戦争)
  • [モジュール]セクションの[モジュールの管理]をクリックします。
  • 基礎となるモジュールのリンクをクリックします
  • 「クラスローダーの順序」を「(最後の親)」に変更します。
0
wmorrison365

コードが同じクラス名とパッケージ定義を持つ2つのモジュールプロジェクトで構成されていないかどうかを確認してください。たとえば、以前の実装に基づいて、コピー&ペーストを使用してインタフェースの新しい実装を作成した場合などに発生する可能性があります。

0
denu

上記のすべて - なんらかの理由で私が大きなリファクタリングをしていてこれを取得し始めていました。私は自分のインターフェースが入っていたパッケージの名前を変更し、それによってそれをクリアしました。それが役立つことを願っています。

0
bsautner

この問題の追加の原因は、Android StudioでInstant Runが有効になっている場合です。

修正

このエラーが発生し始めたら、Instant Runをオフにしてください。

  1. Android Studioの主な設定
  2. 構築、実行、配置
  3. インスタントラン
  4. [インスタントランを有効にする]のチェックを外します。

なぜ

Instant Runは開発中に多くのことを変更して、実行中のアプリケーションの更新をより迅速に行えるようにします。それ故にインスタントラン。それが機能するとき、それは本当に役に立ちます。ただし、このような問題が発生した場合は、次のバージョンのAndroid StudioがリリースされるまでInstant Runをオフにすることをお勧めします。

0
Knossos

あまりにも多くの時間を燃やした後に別のシナリオを文書化する。

EJBアノテーションを付けたクラスを持つ依存関係jarがないことを確認してください。

@localアノテーションを持つ共通のjarファイルがありました。そのクラスは後にその共通プロジェクトから私たちのメインのejb jarプロジェクトに移されました。私たちのejb jarファイルと私たちの共通jarファイルはどちらも耳の中にまとめられています。共通のjar依存関係のバージョンは更新されませんでした。したがって、2つのクラスが互換性のない変更を加えようとしています。

0
Snekse