Saya mendapatkan NoClassDefFoundError
ketika saya menjalankan aplikasi Java. Apa yang biasanya menyebabkan ini?
Sementara itu's mungkin bahwa ini adalah karena classpath ketidaksesuaian antara waktu compile dan run-time, it's tidak selalu benar.
Hal ini penting untuk menjaga dua atau tiga pengecualian lurus di kepala kita dalam hal ini:
jawa.lang.ClassNotFoundException
pengecualian Ini menunjukkan bahwa kelas tidak ditemukan di classpath. Hal ini menunjukkan bahwa kami mencoba untuk memuat definisi kelas, dan kelas tidak ada di classpath.
jawa.lang.NoClassDefFoundError
pengecualian Ini menunjukkan bahwa JVM tampak di internal kelas definisi struktur data untuk definisi kelas dan tidak menemukannya. Ini berbeda dari mengatakan bahwa hal itu tidak bisa diambil dari classpath. Biasanya hal ini menunjukkan bahwa kita sebelumnya berusaha untuk memuat sebuah kelas dari classpath, tetapi gagal untuk beberapa alasan - sekarang kita're mencoba untuk menggunakan kelas lagi (dan dengan demikian perlu untuk beban itu, karena ia gagal untuk terakhir kalinya), tetapi kita're bahkan tidak akan mencoba untuk memuatnya, karena kita gagal loading sebelumnya (dan patut menduga bahwa kita akan gagal lagi). Sebelumnya kegagalan bisa menjadi ClassNotFoundException atau ExceptionInInitializerError (menunjukkan kegagalan dalam statis inisialisasi block) atau masalah-masalah lainnya. Intinya adalah, sebuah NoClassDefFoundError tidak selalu classpath masalah.
Berikut ini adalah kode untuk menggambarkan jawa.lang.NoClassDefFoundError
. Silakan lihat Jared's jawaban untuk penjelasan rinci.
NoClassDefFoundErrorDemo.java
public class NoClassDefFoundErrorDemo {
public static void main(String[] args) {
try {
// The following line would throw ExceptionInInitializerError
SimpleCalculator calculator1 = new SimpleCalculator();
} catch (Throwable t) {
System.out.println(t);
}
// The following line would cause NoClassDefFoundError
SimpleCalculator calculator2 = new SimpleCalculator();
}
}
SimpleCalculator.java
public class SimpleCalculator {
static int undefined = 1 / 0;
}
NoClassDefFoundError Di Jawa
Definisi:
Java Virtual Machine tidak dapat menemukan kelas tertentu pada saat runtime yang tersedia pada waktu kompilasi.
Jika kelas sudah hadir selama waktu kompilasi tetapi tidak tersedia di jawa classpath selama runtime.
Contoh:
Kelas ini tidak dalam Classpath, tidak ada yang pasti ditembak cara untuk mengetahui hal ini tetapi banyak kali anda bisa coba lihat ke Sistem cetak.getproperty("java.classpath") dan itu akan mencetak classpath dari sana setidaknya anda bisa mendapatkan gambaran yang sebenarnya anda runtime classpath.
Contoh sederhana dari NoClassDefFoundError adalah kelas termasuk yang hilang file JAR atau JAR tidak ditambahkan ke dalam classpath atau kadang-kadang jar's nama telah diubah oleh seseorang seperti dalam kasus saya salah satu rekan saya telah berubah tibco.jar ke tibco_v3.jar dan program ini gagal dengan jawa.lang.NoClassDefFoundError dan aku bertanya-tanya apa yang's salah.
Hanya mencoba untuk berjalan dengan secara eksplisit -classpath pilihan dengan classpath anda berpikir akan bekerja dan jika itu's bekerja maka itu's yakin pendek tanda bahwa seseorang adalah override java classpath.
Masalah izin pada file JAR juga dapat menyebabkan NoClassDefFoundError di Jawa.
Typo pada Konfigurasi XML juga dapat menyebabkan NoClassDefFoundError di Jawa.
ketika anda menyusun kelas yang didefinisikan dalam satu paket, tidak hadir dalam paket yang sama saat loading seperti dalam kasus JApplet itu akan membuang NoClassDefFoundError di Jawa.
Solusi Yang Mungkin:
Sumber:
Saya telah menemukan bahwa kadang-kadang saya mendapatkan NoClassDefFound kesalahan saat kode dikompilasi dengan versi tidak kompatibel kelas ditemukan pada saat runtime. Contoh khusus yang saya ingat adalah dengan apache axis perpustakaan. Sebenarnya ada 2 versi yang saya runtime classpath dan mengambil keluar dari tanggal dan versi tidak kompatibel dan tidak benar, menyebabkan NoClassDefFound kesalahan. Ini adalah aplikasi baris perintah di mana saya menggunakan perintah yang sama untuk ini.
set classpath=%classpath%;axis.jar
Saya bisa mendapatkannya untuk mengambil versi yang tepat dengan menggunakan:
set classpath=axis.jar;%classpath%;
Ini adalah solusi saya temukan sejauh ini.
Misalkan kita memiliki sebuah paket yang disebut org.mypackage
yang berisi kelas-kelas:
dan file yang mendefinisikan paket ini disimpan secara fisik di dalam direktori D:\myprogram
(pada Windows) atau /home/user/myprogram
(di Linux).
Struktur file akan terlihat seperti ini:
Ketika kita memohon Jawa, kita tentukan nama aplikasi untuk menjalankan: org.mypackage.HelloWorld
. Namun kita juga harus memberitahu Jawa di mana untuk mencari file dan direktori mendefinisikan paket kami. Jadi untuk memulai program, kita harus menggunakan perintah berikut:
Saya menggunakan Spring Framework dengan Maven dan soal kesalahan ini dalam proyek saya.
Ada runtime error di kelas. Saya sedang membaca sebuah properti sebagai integer, tapi ketika membaca nilai dari properti file, nilainya dua kali lipat.
Musim semi tidak memberi saya penuh dengan tumpukan jejak yang garis runtime gagal.
Itu hanya kata NoClassDefFoundError
. Tapi ketika saya dieksekusi sebagai native aplikasi Java (mengambil itu dari MVC), itu memberi ExceptionInInitializerError
yang merupakan penyebab sebenarnya dan yang adalah bagaimana saya melacak kesalahan.
@xli's jawaban memberi saya wawasan tentang apa yang mungkin salah dalam kode saya.
Saya mendapatkan NoClassFoundError ketika kelas dimuat oleh runtime kelas loader tidak dapat mengakses kelas-kelas yang sudah dimuat oleh jawa rootloader. Karena berbeda kelas loader dalam berbagai domain keamanan (menurut jawa) jvm tidak't memungkinkan kelas-kelas yang sudah dimuat oleh rootloader untuk diselesaikan dalam runtime loader ruang alamat.
Jalankan program anda dengan 'jawa -javaagent:tracer.jar [java ANDA ARGS]'
Ini menghasilkan output yang menunjukkan dimuat kelas, dan loader env yang dimuat kelas. It's sangat membantu tracing mengapa sebuah kelas tidak dapat diselesaikan.
// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5
import java.lang.instrument.*;
import java.security.*;
// manifest.mf
// Premain-Class: ClassLoadTracer
// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class
// java -javaagent:tracer.jar [...]
public class ClassLoadTracer
{
public static void premain(String agentArgs, Instrumentation inst)
{
final java.io.PrintStream out = System.out;
inst.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);
// dump stack trace of the thread loading class
Thread.dumpStack();
// we just want the original .class bytes to be loaded!
// we are not instrumenting it...
return null;
}
});
}
}
Salah satu kasus yang menarik di mana anda mungkin melihat banyak NoClassDefFoundErrors
adalah ketika anda:
membuang
a RuntimeException
di statis
blok kelas Contoh
Contoh
static class Example {
static {
thisThrowsRuntimeException();
}
}
static class OuterClazz {
OuterClazz() {
try {
new Example();
} catch (Throwable ignored) { //simulating catching RuntimeException from static block
// DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
}
new Example(); //this throws NoClassDefFoundError
}
}
NoClassDefError
akan dilemparkan disertai dengan ExceptionInInitializerError
dari blok statis RuntimeException
.
Hal ini terutama penting ketika anda melihat NoClassDefFoundErrors
di UNIT TES.
Dalam cara anda're "berbagi" statis
memblokir eksekusi antara tes awal ExceptionInInitializerError
akan hanya dalam satu kasus uji. Yang pertama yang menggunakan bermasalah Contoh
class. Lain kasus uji yang menggunakan Contoh
class hanya akan membuang NoClassDefFoundErrors
.
Dalam kasus anda telah dihasilkan-kode (EMF, dll.) ada terlalu banyak statis initialisers yang mengkonsumsi semua ruang stack.
Melihat Stack Overflow pertanyaan https://stackoverflow.com/questions/3700459/how-to-increase-the-java-stack-size.
Teknik di bawah ini membantu saya berkali-kali:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
di mana TheNoDefFoundClass adalah kelas yang mungkin "hilang" karena preferensi untuk versi yang lebih tua dari perpustakaan yang sama yang digunakan oleh program anda. Ini paling sering terjadi dengan kasus-kasus, ketika klien perangkat lunak yang sedang digunakan menjadi dominan wadah, dipersenjatai dengan sendiri classloaders dan ton kuno versi paling populer libs.
NoClassDefFoundError
juga dapat terjadi ketika statis penginisialisasi mencoba untuk memuat sumber daya bundel yang tidak tersedia dalam runtime, misalnya properties file yang terkena kelas mencoba untuk memuat dari kode META-INF
direktori, tapi tidak ada. Jika anda tidak menangkap NoClassDefFoundError
, kadang-kadang anda tidak akan dapat untuk melihat full jejak stack; untuk mengatasi hal ini anda dapat menggunakan sementara yang menangkap
klausul Throwable
:
try {
// Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}
Aku punya kesalahan ini ketika saya menambahkan dependency Maven lain modul untuk project saya, masalah itu akhirnya diselesaikan dengan menambahkan -Xss2m
untuk program saya's JVM pilihan(Itu's satu megabyte secara default sejak JDK5.0). It's percaya program ini tidak memiliki cukup stack untuk memuat kelas.
Jika seseorang datang ke sini karena jawa.lang.NoClassDefFoundError: org/apache/log4j/Logger
kesalahan, dalam kasus saya itu dihasilkan karena saya menggunakan log4j 2 (tapi aku didn't menambahkan semua file yang datang dengan itu), dan beberapa ketergantungan perpustakaan menggunakan log4j 1. Solusi untuk menambahkan Log4j 1.x bridge: jar log4j-1.2-api-<versi>.jar
yang datang dengan log4j 2. Info lebih lanjut di log4j 2 migrasi.
Dalam kasus saya, masalahnya adalah Eclipse's ketidakmampuan untuk membedakan antara dua salinan yang berbeda dari proyek yang sama. Saya punya satu terkunci pada batang (SVN versi control) dan yang lain bekerja di salah satu cabang pada suatu waktu. Aku mencoba salah satu perubahan dalam kerja copy sebagai JUnit test case yang termasuk penggalian pribadi dalam kelas menjadi kelas publik sendiri dan saat itu bekerja, saya membuka salinan lain dari proyek ini untuk melihat-lihat di beberapa bagian lain dari kode itu dibutuhkan perubahan. Di beberapa titik, NoClassDefFoundError
muncul mengeluh bahwa pribadi dalam kelas itu tidak ada; double-klik pada stack trace membawa saya ke sumber file dalam proyek yang salah copy.
Penutupan batang copy dari proyek dan menjalankan tes lagi kasus menyingkirkan masalah.
Kesalahan ini dapat disebabkan oleh dicentang versi Java persyaratan.
Dalam kasus saya, saya mampu untuk mengatasi kesalahan ini, sementara bangunan yang tinggi-profil proyek open-source, dengan beralih dari Jawa 9 untuk Java 8 menggunakan SDKMAN!.
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
Kemudian melakukan instalasi yang bersih seperti yang dijelaskan di bawah ini.
Ketika menggunakan Maven seperti yang anda membangun alat, hal ini kadang-kadang membantu-dan biasanya memuaskan, untuk melakukan bersih 'install' membangun dengan pengujian cacat.
mvn clean install -DskipTests
Sekarang bahwa segala sesuatu ** telah dibangun dan diinstal, anda dapat pergi ke depan dan menjalankan tes.
mvn test
Aku punya NoClassDefFound kesalahan ketika saya didn't ekspor kelas pada "Urutan dan Ekspor" tab di Jawa Membangun Jalur proyek saya. Pastikan untuk menempatkan tanda centang di "Urutan dan Ekspor" tab dari setiap ketergantungan anda tambahkan ke proyek's membangun jalan. Lihat https://stackoverflow.com/questions/8884818/eclipse-warning-xxxxxxxxxxx-jar-will-not-be-exported-or-published-runtime-clas.
Bisa juga karena anda copy kode file dari sebuah IDE tertentu dengan nama paket dan anda ingin mencoba untuk menjalankan menggunakan terminal. Anda akan memiliki untuk menghapus nama paket dari kode yang pertama. Hal ini terjadi kepada saya.
Jawa tidak dapat menemukan kelas Yang pada saat runtime. Kelas Yang berada di maven project ArtClient dari tempat kerja yang berbeda. Jadi saya impor ArtClient saya proyek Eclipse. Dua proyek saya menggunakan ArtClient sebagai ketergantungan. Aku berubah referensi perpustakaan untuk referensi proyek untuk orang-orang ini (Membangun Jalan -> Configure Build Path).
Dan masalah pergi.