运行时(at runtime)找到Class对象的classfile location
以下代码参考
http://www.javaworld.com/javaworld/javaqa/2003-07/01-qa-0711-classsrc.html
在项目中经常会碰到jar包冲突的情况,有时候想知道jvm到底是加载了哪个jar里面的对应类,下面这段代码就要派上用场鸟,呼呼
代码清晰易懂,我就不多做解释了,记录下来留着自己以后用
/** * Given a Class<?> object, attempts to find its .class location [returns * null if no such definiton could be found]. * * @return URL that points to the class definition [null if not found] */ 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 // documented 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; }
import java.io.File;import java.lang.reflect.Field;import java.net.MalformedURLException;import java.net.URL;import java.security.CodeSource;import java.security.ProtectionDomain;import java.util.Arrays;import java.util.HashSet;import java.util.LinkedList;import java.util.List;import java.util.Set;import java.util.Vector;/** * A simple static API for listing classes loaded in a JVM. Based on * {@link #getClassLocation(Class)} from * http://www.javaworld.com/javaworld/javaqa/2003-07/01-qa-0711-classsrc.html * @author (C) <a href="http://www.javaworld.com/columns/jw-qna-index.shtml">Vlad Roubtsov</a>, 2003 */public class ClassScope { private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0]; private static final Throwable CVF_FAILURE, CR_FAILURE; // set in <clinit> static { Throwable failure = null; Field tempf = null; try { // this can fail if this is not a Sun-compatible JVM // or if the security is too tight: tempf = ClassLoader.class.getDeclaredField("classes"); if (tempf.getType() != Vector.class) { throw new RuntimeException("not of type java.util.Vector: " + tempf.getType().getName()); } tempf.setAccessible(true); } catch (Throwable t) { failure = t; } CLASSES_VECTOR_FIELD = tempf; CVF_FAILURE = failure; failure = null; CallerResolver tempcr = null; try { // this can fail if the current SecurityManager does not allow // RuntimePermission ("createSecurityManager"): tempcr = new CallerResolver(); } catch (Throwable t) { failure = t; } CALLER_RESOLVER = tempcr; CR_FAILURE = failure; } /** * Given a class loader instance, returns all classes currently loaded by * that class loader. * * @param defining class loader to inspect [may not be null] * @return Class array such that every Class has 'loader' as its defining * class loader [never null, may be empty] * @throws RuntimeException * if the "classes" field hack is not possible in this JRE */ @SuppressWarnings("unchecked") public static Class<?>[] getLoadedClasses(final ClassLoader loader) { if (loader == null) { throw new IllegalArgumentException("null input: loader"); } if (CLASSES_VECTOR_FIELD == null) { throw new RuntimeException("ClassScope::getLoadedClasses() cannot be used in this JRE", CVF_FAILURE); } try { final Vector<Class<?>> classes = (Vector<Class<?>>) CLASSES_VECTOR_FIELD.get(loader); if (classes == null) return EMPTY_CLASS_ARRAY; final Class<?>[] result; // note: Vector is synchronized in Java 2, which helps us make // the following into a safe critical section: synchronized (classes) { result = new Class<?>[classes.size()]; classes.toArray(result); } return result; } // this should not happen if <clinit> was successful: catch (IllegalAccessException e) { e.printStackTrace(System.out); return EMPTY_CLASS_ARRAY; } } /** * A convenience multi-loader version of * {@link #getLoadedClasses(ClassLoader)}. * * @param an array of defining class loaders to inspect [may not be null] * @return Class<?> array [never null, may be empty] * @throws RuntimeException * if the "classes" field hack is not possible in this JRE */ public static Class<?>[] getLoadedClasses(final ClassLoader[] loaders) { if (loaders == null) throw new IllegalArgumentException("null input: loaders"); final List<Class<?>> resultList = new LinkedList<Class<?>>(); for (int l = 0; l < loaders.length; ++l) { final ClassLoader loader = loaders[l]; if (loader != null) { final Class<?>[] classes = getLoadedClasses(loaders[l]); resultList.addAll(Arrays.asList(classes)); } } final Class<?>[] result = new Class<?>[resultList.size()]; resultList.toArray(result); return result; } /** * Returns the class loader set "relevant" to the calling class, as * described in the article. Starting with the class that is the caller of * this method, it collects all class loaders that are loaders for all * classes on the call stack and their respective parent loaders. * * @return ClassLoader array [never null] * @throws RuntimeException * if the caller context resolver could not be instantiated */ public static ClassLoader[] getCallerClassLoaderTree() { if (CALLER_RESOLVER == null) throw new RuntimeException("Class<?>Scope::getCallerClassLoaderTree() cannot be used in this JRE", CR_FAILURE); final Class<?>[] callContext = CALLER_RESOLVER.getClassContext(); final Set<ClassLoader> resultSet = new HashSet<ClassLoader>(); for (int c = 2; c < callContext.length; ++c) { getClassLoaderTree(callContext[c], resultSet); } final ClassLoader[] result = new ClassLoader[resultSet.size()]; resultSet.toArray(result); return result; } /** * Given a Class<?> object, attempts to find its .class location [returns * null if no such definiton could be found]. * * @return URL that points to the class definition [null if not found] */ 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 // documented 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; } /** * A helper class to get the call context. It subclasses SecurityManager to * make getClassContext() accessible. An instance of CallerResolver only * needs to be created, not installed as an actual security manager. */ private static final class CallerResolver extends SecurityManager { protected Class<?>[] getClassContext() { return super.getClassContext(); } } // end of nested class private ClassScope() { } // this class is not extendible private static void getClassLoaderTree(final Class<?> cls, final Set<ClassLoader> resultSet) { if ((cls != null) && (resultSet != null)) { for (ClassLoader loader = cls.getClassLoader(); loader != null; loader = loader.getParent()) { resultSet.add(loader); } } } private static final Field CLASSES_VECTOR_FIELD; // set in <clinit> [can be null] private static final CallerResolver CALLER_RESOLVER; // set in <clinit> [can be null]}