package com.taobao.tddl.optimizer.utils; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.JarURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import com.google.common.collect.Lists; import com.taobao.tddl.optimizer.exceptions.FunctionException; /** * @author jianghang 2013-11-8 下午7:55:16 * @since 5.0.0 */ public class PackageUtils { public static List<Class> findClassesInPackage(String packageName, ClassFilter filter) { try { List<String> classes = Lists.newArrayList(); String packageDirName = packageName.replace('.', '/'); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); Enumeration<URL> dirEnumeration = classLoader.getResources(packageDirName); List<URL> dirs = Lists.newArrayList(); while (dirEnumeration.hasMoreElements()) { URL dir = dirEnumeration.nextElement(); dirs.add(dir); } Iterator<URL> dirIterator = dirs.iterator(); while (dirIterator.hasNext()) { URL url = dirIterator.next(); String protocol = url.getProtocol(); if ("file".equals(protocol)) { findClassesInDirPackage(packageName, URLDecoder.decode(url.getFile(), "UTF-8"), classes); } else if ("jar".equals(protocol)) { JarFile jar = ((JarURLConnection) url.openConnection()).getJarFile(); Enumeration<JarEntry> entries = jar.entries(); while (entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); String pName = packageName; if (name.charAt(0) == '/') { name = name.substring(1); } if (name.startsWith(packageDirName)) { int idx = name.lastIndexOf('/'); if (idx != -1) { pName = name.substring(0, idx).replace('/', '.'); } if (idx != -1) { // it's not inside a deeper dir if (name.endsWith(".class") && !entry.isDirectory()) { String className = name.substring(pName.length() + 1, name.length() - 6); classes.add(makeFullClassName(pName, className)); } } } } } } List<Class> result = Lists.newArrayList(); for (String clazz : classes) { if (filter == null || filter.preFilter(clazz)) { Class<?> cls = null; try { cls = Class.forName(clazz); } catch (Throwable e) { // ignore } if (cls != null && (filter == null || filter.filter(cls))) { result.add(cls); } } } return result; } catch (IOException e) { throw new FunctionException("findClassesInPackage : " + packageName + " is failed. ", e); } } private static void findClassesInDirPackage(String packageName, String packagePath, List<String> classes) { File dir = new File(packagePath); if (!dir.exists() || !dir.isDirectory()) { return; } File[] dirfiles = dir.listFiles(new FileFilter() { @Override public boolean accept(File file) { return file.isDirectory() || (file.getName().endsWith(".class")); } }); for (File file : dirfiles) { if (file.isDirectory()) { findClassesInDirPackage(makeFullClassName(packageName, file.getName()), file.getAbsolutePath(), classes); } else { String className = file.getName().substring(0, file.getName().lastIndexOf(".")); classes.add(makeFullClassName(packageName, className)); } } } private static String makeFullClassName(String pkg, String cls) { return pkg.length() > 0 ? pkg + "." + cls : cls; } public static interface ClassFilter { public boolean preFilter(String className); public boolean filter(Class clazz); } }