Java Tomcat 6-静态初始化器中的错误被NoClassDefFoundError隐藏
我在Tomcat应用程序中有一个类,它有一个静态初始值设定项。正在静态初始值设定项中抛出一个Java Tomcat 6-静态初始化器中的错误被NoClassDefFoundError隐藏,java,tomcat,exception-handling,Java,Tomcat,Exception Handling,我在Tomcat应用程序中有一个类,它有一个静态初始值设定项。正在静态初始值设定项中抛出一个错误 问题是Tomcat显示的错误消息不包括“原因”,即,不显示来自该错误的消息和堆栈跟踪 我可以这样重现问题: public class BadInitClass { static { if (System.currentTimeMillis() > 0) throw new Error("I need to see this message"); } pub
错误
问题是Tomcat显示的错误消息不包括“原因”,即,不显示来自该错误的消息和堆栈跟踪
我可以这样重现问题:
public class BadInitClass
{
static
{
if (System.currentTimeMillis() > 0)
throw new Error("I need to see this message");
}
public void doSomething()
{
System.out.println("functionality here");
}
}
现在,如果我从单元测试调用这个类:
@Test
public void testStaticInit() throws Exception
{
new BadInitClass().doSomething();
}
然后,测试打印出堆栈跟踪和消息:
java.lang.Error: I need to see this message
at mypackage.BadInitClass.<clinit>(BadInitClass.java:8)
at mypackage.BadInitClassTest.testStaticInit(UOneUtilitiesTest.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
我正在运行Tomcat 6.0.37
这是Tomcat里的一只虫子吗?有什么解决办法吗
我知道静态初始化器通常不是一个好主意,但我有一些使用它们的遗留代码,如果没有底层错误消息和堆栈跟踪,调试这些问题是非常痛苦的
我注意到单元测试没有NoClassDefFoundError,这个问题与tomcat使用的自定义类加载器有关吗?在BadInitClass类中有哪些导入?BadInitClass中使用了一个tomcat找不到的类。我注意到
NoClassDefFoundError
不允许内部异常:
在这种情况下,如果不修补Tomcat的类加载器以引发不同类型的异常,这可能无法修复?明白了——问题是静态初始值设定项的错误只是第一次引发的。
第二次及以后访问该类时,将抛出一个NoClassDefFoundError
,其中没有内部异常详细信息:
此测试演示了该问题(与上面的“BadInitClass
”相同)
这与Tomcat无关。否,由于找不到类,因此不会抛出
NoClassDefFoundError
;它是由于静态初始值设定项中的错误而引发的。我在问题中没有说清楚吗?。。。或者,当静态初始值设定项失败时,由Tomcat 6.0.37执行。你自己试试。这个错误是因为类BadInitClass不能被JVM初始化。我说我的答案是因为错误可能是BadInitClass的导入,或者是因为静态区域是错误的,但我认为它是正确的。如果你不抛出新的异常,会出现相同的错误吗?可能tomcat尝试初始化类并捕获错误,因此tomcat抛出NoClassDefFoundError
exception
javax.servlet.ServletException: Servlet.init() for servlet MyServlet threw exception
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
java.lang.Thread.run(Thread.java:662)
root cause
java.lang.NoClassDefFoundError: Could not initialize class mypackage.BadInitClass
mypackage.[calling code here]
datcon.webmail.utils.DispatchedHttpServlet.init(DispatchedHttpServlet.java:77)
MyServlet.init(MyServlet.java:57)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
java.lang.Thread.run(Thread.java:662)
note The full stack trace of the root cause is available in the Apache Tomcat/6.0.37 logs.
public void testStaticInit() throws Exception
{
// First attempt: the underlying message is available:
try {
new BadInitClass().doSomething();
} catch (Throwable t) {
assertThat(t, instanceOf(Error.class));
assertThat(
getFullStackTraceWithCauses(t),
containsString("I need to see this message"));
}
// Second attempt: a NoClassDefFoundError with no "cause":
try {
new BadInitClass().doSomething();
} catch (Throwable t) {
assertThat(t, instanceOf(NoClassDefFoundError.class));
assertThat(
getFullStackTraceWithCauses(t),
not(containsString("I need to see this message")));
}
}
private String getFullStackTraceWithCauses(Throwable t)
{
StringWriter writer = new StringWriter();
t.printStackTrace(new PrintWriter(writer));
return writer.toString();
}