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

package com.shdl.htscada.utils;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 遍历指定包名下所有的类(支持jar)
 * @author ht-meeting
 * @date 2017年7月7日
 */
public class ClassFilesUtils {
	public static void main(String[] args) throws Exception {
		String packageName = "com.shdl.htscada.i18n";
		Set<String> classNames = getClassName(packageName, false, ".properties");
		if (classNames != null) {
			for (String className : classNames) {
				System.out.println(className);
			}
		}
	}

	/**
	 * 获取某包下所有类
	 * @param packageName 包名
	 * @param isRecursion 是否遍历子包
	 * @param suffixstr 后綴名
	 * @return 类的完整名称
	 */
	public static Set<String> getClassName(String packageName, boolean isRecursion ,String suffixstr) {
		Set<String> classNames = null;
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		String packagePath = packageName.replace(".", "/");

		URL url = loader.getResource(packagePath);
		if (url != null) {
			String protocol = url.getProtocol();
			if (protocol.equals("file")) {
				classNames = getClassNameFromDir(url.getPath(), packageName, isRecursion, suffixstr);
			} else if (protocol.equals("jar")) {
				JarFile jarFile = null;
				try{
	                jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
				} catch(Exception e){
					e.printStackTrace();
				}

				if(jarFile != null){
					getClassNameFromJar(jarFile.entries(), packageName, isRecursion);
				}
			}
		} else {
			/*从所有的jar包中查找包名*/
			classNames = getClassNameFromJars(((URLClassLoader)loader).getURLs(), packageName, isRecursion);
		}

		return classNames;
	}

	/**
	 * 从项目文件获取某包下所有类
	 * @param filePath 文件路径
	 * @param className 类名集合
	 * @param isRecursion 是否遍历子包
	 * @param suffixstr 後綴名
	 * @return 类的完整名称
	 */
	private static Set<String> getClassNameFromDir(String filePath, String packageName, boolean isRecursion, String suffixstr) {
		Set<String> className = new HashSet<String>();
		try {
			filePath = java.net.URLDecoder.decode(new String(filePath.getBytes("ISO-8859-1"), "UTF-8"), "UTF-8");
			File file = new File(filePath);
			File[] files = file.listFiles();
			for (File childFile : files) {
				if (childFile.isDirectory()) {
					if (isRecursion) {
						className.addAll(getClassNameFromDir(childFile.getPath(), packageName+"."+childFile.getName(), isRecursion, suffixstr));
					}
				} else {
					String fileName = childFile.getName();
					if (fileName.endsWith(suffixstr) && !fileName.contains("$")) {
						//className.add(fileName);
						className.add(packageName+ "." + fileName);
					}
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		return className;
	}

	/**
	 * @param jarEntries
	 * @param packageName
	 * @param isRecursion
	 * @return
	 */
	private static Set<String> getClassNameFromJar(Enumeration<JarEntry> jarEntries, String packageName, boolean isRecursion){
		Set<String> classNames = new HashSet<String>();

		while (jarEntries.hasMoreElements()) {
			JarEntry jarEntry = jarEntries.nextElement();
			if(!jarEntry.isDirectory()){
				/*
	             * 这里是为了方便,先把"/" 转成 "." 再判断 ".class" 的做法可能会有bug
	             * (FIXME: 先把"/" 转成 "." 再判断 ".class" 的做法可能会有bug)
	             */
				String entryName = jarEntry.getName().replace("/", ".");
				if (entryName.endsWith(".class") && !entryName.contains("$") && entryName.startsWith(packageName)) {
					entryName = entryName.replace(".class", "");
					if(isRecursion){
						classNames.add(entryName);
					} else if(!entryName.replace(packageName+".", "").contains(".")){
						classNames.add(entryName);
					}
				}
			}
		}

		return classNames;
	}

	/**
	 * 从所有jar中搜索该包,并获取该包下所有类
	 * @param urls URL集合
	 * @param packageName 包路径
	 * @param isRecursion 是否遍历子包
	 * @return 类的完整名称
	 */
	private static Set<String> getClassNameFromJars(URL[] urls, String packageName, boolean isRecursion) {
		Set<String> classNames = new HashSet<String>();

		for (int i = 0; i < urls.length; i++) {
			String classPath = urls[i].getPath();

			//不必搜索classes文件夹
			if (classPath.endsWith("classes/")) {continue;}

			JarFile jarFile = null;
			try {
				jarFile = new JarFile(classPath.substring(classPath.indexOf("/")));
			} catch (IOException e) {
				e.printStackTrace();
			}

			if (jarFile != null) {
				classNames.addAll(getClassNameFromJar(jarFile.entries(), packageName, isRecursion));
			}
		}

		return classNames;
	}
}
时间: 2024-10-14 04:07:50

java 遍历指定包名下所有的类(支持jar)的相关文章

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

支持包名下的子包名遍历,并使用Annotation(内注)来过滤一些不必要的内部类,提高命中精度. 通过Thread.currentThread().getContextClassLoader()获取ClassLoader实例将包名转为路径名后,做为参数传给CloassLoader.getResources(),以得到该路径下所有资源的URL;通过URL.getProtocol()方法,判断资源是在本地(file:)或是第三方jar包(jar:)内;在本地的类直接文件遍历即可;第三方jar则通过

Android支持Split Apks后,如何获得指定包名下的所有类

从Android5.0以后,支持多个apk动态部署,这导致以前通过单一apk获取包路径下的所有类的方法失效,不过稍微修改一下原先的代码就可以,代码如下 1 public static final List<Class<?>> getClassesFromPackage(Context ctx, String pkgName) { 2 List<Class<?>> rtnList = new ArrayList<Class<?>>();

加载指定包名下的所有类或根据类的annotation进行过滤的工具类

版权声明:本文为博主原创文章,未经博主允许不得转载.

加载指定包名下的全部类以及指定annotation进行过滤的工具类

package org.konghao.sys.kit; import java.io.File; import java.io.FileFilter; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import o

加载指定包下的所有类

package util; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import java.util.jar.JarEnt

获取指定包名下继承或者实现某接口的所有类(扫描文件目录和所有jar)

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.LinkedHashSet; im

24.Java中atomic包中的原子操作类总结

1. 原子操作类介绍 在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量i=1,比如多个线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全的目的(关于synchronized可以看这篇文章).但是由于synchronized是采用的是悲观锁策略,并不是特别高效的一种解决方案.实际上,在J.U.C下的atomic包提供了一系列的操作简单,性能高效,并能保证线程安全的类去更新基本类型变量,数组元素,引用类

Java 遍历指定文件夹及子文件夹下的文件

/** * 遍历指定文件夹及子文件夹下的文件 * * @author testcs_dn * @date 2014年12月12日下午2:33:49 * @param file 要遍历的指定文件夹 * @param collector 符合条件的结果加入到此List<File>中 * @param pathInclude 路径中包括指定的字符串 * @param fileNameInclude 文件名称(不包括扩展名)中包括指定的字符串 * @param extnEquals 文件扩展名为指定字

Java 遍历指定目录及子目录下的文件

/** * 遍历指定目录及子目录下的文件 * * @author testcs_dn * @date 2014年12月12日下午2:33:49 * @param file 要遍历的指定目录 * @param collector 符合条件的结果添加到此List<File>中 * @param pathInclude 路径中包含指定的字符串 * @param fileNameInclude 文件名(不包含扩展名)中包含指定的字符串 * @param extnEquals 文件扩展名为指定字符串 *