[Java] 遍历指定包名下所有的类(支持jar)

项目需要,仅做记录。
支持包名下的子包名遍历,并使用Annotation(内注)来过滤一些不必要的内部类,提高命中精度。

通过Thread.currentThread().getContextClassLoader()获取ClassLoader实例
将包名转为路径名后,做为参数传给CloassLoader.getResources(),以得到该路径下所有资源的URL;
通过URL.getProtocol()方法,判断资源是在本地(file:)或是第三方jar包(jar:)内;
在本地的类直接文件遍历即可;
第三方jar则通过URL.openConnection()得到JarURLConnection,再通过JarURLConnection.getJarFile()获得JarFile,最后遍历该JarFile的item即可。


示例工程结构见下图.

[Java] 遍历指定包名下所有的类(支持jar)_第1张图片


package lab.sodino.clazz;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation:见http://blog.csdn.net/sodino/article/details/7987888
 * */
@Target(ElementType.TYPE)//ElementType.TYPE用于标识类、接口(包括内注自身)、枚举
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface author {
	//修饰符仅可为public, protected, private & static的组合
	public static enum AppEnum {
		Web, Client, Service, Undesignated
	};

	//public & abstract的组合或默认
	AppEnum type() default AppEnum.Undesignated;

	String name() default "unknown";

	String webSite() default "N/A";
}


package lab.sodino.clazz;
/**
 * @author Sodino E-mail:sodino@qq.com
 * @version Time:2014年2月10日 下午9:06:55
 */
@author(name="sodino", webSite="sodino.com")
public class ClassTestDemo {

}



package lab.sodino.clazz;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 用于获取指定包名下的所有类名.<br/>
 * 并可设置是否遍历该包名下的子包的类名.<br/>
 * 并可通过Annotation(内注)来过滤,避免一些内部类的干扰.<br/>
 * 
 * @author Sodino E-mail:sodino@qq.com
 * @version Time:2014年2月10日 下午3:55:59
 */
public class ClassUtil {
	public static void main(String []args){
		// 标识是否要遍历该包路径下子包的类名
//		boolean recursive = false;
		boolean recursive = true;
		// 指定的包名
//		String pkg = "javax.crypto.spec";// 为java/jre6/lib/jce.jar,普通的java工程默认已引用
//		String pkg = "javax.crypto";
//		String pkg = "lab.sodino";
		String pkg = "lab.sodino.clazz";
		List list = null;
//		list = getClassList(pkg, recursive, null);
		// 增加 author.class的过滤项,即可只选出ClassTestDemo
		list = getClassList(pkg, recursive, author.class);
		
		for(int i = 0;i < list.size(); i ++){
			System.out.println(i +":"+list.get(i));
		}
	}
	
	public static List<Class<?>> getClassList(String pkgName , boolean isRecursive, Class<? extends Annotation> annotation) {
		List<Class<?>> classList = new ArrayList<Class<?>>();
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		try {
			// 按文件的形式去查找
			String strFile = pkgName.replaceAll("\\.", "/");
			Enumeration<URL> urls = loader.getResources(strFile);
			while (urls.hasMoreElements()) {
				URL url = urls.nextElement();
                if (url != null) {
                	String protocol = url.getProtocol();
                	String pkgPath = url.getPath();
                	System.out.println("protocol:" + protocol +" path:" + pkgPath);
                    if ("file".equals(protocol)) {
                    	// 本地自己可见的代码
						findClassName(classList, pkgName, pkgPath, isRecursive, annotation);
					} else if ("jar".equals(protocol)) {
                    	// 引用第三方jar的代码
						findClassName(classList, pkgName, url, isRecursive, annotation);
                    }
                }
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return classList;
	}
	
	public static void findClassName(List<Class<?>> clazzList, String pkgName, String pkgPath, boolean isRecursive, Class<? extends Annotation> annotation) {
		if(clazzList == null){
			return;
		}
		File[] files = filterClassFiles(pkgPath);// 过滤出.class文件及文件夹
		System.out.println("files:" +((files == null)?"null" : "length=" + files.length));
		if(files != null){
			for (File f : files) {
				String fileName = f.getName();
				if (f.isFile()) {
					// .class 文件的情况
					String clazzName = getClassName(pkgName, fileName);
					addClassName(clazzList, clazzName, annotation);
				} else {
					// 文件夹的情况
					if(isRecursive){
						// 需要继续查找该文件夹/包名下的类
						String subPkgName = pkgName +"."+ fileName;
						String subPkgPath = pkgPath +"/"+ fileName;
						findClassName(clazzList, subPkgName, subPkgPath, true, annotation);
					}
				}
			}
		}
	}
	
	/**
	 * 第三方Jar类库的引用。<br/>
	 * @throws IOException 
	 * */
	public static void findClassName(List<Class<?>> clazzList, String pkgName, URL url, boolean isRecursive, Class<? extends Annotation> annotation) throws IOException {
		JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
		JarFile jarFile = jarURLConnection.getJarFile();
		System.out.println("jarFile:" + jarFile.getName());
		Enumeration<JarEntry> jarEntries = jarFile.entries();
		while (jarEntries.hasMoreElements()) {
			JarEntry jarEntry = jarEntries.nextElement();
			String jarEntryName = jarEntry.getName(); // 类似:sun/security/internal/interfaces/TlsMasterSecret.class
			String clazzName = jarEntryName.replace("/", ".");
			int endIndex = clazzName.lastIndexOf(".");
			String prefix = null;
			if (endIndex > 0) {
				String prefix_name = clazzName.substring(0, endIndex);
				endIndex = prefix_name.lastIndexOf(".");
				if(endIndex > 0){
					prefix = prefix_name.substring(0, endIndex);
				}
			}
			if (prefix != null && jarEntryName.endsWith(".class")) {
//				System.out.println("prefix:" + prefix +" pkgName:" + pkgName);
				if(prefix.equals(pkgName)){
					System.out.println("jar entryName:" + jarEntryName);
					addClassName(clazzList, clazzName, annotation);
				} else if(isRecursive && prefix.startsWith(pkgName)){
					// 遍历子包名:子类
					System.out.println("jar entryName:" + jarEntryName +" isRecursive:" + isRecursive);
					addClassName(clazzList, clazzName, annotation);
				}
			}
		}
	}
	
	private static File[] filterClassFiles(String pkgPath) {
		if(pkgPath == null){
			return null;
		}
		// 接收 .class 文件 或 类文件夹
		return new File(pkgPath).listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();
			}
		});
    }
	
	private static String getClassName(String pkgName, String fileName) {
		int endIndex = fileName.lastIndexOf(".");
		String clazz = null;
		if (endIndex >= 0) {
			clazz = fileName.substring(0, endIndex);
		}
		String clazzName = null;
		if (clazz != null) {
			clazzName = pkgName + "." + clazz;
		}
		return clazzName;
	}
	
	private static void addClassName(List<Class<?>> clazzList, String clazzName, Class<? extends Annotation> annotation) {
		if (clazzList != null && clazzName != null) {
			Class<?> clazz = null;
			try {
				clazz = Class.forName(clazzName);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
//			System.out.println("isAnnotation=" + clazz.isAnnotation() +" author:" + clazz.isAnnotationPresent(author.class));
			
			if (clazz != null) {
				if(annotation == null){
					clazzList.add(clazz);
					System.out.println("add:" + clazz);
				} else if (clazz.isAnnotationPresent(annotation)){
					clazzList.add(clazz);
					System.out.println("add annotation:" + clazz);
				}
			}
		}
	}
}



你可能感兴趣的:(java)