我遇到了一个让我完全措手不及的问题,我花了很长时间才弄明白到底怎么了。Struts 1.2.7发行版附带了commons logging 1.0.4和log4j 1.2.8。当我将控制台升级到struts 1.2.7并试图将其部署到服务器上时,部署失败了,出现了下面的错误:
java.lang.NoSuchMethodError: isEnabledFor
at org.apache.commons.logging.impl.Log4JCategoryLog.isErrorEnabled(Log4JCategoryLog.java:189)
at org.apache.beehive.netui.util.logging.Logger.isErrorEnabled(Logger.java:97)
at org.apache.beehive.netui.pageflow.internal.AdapterManager.getServletContainerAdapter(AdapterManager.java:47)
at org.apache.beehive.netui.pageflow.PageFlowUtils.createURLTemplatesFactory(PageFlowUtils.java:1716)
最初,我以为这是由于系统类路径中某处存在另一个commons-logging.jar版本并被应用程序获得而引起的。但是仔细查看了类路径以及应用程序中的其他库之后,我没发现任何不妥之处,这使我快要疯了。后来我想应该装备Log4JCategoryLog类,看看org.apache.log4j.Category中什么方法使它产生了NoSuchMethodError错误。编译并将其重新包装进commons-logging.jar之后,我惊奇地发现一切都正常了。我可以看到装备Log4jCategoryLog时的调试输出。这使我考虑:把类文件打包在commons-logging.jar中是否不正确?为了验证,我把问题只限定在commons-logging和log4j上。在一个同事的帮助下,下面这个简单的再现类指出了问题所在:
public class Foo {
// Ensure that your classpath has commons-logging-1.0.4.jar and log4j-1.2.8.jar
public static void main(String[] args) {
org.apache.commons.logging.impl.Log4JCategoryLog x = new org.apache.commons.logging.impl.Log4JCategoryLog();
x.isErrorEnabled();
}
}
这个简单的客户端因与部署控制台时相同的错误而失败。我相信问题出在来自apache的commons-logging-1.0.4中的类上面:使用了错误的log4j Category类对其进行编译。
如果使用commons-logging-1.0.4.jar在类路径中执行javap -c org.apache.commons.logging.impl.Log4JCategoryLog,就可以看到isErrorEnabled方法:
public boolean isErrorEnabled();
Code:
0: aload_0
1: getfield #7; //Field category:Lorg/apache/log4j/Category;
4: getstatic #14; //Field org/apache/log4j/Level.ERROR:Lorg/apache/log4j/Level;
7: invokevirtual #17; //Method org/apache/log4j/Category.isEnabledFor:(Lorg/apache/log4j/Level;)Z
10: ireturn
这里,log4j的Category的isEnabledFor使用Level作为参数,但是Log4JCategoryLog应该是一个Priority类型的参数。如果重新编译Log4JCategoryLog并将其重新打包,并对该类执行javap –c,则将得到以下结果:
public boolean isErrorEnabled();
Code:
0: aload_0
1: getfield #2; //Field category:Lorg/apache/log4j/Category;
4: getstatic #9; //Field org/apache/log4j/Priority.ERROR:Lorg/apache/log4j/Priority;
7: invokevirtual #12; //Method org/apache/log4j/Category.isEnabledFor:(Lorg/apache/log4j/Priority;)Z
10: ireturn
可以看出,log4j的Category的isEnabledFor使用一个Priority类型的对象作为参数,这是正确的。用google搜索了一下,我发现这个问题在新的commons-logging jar中已经被纠正了,可从下面的页面上得到新版本:http://www.ibiblio.org/maven/commons-logging/jars/commons-logging-1.1-dev.jar。
原文出处:http://dev2dev.bea.com/blog/sghattu/archive/2006/02/in_case_you_run.html