All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.drinkjava2.jbeanbox.ClassScanner Maven / Gradle / Ivy

There is a newer version: 5.0.15.jre8
Show newest version
/*
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package com.github.drinkjava2.jbeanbox;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.regex.Pattern;

/**
 * A util class used to scan all classes in some packages, include all child
 * folders and jars insdie of packages' path.
 * 
 * @author: cent
 * @email: [email protected]
 * @date: 2019/1/8.
 * 
 * @author: Yong(shrink & downgrade to Java7)
 * @since 2.5.0
 */
@SuppressWarnings("all")
public enum ClassScanner {
	;
	public static enum ProtocolTypes {
		http, https, file, jar;
	}

	/**
	 * Find all classes in packages 扫描一或多个包下的所有Class,包含接口类
	 *
	 * @param scanBasePackages
	 * @return
	 */
	public static List scanPackages(String... scanBasePackages) {
		List classList = new LinkedList();
		if (scanBasePackages.length == 0) {
			return classList;
		}
		for (String pkg : scanBasePackages) {
			if (pkg != null && pkg.length() != 0)
				classList.addAll(ClassScanner.scanOnePackage(pkg));
		}
		return classList;
	}

	/**
	 * Find all classes with given annotation in packages 扫描某个包下带有注解的Class
	 *
	 * @param anno
	 * @param scanBasePackages
	 * @return
	 */
	public static List scanByAnno(Class anno, String... scanBasePackages) {
		List classList = scanPackages(scanBasePackages);
		List result = new ArrayList();
		for (Class clz : classList) {
			Annotation clzAnno = clz.getAnnotation(anno);
			if (clzAnno != null)
				result.add(clz);
		}
		return result;
	}

	/**
	 * Find all classes with given name patten 扫描某个包下所有类名匹配通配符的Class
	 *
	 * @param nameSimpleReg
	 *            name patten, only 1 * allow, 类名简化版通配符,只允许一个星号出现
	 * @param scanBasePackages
	 * @return
	 */
	public static List scanByName(String nameSimpleReg, String... scanBasePackages) {
		List classList = scanPackages(scanBasePackages);
		List result = new ArrayList();
		for (Class clz : classList)
			if (NameMatchUtil.nameMatch(nameSimpleReg, clz.getName()))
				result.add(clz);
		return result;
	}

	/**
	 * find all classes in one package 扫描某个包下所有Class类
	 *
	 * @param pkg
	 * @return Class
	 */
	private static List scanOnePackage(String pkg) {
		List classList = new LinkedList();
		try {
			// 包名转化为路径名
			String pathName = package2Path(pkg);
			// 获取路径下URL
			Enumeration urls = Thread.currentThread().getContextClassLoader().getResources(pathName);
			// 循环扫描路径
			classList = scanUrls(pkg, urls);
		} catch (IOException e) {
			System.err.println("Warning: Can not scan package:" + pkg);
		}

		return classList;
	}

	/**
	 * find all classes in urls 扫描多个Url路径,找出符合包名的Class类
	 *
	 * @param pkg
	 * @param urls
	 * @return Class
	 * @throws IOException
	 */
	private static List scanUrls(String pkg, Enumeration urls) throws IOException {
		List classList = new LinkedList();
		while (urls.hasMoreElements()) {
			URL url = urls.nextElement();
			// 获取协议
			String protocol = url.getProtocol();

			if (ProtocolTypes.file.name().equals(protocol)) {
				// 文件
				String path = URLDecoder.decode(url.getFile(), "UTF-8");
				classList.addAll(recursiveScan4Path(pkg, path));

			} else if (ProtocolTypes.jar.name().equals(protocol)) {
				// jar包
				String jarPath = getJarPathFormUrl(url);
				classList.addAll(recursiveScan4Jar(pkg, jarPath));
			}
		}
		return classList;
	}

	/**
	 * get real path from url 从url中获取jar真实路径
	 * 

* jar文件url示例如下: *

* jar:file:/Users/cent/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.4/7103ab519b1cdbb0642ad4eaf1db209d905d0f96/lombok-1.18.4.jar!/org * * @param url * @return */ private static String getJarPathFormUrl(URL url) { String file = url.getFile(); String jarRealPath = file.substring(0, file.lastIndexOf("!")).replaceFirst("file:", ""); return jarRealPath; } /** * recursive scan for path 递归扫描指定文件路径下的Class文件 * * @param pkg * @param filePath * @return Class列表 */ private static List recursiveScan4Path(String pkg, String filePath) { List classList = new LinkedList(); File file = new File(filePath); if (!file.exists() || !file.isDirectory()) { return classList; } // 处理类文件 File[] classes = file.listFiles(new FileFilter() { public boolean accept(File child) { return isClass(child.getName()); } }); for (File child : classes) { String className = classFile2SimpleClass( new StringBuilder().append(pkg).append(".").append(child.getName()).toString()); try { Class clz = Thread.currentThread().getContextClassLoader().loadClass(className); classList.add(clz); } catch (ClassNotFoundException e) { System.err.println("Warning: Can not load class:" + className); } catch (LinkageError e) { System.err.println("Warning: Can not load class:" + className); } } // 处理目录 File[] dirs = file.listFiles(new FileFilter() { public boolean accept(File f) { return f.isDirectory(); } }); for (File child : dirs) { String childPackageName = new StringBuilder().append(pkg).append(".").append(child.getName()).toString(); String childPath = new StringBuilder().append(filePath).append("/").append(child.getName()).toString(); classList.addAll(recursiveScan4Path(childPackageName, childPath)); } return classList; } /** * Recursive scan 4 jar 递归扫描Jar文件内的Class类 * * @param pkg * @param jarPath * @return Class列表 * @throws IOException */ private static List recursiveScan4Jar(String pkg, String jarPath) throws IOException { List classList = new LinkedList(); JarInputStream jin = new JarInputStream(new FileInputStream(jarPath)); JarEntry entry = jin.getNextJarEntry(); while (entry != null) { String name = entry.getName(); entry = jin.getNextJarEntry(); if (!name.contains(package2Path(pkg))) { continue; } if (isClass(name)) { if (isAnonymousInnerClass(name)) { // 是匿名内部类,跳过不作处理 continue; } String className = classFile2SimpleClass(path2Package(name)); try { Class clz = Thread.currentThread().getContextClassLoader().loadClass(className); classList.add(clz); } catch (ClassNotFoundException e) { System.err.println("Warning: Can not load class:" + className); } catch (LinkageError e) { System.err.println("Warning: Can not load class:" + className); } } } return classList; } // ===== Inside used static tool methods ===== private static final Pattern ANONYMOUS_INNER_CLASS_PATTERN = Pattern.compile("^[\\s\\S]*\\${1}\\d+\\.class$"); private static String package2Path(String packageName) { return packageName.replace(".", "/"); } private static String path2Package(String pathName) { return pathName.replaceAll("/", "."); } private static boolean isClass(String fileName) { if (fileName == null || fileName.length() == 0) { return false; } return fileName.endsWith(".class"); } private static String classFile2SimpleClass(String classFileName) { return classFileName.replace(".class", ""); } private static boolean isAnonymousInnerClass(String className) { return ANONYMOUS_INNER_CLASS_PATTERN.matcher(className).matches(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy