但凡Java的开发者,想必遇到过java.lang.NoSuchMethodError的错误信息吧。究其源,这个错误基本上都是由JVM的"全盘负责委托机制"引发的问题:因为在类路径下放置了多个不同版本的类包,如commons-lang 2.x.jar和commons-lang3.x.jar都位于类路径中,代码中用到了commons-lang3.x类的某个方法,而这个方法在commons-lang2.x中并不存在,JVM加载类时碰巧又从commons-lang 2.x.jar中加载类,运行时就会抛出NoSuchMethodError的错误。
这种问题的排查是比较棘手的,特别是在Web应用的情况下,可作为类路径的系统目录比较多,特别在类包众多时,情况尤其复杂:你不知道JVM到底从哪个类包中加载类文件。不过笔者有一个一般人不告诉的易用小工具,现奉献出来:
这种问题的排查是比较棘手的,特别是在Web应用的情况下,可作为类路径的系统目录比较多,特别在类包众多时,情况尤其复杂:你不知道JVM到底从哪个类包中加载类文件。不过笔者有一个一般人不告诉的易用小工具,现奉献出来:
在光盘根路径下有一个srcAdd.jsp的程序,你把它放到Web应用的根路径下,通过如下方式即可查看JVM从哪个类包加载指定类:
- http://localhost/srcAdd.jsp?className=java.net.URL
<span style="font-size:18px;"> </span><span style="font-family:Microsoft YaHei;font-size:14px;">srcAdd.jsp</span>
<pre name="code" class="html"><span style="font-family:Microsoft YaHei;font-size:14px;"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page import="java.security.*,java.net.*,java.io.*"%>
<%!
public static URL getClassLocation(final Class cls)
{
if(cls==null)
{
throw new IllegalArgumentException("null input: cls");
}
URL result=null;
final String clsAsResource=cls.getName().replace('.', '/').concat(".class");
final ProtectionDomain pd=cls.getProtectionDomain();
// java.lang.Class contract does not specify if 'pd' can ever be null;
// it is not the case for Sun's implementations, but guard against null
// just in case:
if(pd != null)
{
final CodeSource cs=pd.getCodeSource();
// 'cs' can be null depending on the classloader behavior:
if(cs != null)
{
result=cs.getLocation();
}
if(result != null)
{
// Convert a code source location into a full class file location
// for some common cases:
if("file".equals(result.getProtocol()))
{
try
{
if(result.toExternalForm().endsWith(".jar") || result.toExternalForm().endsWith(".zip"))
{
result=new URL("jar:".concat(result.toExternalForm()).concat("!/").concat(clsAsResource));
}
else if(new File(result.getFile()).isDirectory())
{
result=new URL(result, clsAsResource);
}
}
catch(MalformedURLException ignore)
{
}
}
}
}
if(result == null)
{
// Try to find 'cls' definition as a resource; this is not
// document.d to be legal, but Sun's implementations seem to //allow this:
final ClassLoader clsLoader=cls.getClassLoader();
result=clsLoader != null ? clsLoader.getResource(clsAsResource) : ClassLoader.getSystemResource(clsAsResource);
}
return result;
}
%>
<html>
<head>
<title>srcAdd.jar</title>
</head>
<body bgcolor="#ffffff">
使用方法,className参数为类的全名,不需要.class后缀,如
srcAdd.jsp?className=java.net.URL
<%
try
{
String classLocation=null;
String error=null;
String className=request.getParameter("className");
classLocation=""+getClassLocation(Class.forName(className));
if(error == null)
{
out.print("类" + className + "实例的物理文件位于:");
out.print("<hr>");
out.print(classLocation);
}
else
{
out.print("类" + className + "没有对应的物理文件。<br>");
out.print("错误:" + error);
}
}
catch(Exception e)
{
out.print("异常。"+e.getMessage());
}
%>
</body>
</html></span>