Saya mengemas perpustakaan Java sebagai JAR, dan itu membuang banyak java.lang.IncompatibleClassChangeError
ketika saya mencoba untuk memanggil metode dari itu. Kesalahan ini tampaknya muncul secara acak. Jenis masalah apa yang dapat menyebabkan kesalahan ini?
218
Jawaban:
Ini berarti bahwa Anda telah membuat beberapa perubahan biner yang tidak kompatibel ke pustaka tanpa mengkompilasi ulang kode klien. Spesifikasi Bahasa Jawa §13 merinci semua perubahan seperti itu, yang paling jelas, mengubah
static
bidang / metode non-pribadi menjadistatic
atau sebaliknya.Kompilasi ulang kode klien terhadap pustaka baru, dan Anda harus melakukannya dengan baik.
UPDATE: Jika Anda menerbitkan perpustakaan umum, Anda harus menghindari membuat perubahan biner yang tidak kompatibel sebanyak mungkin untuk mempertahankan apa yang dikenal sebagai "kompatibilitas mundur biner". Memperbarui stoples ketergantungan saja idealnya tidak merusak aplikasi atau build. Jika Anda harus memutus kompatibilitas mundur biner, disarankan untuk menambah nomor versi utama (mis. Dari 1.xy ke 2.0.0) sebelum merilis perubahan.
sumber
*.class
file) dan mengkompilasi ulang? Mengedit file memiliki efek yang serupa.Pustaka Anda yang baru dikemas tidak kompatibel dengan backward binary (BC) dengan versi lama. Untuk alasan ini beberapa klien perpustakaan yang tidak dikompilasi ulang dapat melempar pengecualian.
Ini adalah daftar lengkap perubahan dalam Java library API yang dapat menyebabkan klien yang dibuat dengan versi lama dari perpustakaan untuk membuang java.lang. IncompatibleClassChangeError jika mereka berjalan pada yang baru (yaitu melanggar BC):
Catatan : Ada banyak pengecualian lain yang disebabkan oleh perubahan lain yang tidak kompatibel: NoSuchFieldError , NoSuchMethodError , IllegalAccessError , InstantiationError , VerifyError , NoClassDefFoundError dan AbstractMethodError .
Makalah yang lebih baik tentang BC adalah "Evolving API berbasis Java 2: Mencapai Kompatibilitas Biner API" yang ditulis oleh Jim des Rivières.
Ada juga beberapa alat otomatis untuk mendeteksi perubahan tersebut:
Penggunaan checker kepatuhan japi untuk perpustakaan Anda:
Penggunaan alat clirr:
Semoga berhasil!
sumber
Meskipun semua jawaban ini benar, menyelesaikan masalah seringkali lebih sulit. Ini umumnya merupakan hasil dari dua versi yang agak berbeda dari ketergantungan yang sama pada classpath, dan hampir selalu disebabkan oleh superclass yang berbeda daripada yang semula dikompilasi agar tidak berada di classpath atau beberapa impor dari transitive closure yang berbeda, tetapi umumnya di kelas pemanggilan instantiasi dan konstruktor. (Setelah pemuatan kelas berhasil dan pemanggilan aktor, Anda akan mendapatkan
NoSuchMethodException
atau yang lainnya.)Jika perilaku tampak acak, kemungkinan hasil dari program multithreaded classloading dependensi transitif yang berbeda berdasarkan kode apa yang terkena pertama.
Untuk mengatasinya, coba luncurkan VM dengan
-verbose
sebagai argumen, lalu lihat kelas yang sedang dimuat saat pengecualian terjadi. Anda harus melihat beberapa informasi yang mengejutkan. Misalnya, memiliki banyak salinan dengan ketergantungan dan versi yang sama yang tidak pernah Anda harapkan atau akan Anda terima jika Anda tahu mereka dimasukkan.Menyelesaikan guci duplikat dengan Maven paling baik dilakukan dengan kombinasi maven-dependency-plugin dan maven-penegakan-plugin di bawah Maven (atau SBT's Dependency Graph Plugin , kemudian menambahkan guci-guci itu ke bagian POM tingkat atas Anda atau sebagai ketergantungan impor) elemen dalam SBT (untuk menghapus dependensi itu).
Semoga berhasil!
sumber
Saya juga menemukan bahwa, ketika menggunakan JNI, memanggil metode Java dari C ++, jika Anda meneruskan parameter ke metode Java yang dipanggil dalam urutan yang salah, Anda akan mendapatkan kesalahan ini ketika Anda mencoba menggunakan parameter di dalam metode yang disebut (karena mereka tidak akan menjadi tipe yang tepat). Saya awalnya terkejut bahwa JNI tidak melakukan pemeriksaan ini untuk Anda sebagai bagian dari pemeriksaan tanda tangan kelas ketika Anda memanggil metode, tetapi saya berasumsi mereka tidak melakukan pemeriksaan semacam ini karena Anda mungkin melewati parameter polimorfik dan mereka harus menganggap Anda tahu apa yang Anda lakukan.
Contoh C ++ JNI Code:
Contoh Kode Java:
sumber
Saya memiliki masalah yang sama, dan kemudian saya menemukan bahwa saya menjalankan aplikasi pada Java versi 1.4 sementara aplikasi dikompilasi pada versi 6.Sebenarnya, alasannya adalah memiliki perpustakaan duplikat, satu terletak di dalam classpath dan yang lainnya dimasukkan ke dalam file jar yang terletak di dalam classpath.
sumber
Situasi lain di mana kesalahan ini dapat muncul adalah dengan Cakupan Kode Emma.
Ini terjadi ketika menetapkan Obyek ke antarmuka. Saya kira ini ada hubungannya dengan Objek yang diinstrumentasi dan tidak kompatibel biner lagi.
http://sourceforge.net/tracker/?func=detail&aid=3178921&group_id=177969&atid=883351
Untungnya masalah ini tidak terjadi pada Cobertura, jadi saya telah menambahkan cobertura-maven-plugin di plugin pelaporan pom.xml saya
sumber
Saya telah menghadapi masalah ini saat menganggur dan memindahkan perang dengan glassfish. Struktur kelas saya seperti ini,
dan diubah menjadi
Setelah berhenti dan memulai kembali domain, itu berhasil dengan baik. Saya menggunakan glassfish 3.1.43
sumber
Saya memiliki aplikasi web yang menyebarkan baik-baik saja pada kucing jantan mesin lokal saya (8.0.20). Namun, ketika saya memasukkannya ke dalam lingkungan qa (kucing jantan - 8.0.20), ia terus memberi saya IncompatibleClassChangeError dan itu mengeluh bahwa saya memperluas pada antarmuka. Antarmuka ini diubah menjadi kelas abstrak. Dan saya mengkompilasi kelas orang tua dan anak dan masih terus mendapatkan masalah yang sama. Akhirnya, saya ingin men-debug, jadi, saya mengubah versi pada induknya ke x.0.1-SNAPSHOT dan kemudian mengkompilasi semuanya dan sekarang sudah berfungsi. Jika seseorang masih mengalami masalah setelah mengikuti jawaban yang diberikan di sini, pastikan versi di pom.xml Anda juga benar. Ubah versi untuk melihat apakah itu berfungsi. Jika demikian, maka perbaiki masalah versi.
sumber
Jawaban saya, saya yakin, akan spesifik untuk Intellij.
Saya telah membangun kembali bersih, bahkan sejauh secara manual menghapus dir "keluar" dan "target". Intellij memiliki "cache tidak valid dan mulai ulang", yang terkadang menghapus kesalahan aneh. Kali ini tidak berhasil. Semua versi ketergantungan terlihat benar di menu pengaturan-> modul modul.
Jawaban terakhir adalah secara manual menghapus ketergantungan masalah saya dari repo pakar lokal saya. Versi lama bouncycastle adalah biang keladinya (saya tahu saya baru saja mengubah versi dan itu akan menjadi masalah) dan meskipun versi lama tidak menunjukkan di mana dalam apa yang sedang dibangun, itu menyelesaikan masalah saya. Saya menggunakan intellij versi 14 dan kemudian ditingkatkan menjadi 15 selama proses ini.
sumber
Dalam kasus saya, saya mengalami kesalahan ini dengan cara ini.
pom.xml
proyek saya mendefinisikan dua dependensiA
danB
. Dan keduanyaA
danB
ketergantungan yang ditentukan pada artefak yang sama (menyebutnyaC
) tetapi versi yang berbeda (C.1
danC.2
). Ketika ini terjadi, untuk setiap kelas diC
pakar hanya dapat memilih satu versi kelas dari dua versi (sambil membangun uber-jar ). Ini akan memilih versi "terdekat" berdasarkan aturan mediasi dependensi dan akan menampilkan peringatan "Kami memiliki kelas duplikat ..." Jika metode / tanda tangan kelas berubah di antara versi, itu dapat menyebabkanjava.lang.IncompatibleClassChangeError
pengecualian jika versi yang salah adalah digunakan saat runtime.Lanjutan: Jika
A
harus menggunakan v1 dariC
danB
harus menggunakan v2 dariC
, maka kita harus pindahC
diA
danB
's pom konflik kelas menghindari (kami memiliki peringatan kelas duplikat) ketika membangun proyek akhir yang tergantung pada keduaA
danB
.sumber
Dalam kasus saya kesalahan muncul ketika saya menambahkan
com.nimbusds
perpustakaan di aplikasi saya yang digunakanWebsphere 8.5
.Pengecualian di bawah ini terjadi:
Solusinya adalah dengan mengecualikan tabung asm dari perpustakaan:
sumber
Silakan periksa apakah kode Anda tidak terdiri dari dua proyek modul yang memiliki nama kelas dan definisi paket yang sama. Misalnya ini bisa terjadi jika seseorang menggunakan copy-paste untuk membuat implementasi antarmuka baru berdasarkan implementasi sebelumnya.
sumber
Jika ini merupakan catatan kemungkinan terjadinya kesalahan ini, maka:
Saya baru saja mendapatkan kesalahan ini pada WS (8.5.0.1), selama pemuatan CXF (2.6.0) dari pegas (3.1.1_release) konfigurasi di mana BeanInstantiationException menggulung CXF ExtensionException, menggulung IncompatibleClassChangeError. Cuplikan berikut ini menunjukkan inti dari jejak tumpukan:
Dalam hal ini, solusinya adalah mengubah urutan classpath dari modul dalam file perang saya. Yaitu, buka aplikasi perang di konsol WS di bawah dan pilih modul klien. Dalam konfigurasi modul, atur pemuatan kelas menjadi "induk terakhir".
Ini ditemukan di konsol WS:
sumber
Mendokumentasikan skenario lain setelah membakar terlalu banyak waktu.
Pastikan Anda tidak memiliki jar ketergantungan yang memiliki kelas dengan anotasi EJB di atasnya.
Kami memiliki file jar umum yang memiliki
@local
anotasi. Kelas itu kemudian dipindahkan dari proyek bersama itu ke proyek ejb jar utama kami. Guci ejb kami dan guci umum kami keduanya dibundel di dalam telinga. Versi ketergantungan botol umum kami tidak diperbarui. Jadi 2 kelas berusaha menjadi sesuatu dengan perubahan yang tidak kompatibel.sumber
Semua hal di atas - untuk alasan apa pun saya sedang melakukan refactor besar dan mulai mendapatkan ini. Saya mengganti nama paket dengan antarmuka saya dan itu membersihkannya. Semoga itu bisa membantu.
sumber
Untuk beberapa alasan pengecualian yang sama juga dilemparkan ketika menggunakan JNI dan melewati argumen jclass bukannya pada jobject saat memanggil a
Call*Method()
.Ini mirip dengan jawaban dari Ogre Psalm33.
Saya tahu ini agak terlambat untuk menjawab pertanyaan ini 5 tahun setelah ditanya tetapi ini adalah salah satu hit teratas ketika mencari
java.lang.IncompatibleClassChangeError
jadi saya ingin mendokumentasikan kasus khusus ini.sumber
Menambahkan 2 sen saya. Jika Anda menggunakan scala dan sbt dan scala-logging sebagai dependensi, maka ini dapat terjadi karena versi scala-logging sebelumnya memiliki nama scala-logging-api.So, pada dasarnya resolusi dependensi tidak terjadi karena perbedaan nama-nama yang mengarah ke kesalahan runtime saat meluncurkan aplikasi scala.
sumber
Penyebab tambahan masalah ini, adalah jika Anda telah
Instant Run
mengaktifkan untuk Android Studio.Cara mengatasinya
Jika Anda mulai mendapatkan kesalahan ini, matikan
Instant Run
.Mengapa
Instant Run
memodifikasi sejumlah besar hal selama pengembangan, untuk membuatnya lebih cepat untuk memberikan pembaruan ke Aplikasi Anda yang sedang berjalan. Karena itu jalankan instan. Ketika berhasil, itu sangat berguna. Namun, ketika masalah seperti ini menyerang, hal terbaik untuk dilakukan adalah mematikanInstant Run
versi Android Studio berikutnya.sumber