Sep 7, 2010

Strange java.lang.NoClassDefFoundError

In the beginning I was thinking this is a ClassNotFoundException, and spend many time on looking into my runtime classpath settings, compiling from outside Eclipse, but finally I realized it is not. It's some bug in my code. Here is the story:

The program is trying to decode UDP packets. I try to ping the server by simply echo some string to ncat, and the server failed immediately with a whole bunch of stack trace, and it always report java.lang.NoClassDefFoundError: Could not initialize class radiustool.protocol.Packet$Code, actually almost always report the error upon any packets received, except the first time. Here is the stacktrace of the first time:

java.lang.ExceptionInInitializerError
at radiustool.protocol.Packet$Codec.decode(Packet.java:429)
at radiustool.server.PacketDecoder.decode(PacketDecoder.java:21)
at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:282)
at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:216)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:274)
at org.jboss.netty.channel.socket.nio.NioDatagramWorker.read(NioDatagramWorker.java:419)
at org.jboss.netty.channel.socket.nio.NioDatagramWorker.processSelectedKeys(NioDatagramWorker.java:3r8)
at org.jboss.netty.channel.socket.nio.NioDatagramWorker.run(NioDatagramWorker.java:261)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:470)
at java.lang.Integer.parseInt(Integer.java:499)
at radiustool.protocol.Attribute$Type.parseInt(Attribute.java:118)
at radiustool.protocol.Packet$Code$1.setValidators(Packet.java:31)
at radiustool.protocol.Packet$Code.(Packet.java:201)
at radiustool.protocol.Packet$Code.(Packet.java:193)
at radiustool.protocol.Packet$Code$1.(Packet.java:22)
at radiustool.protocol.Packet$Code.(Packet.java:22)
... 11 more


So here we have it, one stupid non-needed line in Attribute.java is the root cause. But wait, there are something wrong some where, isn't it? Why an uncaptured RuntimeException cause a NoClassDefFoundError? Can't we throw out exception in a constructor? Okay, let's do a simple test:


public class T1 {

private static class T2 {
public T2(int i) {
if (i%2 == 0) throw new RuntimeException();
System.out.println("T2 initialized with: " + i);
}
}

private static enum T3 {
A(0), B(1);

T3(int i) {
if (i % 2 == 0) throw new RuntimeException();
System.out.println("T3 initialized with: " + i);
}
}

public static void main(String[] args) {
try {
T2 t2 = new T2(0);
} catch (Exception e) {
e.printStackTrace();
}

try {
T2 t2 = new T2(1);
} catch (Exception e) {
e.printStackTrace();
}

try {
T3 t3 = T3.A;
} catch (Throwable e) {
e.printStackTrace();
}

try {
T3 t3 = T3.B;
} catch (Throwable e) {
e.printStackTrace();
}
}

}


And here is the output:

java.lang.RuntimeException
at T1$T2.(T1.java:7)
at T1.main(T1.java:23)
T2 initialized with: 1
java.lang.ExceptionInInitializerError
at T1.main(T1.java:35)
Caused by: java.lang.RuntimeException
at T1$T3.(T1.java:16)
at T1$T3.(T1.java:13)
... 1 more
java.lang.NoClassDefFoundError: Could not initialize class T1$T3
at T1.main(T1.java:41)


So now everything is clear. it's okay for your to throw runtime exception in the constructor of a normal class, like T2 in the above code, there won't be NoClassDefFoundError the next time you refer to that class, but you need to be very careful in the constructor of a enum, if the system captures an exception in a constructor of an enum, you won't get that class anymore.

In conclusion, NEVER THROW EXCEPTION in the constructor of a enum!!!

1 comment:

Dom Casas said...

Even if you are knowledgeable on languages like C and C++, you can undergo java training to make your resume shine in the next interview you appear for.