ฉันได้รับNoClassDefFoundError
เมื่อฉันรันแอปพลิเคชัน Java ของฉัน อะไรคือสาเหตุของสิ่งนี้
ฉันได้รับNoClassDefFoundError
เมื่อฉันรันแอปพลิเคชัน Java ของฉัน อะไรคือสาเหตุของสิ่งนี้
คำตอบ:
สิ่งนี้เกิดขึ้นเมื่อมีไฟล์คลาสที่รหัสของคุณขึ้นอยู่กับมันและมีอยู่ในเวลารวบรวม แต่ไม่พบในขณะใช้งานจริง ค้นหาความแตกต่างในเวลาบิลด์และคลาสพา ธ ของรันไทม์ของคุณ
ในขณะที่เป็นไปได้ว่านี่เป็นเพราะ classpath ไม่ตรงกันระหว่างเวลาคอมไพล์และรันไทม์ แต่ก็ไม่จำเป็นต้องเป็นเรื่องจริง
เป็นสิ่งสำคัญที่จะต้องรักษาข้อยกเว้นที่แตกต่างกันสองหรือสามข้อไว้ในหัวของเราในกรณีนี้:
java.lang.ClassNotFoundException
ข้อยกเว้นนี้บ่งชี้ว่าไม่พบคลาสบนคลาสพา ธ สิ่งนี้บ่งชี้ว่าเราพยายามโหลดนิยามคลาสและคลาสไม่มีอยู่ใน classpath
java.lang.NoClassDefFoundError
ข้อยกเว้นนี้บ่งชี้ว่า JVM ค้นหาในโครงสร้างข้อมูลนิยามคลาสภายในเพื่อหานิยามของคลาสและไม่พบ สิ่งนี้ต่างจากการบอกว่าไม่สามารถโหลดได้จากคลาสพา ธ โดยปกติแล้วสิ่งนี้บ่งชี้ว่าก่อนหน้านี้เราพยายามโหลดคลาสจาก classpath แต่มันล้มเหลวด้วยเหตุผลบางอย่าง - ตอนนี้เรากำลังพยายามใช้คลาสอีกครั้ง (และต้องโหลดอีกครั้งเนื่องจากมันล้มเหลวในครั้งที่แล้ว) แต่เรา ' ไม่แม้แต่จะพยายามโหลดเพราะเราล้มเหลวในการโหลดก่อนหน้า (และสงสัยว่าเราจะล้มเหลวอีกครั้ง) ความล้มเหลวก่อนหน้านี้อาจเป็น ClassNotFoundException หรือ ExceptionInInialializerError (ระบุความล้มเหลวในบล็อกการเริ่มต้นคงที่) หรือปัญหาอื่น ๆ ประเด็นคือ NoClassDefFoundError ไม่จำเป็นต้องเป็นปัญหา classpath
Error: Could not find or load main class
มันจะถูกจัดประเภทตามประเภทของข้อผิดพลาด?
java.lang.NoClassDefFoundError
นี่คือรหัสที่จะแสดงให้เห็นถึง โปรดดูคำตอบของ Jaredสำหรับคำอธิบายโดยละเอียด
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;
}
SimpleCalculator
หลังจากหารด้วยศูนย์? มีใครบางคนมีการอ้างอิงถึงเอกสารอย่างเป็นทางการสำหรับพฤติกรรมนี้หรือไม่?
new SimpleCalculator()
มีการเรียกคุณจะได้รับ ExceptionInInialializerError โดยมีสาเหตุมาจาก ArithmeticException ครั้งที่สองที่คุณโทรหาnew SimpleCalculator()
คุณจะได้รับ NoClassDefFoundError ล้วนๆ ประเด็นก็คือคุณจะได้รับ NoClassDefFoundError ด้วยเหตุผลอื่นนอกเหนือจาก SimpleCalculator.class ที่ไม่ได้อยู่ใน classpath ตอนรันไทม์
NoClassDefFoundError ใน Java
ความหมาย:
Java Virtual Machine ไม่สามารถค้นหาคลาสเฉพาะที่รันไทม์ซึ่งมีอยู่ในเวลารวบรวม
หากคลาสมีอยู่ในระหว่างการคอมไพล์ แต่ไม่สามารถใช้ได้ใน java classpath ระหว่างรันไทม์
ตัวอย่าง:
ตัวอย่างง่ายๆของ NoClassDefFoundError คือคลาสเป็นของไฟล์ JAR ที่หายไปหรือ JAR ไม่ได้ถูกเพิ่มเข้าไปใน classpath หรือบางครั้งชื่อของ jar ถูกเปลี่ยนโดยคนที่ชอบในกรณีของฉันหนึ่งในเพื่อนร่วมงานของฉันเปลี่ยน tibco.jar เป็น tibco_v3.jar ล้มเหลวด้วย java.lang.NoClassDefFoundError และฉันสงสัยว่ามีอะไรผิดปกติ
เพียงแค่พยายามเรียกใช้ตัวเลือก -classpath อย่างชัดเจนกับ classpath ที่คุณคิดว่าจะใช้งานได้และหากใช้งานได้จะเป็นสัญญาณสั้น ๆ ว่ามีบางคนกำลังเอาชนะ java classpath
การแก้ปัญหาที่เป็นไปได้:
แหล่งข้อมูล:
ฉันพบว่าบางครั้งฉันได้รับข้อผิดพลาด NoClassDefFound เมื่อโค้ดถูกคอมไพล์ด้วยคลาสที่เข้ากันไม่ได้ของคลาสที่พบในรันไทม์ อินสแตนซ์เฉพาะที่ฉันจำได้คืออยู่ในไลบรารีแกน apache จริงๆแล้วมี 2 เวอร์ชันใน runtime classpath ของฉันและมันก็ล้าสมัยและเข้ากันไม่ได้และไม่ใช่รุ่นที่ถูกต้องทำให้เกิดข้อผิดพลาด NoClassDefFound นี่คือแอปบรรทัดคำสั่งที่ฉันใช้คำสั่งคล้ายกับสิ่งนี้
set classpath=%classpath%;axis.jar
ฉันสามารถรับเวอร์ชันที่เหมาะสมโดยใช้:
set classpath=axis.jar;%classpath%;
นี่เป็นทางออกที่ดีที่สุดที่ฉันพบ
สมมติว่าเรามีแพ็คเกจorg.mypackage
ที่มีคลาส:
และไฟล์ที่กำหนดแพ็คเกจนี้จะถูกจัดเก็บทางกายภาพภายใต้ไดเรกทอรีD:\myprogram
(บน Windows) หรือ/home/user/myprogram
(บน Linux)
โครงสร้างไฟล์จะมีลักษณะดังนี้:
เมื่อเราเรียกใช้ Java org.mypackage.HelloWorld
เราระบุชื่อของแอพลิเคชันในการทำงาน: อย่างไรก็ตามเราต้องบอก Java ว่าจะค้นหาไฟล์และไดเรคทอรีที่กำหนดแพ็คเกจของเราได้อย่างไร ดังนั้นเพื่อเปิดโปรแกรมเราต้องใช้คำสั่งต่อไปนี้:
ฉันใช้Spring FrameworkกับMavenและแก้ไขข้อผิดพลาดนี้ในโครงการของฉัน
มีข้อผิดพลาดรันไทม์ในชั้นเรียน ฉันอ่านคุณสมบัติเป็นจำนวนเต็ม แต่เมื่ออ่านค่าจากไฟล์คุณสมบัติค่าของมันจะเป็นสองเท่า
ฤดูใบไม้ผลิไม่ได้ให้ฉันเต็มสแต็คร่องรอยของบนบรรทัดที่รันไทม์ล้มเหลว NoClassDefFoundError
มันก็กล่าวว่า แต่เมื่อฉันเรียกใช้มันเป็นแอปพลิเคชัน Java ดั้งเดิม (นำออกจาก MVC) มันให้ExceptionInInitializerError
ซึ่งเป็นสาเหตุที่แท้จริงและสิ่งที่ฉันติดตามข้อผิดพลาด
คำตอบของ @xli ทำให้ฉันเข้าใจถึงสิ่งที่อาจผิดในรหัสของฉัน
NoClassDefFoundError
จริงแล้วเกิดจากExceptionInInitalizerError
ซึ่งเกิดจากDateTimeParseException
) มันทำให้เข้าใจผิดเล็กน้อยใช่มั้ย ฉันรู้ว่าพวกเขาอาจมีเหตุผลของพวกเขาที่จะทำให้มันเป็นอย่างนั้น แต่มันก็ดีที่มีอย่างน้อยคำใบ้เล็ก ๆ น้อย ๆ นั่นNoClassDefFoundError
เป็นผลมาจากข้อยกเว้นอื่นโดยไม่จำเป็นต้องอนุมานมัน การขว้างปาExceptionInInitializerError
อีกครั้งจะมีความชัดเจนมากขึ้น บางครั้งการเชื่อมต่อระหว่างสองอาจไม่ชัดเจน
ฉันได้รับ NoClassFoundError เมื่อโหลดคลาสโดย runtime class loader ไม่สามารถเข้าถึงคลาสที่โหลดโดย java rootloader แล้ว เนื่องจากตัวโหลดคลาสที่แตกต่างกันอยู่ในโดเมนความปลอดภัยที่แตกต่างกัน (ตามจาวา) jvm จะไม่อนุญาตให้คลาสที่โหลดโดย rootloader ได้รับการแก้ไขในพื้นที่ที่อยู่ของโหลดเดอร์รันไทม์
รันโปรแกรมด้วย 'java -javaagent: tracer.jar [YOUR java ARGS]'
สร้างเอาต์พุตที่แสดงคลาสที่โหลดและตัวโหลด env ที่โหลดคลาส มันมีประโยชน์มากในการติดตามว่าทำไมคลาสไม่สามารถแก้ไขได้
// 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;
}
});
}
}
กรณีที่น่าสนใจอย่างหนึ่งที่คุณอาจเห็นเป็นจำนวนมากNoClassDefFoundErrors
คือเมื่อคุณ:
throw
RuntimeException
ในstatic
บล็อกของชั้นเรียนของคุณExample
Example
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
จะถูกโยนพร้อมกับจากบล็อกแบบคงที่ExceptionInInitializerError
RuntimeException
ในกรณีนี้คือสิ่งสำคัญโดยเฉพาะอย่างยิ่งเมื่อคุณเห็นNoClassDefFoundErrors
ของคุณในการทดสอบหน่วย
ในแบบที่คุณ "แบ่งปัน" การstatic
ดำเนินการบล็อกระหว่างการทดสอบ แต่เริ่มต้นExceptionInInitializerError
จะเป็นเพียงในกรณีทดสอบหนึ่ง อันแรกที่ใช้Example
คลาสที่มีปัญหา กรณีทดสอบอื่น ๆ ที่ใช้ในชั้นเรียนก็จะโยนExample
NoClassDefFoundErrors
เทคนิคด้านล่างช่วยฉันได้หลายครั้ง:
System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());
โดย TheNoDefFoundClass เป็นคลาสที่อาจ "หลงทาง" เนื่องจากการกำหนดค่าตามความชอบสำหรับไลบรารี่รุ่นเก่าที่ใช้โดยโปรแกรมของคุณ สิ่งนี้เกิดขึ้นได้บ่อยที่สุดเมื่อมีการปรับใช้ซอฟต์แวร์ไคลเอนต์ลงในคอนเทนเนอร์ที่โดดเด่นติดอาวุธด้วย classloaders ของตัวเองและ libs ยอดนิยมรุ่นโบราณจำนวนมาก
ในกรณีที่คุณสร้างรหัส (EMF ฯลฯ ) อาจมีตัวกำหนดค่าเริ่มต้นคงที่มากเกินไปซึ่งใช้พื้นที่สแต็กทั้งหมด
ดูคำถาม Stack Overflow วิธีเพิ่มขนาดสแต็ก Java? .
ฉันแก้ไขปัญหาด้วยการปิดใช้งาน preDexL ไลบรารีสำหรับโมดูลทั้งหมด:
dexOptions {
preDexLibraries false
...
NoClassDefFoundError
ยังสามารถเกิดขึ้นได้เมื่อstatic initializer พยายามโหลดบันเดิลรีซอร์สที่ไม่พร้อมใช้งานในรันไทม์ตัวอย่างเช่นไฟล์คุณสมบัติที่คลาสที่ได้รับผลกระทบพยายามโหลดจากMETA-INF
ไดเร็กทอรี แต่ไม่มี หากคุณไม่ทันNoClassDefFoundError
บางครั้งคุณจะไม่สามารถเห็นร่องรอยสแต็กเต็ม เพื่อเอาชนะสิ่งนี้คุณสามารถใช้catch
ประโยคสำหรับ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);
}
for example a properties file that the affected class tries to load from the META-INF directory
แต่ที่ผมเขียน สิ่งนี้เกิดขึ้นกับฉันและฉันก็สามารถแก้ไขได้NoClassDefFoundError
โดยการเพิ่มไฟล์คุณสมบัติที่หายไป ฉันเพิ่มคำตอบนี้อย่างแน่นอนเพราะไม่มีใครคาดหวังข้อผิดพลาดนี้ภายใต้สถานการณ์ที่กล่าวถึง
static
เริ่มต้น ... ซึ่งทำให้เกิดข้อยกเว้นที่ไม่ได้ตรวจสอบ ที่จะล้มเหลว. ข้อยกเว้นที่ไม่ได้ตรวจสอบใด ๆ ที่เผยแพร่จากการเริ่มต้นคงที่จะทำเช่นนั้น
static
เริ่มต้นล้มเหลว) ฉันจะสนใจที่จะเห็นตัวอย่างจริง (เช่น MCVE) ที่แสดงให้เห็นถึงพฤติกรรม
ฉันได้รับข้อผิดพลาดนี้เมื่อฉันเพิ่มการพึ่งพา Maven ของโมดูลอื่นในโครงการของฉันในที่สุดปัญหาก็ถูกแก้ไขโดยการเพิ่ม-Xss2m
ตัวเลือก JVM ของโปรแกรมของฉัน (เป็นค่าเริ่มต้นหนึ่งเมกะไบต์ตั้งแต่ JDK5.0) เชื่อว่าโปรแกรมมีสแต็กไม่เพียงพอในการโหลดคลาส
หากมีคนมาที่นี่เพราะเกิดjava.lang.NoClassDefFoundError: org/apache/log4j/Logger
ข้อผิดพลาดในกรณีของฉันมันถูกสร้างขึ้นเพราะฉันใช้ log4j 2 (แต่ฉันไม่ได้เพิ่มไฟล์ทั้งหมดที่มาพร้อมกับมัน) และบางไลบรารีที่พึ่งพาใช้ log4j 1. วิธีแก้ปัญหาคือการเพิ่ม Log4j สะพาน 1.x: ขวดlog4j-1.2-api-<version>.jar
ที่มาพร้อมกับข้อมูล log4j 2. เพิ่มเติมใน log4j 2 การโยกย้าย
ในกรณีของฉันปัญหาคือ Eclipse ไม่สามารถแยกความแตกต่างระหว่างสองสำเนาที่แตกต่างกันของโครงการเดียวกัน ฉันมีหนึ่งถูกล็อกบน trunk (การควบคุมเวอร์ชัน SVN) และอีกอันหนึ่งทำงานในสาขาเดียวในแต่ละครั้ง ฉันลองทำการเปลี่ยนแปลงในสำเนาการทำงานเป็นกรณีทดสอบ JUnit ซึ่งรวมถึงการแยกคลาสส่วนตัวภายในให้เป็นคลาสสาธารณะด้วยตนเองและในขณะที่ทำงานอยู่ฉันเปิดสำเนาอีกชุดของโครงการเพื่อดูรอบ ๆ ส่วนหนึ่งของรหัสที่ต้องการการเปลี่ยนแปลง เมื่อถึงจุดหนึ่งก็NoClassDefFoundError
โผล่ขึ้นมาบ่นว่าชั้นในส่วนตัวไม่อยู่ที่นั่น; การดับเบิลคลิกในการติดตามสแต็กนำฉันไปยังไฟล์ต้นฉบับในสำเนาโครงการที่ไม่ถูกต้อง
การปิดสำเนาของโปรเจ็กต์และเรียกใช้กรณีทดสอบอีกครั้งทำให้ปัญหาหมดไป
ข้อผิดพลาดนี้อาจเกิดจากข้อกำหนดรุ่น Java ที่ไม่ได้ตรวจสอบ
ในกรณีของฉันฉันสามารถแก้ไขข้อผิดพลาดนี้ในขณะที่สร้างโครงการโอเพนซอร์สสูงโปรไฟล์โดยเปลี่ยนจาก Java 9 เป็น Java 8 โดยใช้SDKMAN! .
sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu
จากนั้นทำการติดตั้งใหม่ทั้งหมดตามที่อธิบายไว้ด้านล่าง
เมื่อใช้Mavenเป็นสร้างเครื่องมือของคุณจะเป็นประโยชน์บางครั้ง - และมักจะพอใจที่จะทำสะอาด 'ติดตั้ง' สร้างกับการทดสอบพิการ
mvn clean install -DskipTests
เมื่อทุกอย่างถูกสร้างและติดตั้งแล้วคุณสามารถดำเนินการทดสอบได้
mvn test
ฉันได้รับข้อผิดพลาด NoClassDefFound เมื่อฉันไม่ได้ส่งออกคลาสบนแท็บ "สั่งซื้อและส่งออก" ใน Java Build Path ของโครงการของฉัน ตรวจสอบให้แน่ใจว่าได้ใส่เครื่องหมายถูกในแท็บ "สั่งซื้อและส่งออก" ของการอ้างอิงใด ๆ ที่คุณเพิ่มไปยังเส้นทางการสร้างของโครงการ ดูคำเตือน Eclipse: XXXXXXXXXXX.jar จะไม่ถูกส่งออกหรือเผยแพร่ Runtime ClassNotFoundExceptions อาจส่งผลให้
อาจเป็นเพราะคุณคัดลอกไฟล์รหัสจาก IDE ด้วยชื่อแพ็กเกจที่แน่นอนและคุณต้องการลองรันโดยใช้เทอร์มินัล คุณจะต้องลบชื่อแพ็คเกจออกจากรหัสก่อน สิ่งนี้เกิดขึ้นกับฉัน
ในกรณีของฉันฉันได้รับข้อผิดพลาดนี้เนื่องจากไม่ตรงกันในรุ่น JDK เมื่อฉันพยายามเรียกใช้แอพพลิเคชั่นจาก Intelij มันไม่ทำงาน แต่ก็เปิดใช้งานจากบรรทัดคำสั่งได้ผล นี่เป็นเพราะ Intelij พยายามที่จะรันด้วย Java 11 JDK ที่ติดตั้ง แต่ในบรรทัดคำสั่งมันกำลังทำงานกับ Java 8 JDK หลังจากสลับการตั้งค่านั้นในไฟล์> โครงสร้างโครงการ> การตั้งค่าโครงการ> SDK โครงการมันใช้งานได้สำหรับฉัน
ทุกคนพูดถึงที่นี่เกี่ยวกับบางสิ่งที่เกี่ยวกับการกำหนดค่า Java ปัญหา JVM ฯลฯ ในกรณีของฉันข้อผิดพลาดไม่เกี่ยวข้องกับหัวข้อเหล่านี้เลยและมีเหตุผลเล็กน้อยและง่ายต่อการแก้ปัญหา: ฉันมีคำอธิบายประกอบผิดที่จุดปลายทางของฉันในคอนโทรลเลอร์ แอปพลิเคชั่น Spring Boot)
ฉันมีปัญหาที่น่าสนใจกับ NoClassDefFoundError ใน JavaEE ที่ทำงานกับเซิร์ฟเวอร์ Liberty ฉันใช้อะแดปเตอร์ทรัพยากร IMS และ server.xml ของฉันมีอะแดปเตอร์ทรัพยากรสำหรับ imsudbJXA.rar แล้ว เมื่อฉันเพิ่มอะแดปเตอร์ใหม่สำหรับ imsudbXA.rar ฉันจะเริ่มรับข้อผิดพลาดนี้สำหรับวัตถุอินสแตนซ์สำหรับ DLIException, IMSConnectionSpec หรือ SQLInteractionSpec ฉันไม่สามารถหาสาเหตุได้ แต่ฉันแก้ไขด้วยการสร้าง server.xml ใหม่สำหรับงานของฉันโดยใช้เพียง imsudbXA.rar ฉันแน่ใจว่าใช้อะแดปเตอร์ทรัพยากรหลายตัวใน server.xml ไม่เป็นไรฉันไม่มีเวลาดู
Java ไม่พบคลาส A ในรันไทม์ Class A อยู่ในโครงการ Maven ArtClient จากพื้นที่ทำงานอื่น ดังนั้นฉันจึงนำเข้า ArtClient ไปยังโครงการ Eclipse ของฉัน สองโครงการของฉันใช้ ArtClient เป็นการพึ่งพา ฉันเปลี่ยนการอ้างอิงไลบรารีเป็นการอ้างอิงโครงการสำหรับสิ่งเหล่านี้ (Build Path -> Configure Build Path)
และปัญหาก็หมดไป
ฉันมีปัญหาเดียวกันและฉันเป็นสต็อกเป็นเวลาหลายชั่วโมง
ฉันพบวิธีแก้ปัญหา ในกรณีของฉันมีวิธีการคงที่ที่กำหนดเนื่องจากการที่ JVM ไม่สามารถสร้างวัตถุอื่นของคลาสนั้น
ตัวอย่างเช่น,
private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");
ฉันได้รับข้อความนี้หลังจากลบไฟล์สองไฟล์ออกจากไลบรารี SRC และเมื่อฉันนำไฟล์เหล่านั้นกลับมาฉันก็ยังเห็นข้อความแสดงข้อผิดพลาดนี้อยู่
วิธีแก้ปัญหาของฉันคือ: รีสตาร์ท Eclipse ตั้งแต่นั้นมาฉันไม่เห็นข้อความนี้อีก :-)
ตรวจสอบให้แน่ใจว่าการจับคู่นี้ในmodule:app
และmodule:lib
:
android {
compileSdkVersion 23
buildToolsVersion '22.0.1'
packagingOptions {
}
defaultConfig {
minSdkVersion 17
targetSdkVersion 23
versionCode 11
versionName "2.1"
}
{s
และสอง}
) คุณซ่อมได้หรือไม่?