私はJavaライブラリをJARとしてパッケージ化しています、そしてそれからメソッドを呼び出そうとするとたくさんのJava.lang.IncompatibleClassChangeError
sを投げます。これらのエラーはランダムに現れるようです。どのような問題がこのエラーの原因と考えられますか?
つまり、クライアントコードを再コンパイルせずに、ライブラリに互換性のないバイナリ変更を加えたということです。 Java言語仕様§13 は、そのようなすべての変更を詳しく説明していますが、最も目立つのは、non -static
非privateフィールド/メソッドをstatic
に、またはその逆に変更することです。
新しいライブラリに対してクライアントコードを再コンパイルすれば、うまくいくはずです。
更新:あなたが公共図書館を公開する場合、「バイナリ下位互換性」として知られているものを保存するために、互換性のないバイナリ変更をできるだけ行わないようにすべきです。依存関係jarだけを更新しても、理想的にはアプリケーションやビルドを中断するべきではありません。バイナリの下位互換性を破る必要がある場合は、メジャーバージョン番号を増やすことをお勧めします(例:1.xyから2.0.0)。変化する。
あなたの新しくパッケージ化されたライブラリ旧バージョンとの互換性はありません(BC)。このため、再コンパイルされていないライブラリクライアントの中には、例外をスローするものがあります。
これは、JavaライブラリAPIの完全変更のリストで、古いバージョンのライブラリで構築されたクライアントがJava.langをスローする可能性があります。IncompatibleClassChangeError新しいライブラリを実行すると一つ(すなわちBCを壊す):
注:他に互換性のない変更が原因で多くのその他の例外: 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
がんばろう!
これらの答えはすべて正解ですが、問題を解決することは多くの場合より困難です。これは一般的にクラスパスに対する同じ依存関係の2つのわずかに異なるバージョンの結果であり、クラスパスまたはにあることに対して元々コンパイルされたものとは異なるスーパークラスによって引き起こされます。推移的閉包は異なりますが、通常はクラスのインスタンス化とコンストラクタの呼び出し時です。 (クラスのロードとコントロールの呼び出しが成功すると、NoSuchMethodException
またはwhatnotが返されます。)
動作がランダムに見える場合は、最初にヒットしたコードに基づいてマルチスレッドプログラムが異なる推移的な依存関係をクラスロードした結果である可能性があります。
これらを解決するには、-verbose
を引数としてVMを起動し、例外が発生したときにロードされていたクラスを調べます。あなたはいくつかの驚くべき情報を見るべきです。たとえば、同じ依存関係とバージョンのコピーが複数あること、予期しなかったこと、またはそれらが含まれていることがわかっていれば受け入れたことなどです。
Mavenで重複したjarを解決するには、Mavenで maven-dependency-plugin と maven-enforcer-plugin を組み合わせて使用するのが最善です。 (またはSBTの 依存グラフプラグイン をクリックして、それらのjarファイルを最上位のPOMのセクションに追加するか、SBTのインポートされた依存要素として(これらの依存関係を削除します)。
がんばろう!
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...
}
}
}
私は同じ問題を抱えていました、そして後で私はアプリケーションがバージョン6でコンパイルされている間、私はJavaバージョン1.4でアプリケーションを実行していることを知りました。
実際、その理由は、ライブラリが重複しているためです。1つはクラスパス内にあり、もう1つはクラスパス内にあるjarファイルの中に含まれています。
私の場合、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>
私の答えは、Intellijに固有のものになると思います。
手動で "out"と "target"のディレクトリを削除することさえしても、私はクリーンに再構築しました。 Intellijには「キャッシュを無効にして再起動する」機能があり、奇妙なエラーを解消することがあります。今回はうまくいきませんでした。依存関係のバージョンはすべてプロジェクト設定 - >モジュールメニューで正しいように見えました。
最後の答えは私の地元のmavenリポジトリから手動で問題の依存関係を削除することでした。 bouncycastleの古いバージョンが原因でした(私はバージョンを変更したばかりなのでそれが問題になるだろうと思いました)。私はintellijバージョン14を使用していて、それからこのプロセスの間に15にアップグレードしました。
このエラーが発生する可能性があるもう1つの状況は、Emma Code Coverageの場合です。
これは、オブジェクトをインタフェースに割り当てるときに起こります。これはインストゥルメントされているオブジェクトと関係があり、バイナリ互換ではなくなったと思います。
http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351
幸い、この問題はCoberturaでは起こらないので、私のpom.xmlのレポートプラグインにcobertura-maven-pluginを追加しました。
Glassfishとの戦争をアンデプロイおよび再デプロイしているときに、この問題に直面しました。私のクラス構造はこんな感じでした、
public interface A{
}
public class AImpl implements A{
}
そしてそれはに変更されました
public abstract class A{
}
public class AImpl extends A{
}
ドメインを停止して再起動した後、正常に動作しました。私はグラスフィッシュを使っていました3.1.43
私は自分のローカルマシンのTomcat(8.0.20)に完璧にデプロイできるWebアプリケーションを持っています。しかし、私がそれをqa環境(Tomcat - 8.0.20)に入れたとき、それは私にIncompatibleClassChangeErrorを与え続け、それが私がインターフェース上で拡張していると不満でした。このインタフェースは抽象クラスに変更されました。そして、私は親クラスと子クラスをまとめました、それでも私は同じ問題を受け続けました。最後に、デバッグしたかったので、親のバージョンをx.0.1-SNAPSHOTに変更してからすべてをコンパイルしたところ、動作しています。ここに記載されている回答に従っても問題が解決しない場合は、pom.xmlのバージョンも正しいことを確認してください。それが機能するかどうかを確認するためにバージョンを変更します。もしそうなら、バージョンの問題を修正してください。
私の場合は、このエラーに遭遇しました。私のプロジェクトのpom.xml
は、2つの依存関係A
とB
を定義しました。そしてA
とB
の両方が同じ成果物への依存関係を定義しました(C
と呼びます)が、バージョンは異なります(C.1
とC.2
)。これが起こると、C
mavenの各クラスに対して、2つのバージョンからクラスの1つのバージョンしか選択できません( ber-jar の構築中)。それは、 依存関係の調停 規則に基づいて "最も近い"バージョンを選択し、警告を出力します "重複クラスがあります..." メソッド/クラスのシグネチャが変更された場合バージョン間で誤ったバージョンが実行時に使用されると、Java.lang.IncompatibleClassChangeError
例外が発生する可能性があります。
詳細:A
にv1 [_ SOME_VARIABLE] _を、C
にv2のB
を使用する必要がある場合は、 relocateC
inを使用する必要があります。 C
およびA
とB
の両方に依存する最終的なプロジェクトをビルドするときには、クラスの競合を避けるためにA
とB
が使用されます。
私の2セントを追加します。依存関係としてscalaとsbtおよびscala-loggingを使用している場合、scala-loggingの以前のバージョンの名前がscala-logging-api.Soであったために、これが発生する可能性があります。 scalaアプリケーションの起動中にランタイムエラーにつながる名前。
何らかの理由で、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つなので、この特別な場合を文書化したいと思いました。
これがこのエラーの可能性のある記録であるならば:
このエラーは、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コンソールにあります。
コードが同じクラス名とパッケージ定義を持つ2つのモジュールプロジェクトで構成されていないかどうかを確認してください。たとえば、以前の実装に基づいて、コピー&ペーストを使用してインタフェースの新しい実装を作成した場合などに発生する可能性があります。
上記のすべて - なんらかの理由で私が大きなリファクタリングをしていてこれを取得し始めていました。私は自分のインターフェースが入っていたパッケージの名前を変更し、それによってそれをクリアしました。それが役立つことを願っています。
この問題の追加の原因は、Android StudioでInstant Run
が有効になっている場合です。
このエラーが発生し始めたら、Instant Run
をオフにしてください。
Instant Run
は開発中に多くのことを変更して、実行中のアプリケーションの更新をより迅速に行えるようにします。それ故にインスタントラン。それが機能するとき、それは本当に役に立ちます。ただし、このような問題が発生した場合は、次のバージョンのAndroid StudioがリリースされるまでInstant Run
をオフにすることをお勧めします。
あまりにも多くの時間を燃やした後に別のシナリオを文書化する。
EJBアノテーションを付けたクラスを持つ依存関係jarがないことを確認してください。
@local
アノテーションを持つ共通のjarファイルがありました。そのクラスは後にその共通プロジェクトから私たちのメインのejb jarプロジェクトに移されました。私たちのejb jarファイルと私たちの共通jarファイルはどちらも耳の中にまとめられています。共通のjar依存関係のバージョンは更新されませんでした。したがって、2つのクラスが互換性のない変更を加えようとしています。