Package com.xiaoleilu.hutool

Source Code of com.xiaoleilu.hutool.ClassUtil$ClassFilter

package com.xiaoleilu.hutool;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.URL;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;

import com.xiaoleilu.hutool.exceptions.UtilException;

/**
* 类工具类
* 1、扫描指定包下的所有类<br>
* 参考 http://www.oschina.net/code/snippet_234657_22722
* @author seaside_hi, xiaoleilu
*
*/
public class ClassUtil {
  private static Logger log = Log.get();
 
  /**
   * 基本变量类型的枚举
   * @author xiaoleilu
   */
  private static enum BASIC_TYPE {
    BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING;
  }
 
  private ClassUtil() {
  }
 
  /**
   * 扫面改包路径下所有class文件
   *
   * @param packageName 包路径 com | com. | com.abs | com.abs.
   * @return 类集合
   */
  public static Set<Class<?>> scanPackage(String packageName) {
    return scanPackage(packageName, null);
  }
 
  /**
   * 扫描指定包路径下所有包含指定注解的类
   * @param packageName 包路径
   * @param annotationClass 注解类
   * @return 类集合
   */
  public static Set<Class<?>> scanPackageByAnnotation(String packageName, final Class<? extends Annotation> annotationClass) {
    return scanPackage(packageName, new ClassFilter() {
      @Override
      public boolean accept(Class<?> clazz) {
        return clazz.isAnnotationPresent(annotationClass);
      }
    });
  }
 
  /**
   * 扫描指定包路径下所有指定类的子类
   * @param packageName 包路径
   * @param superClass 父类
   * @return 类集合
   */
  public static Set<Class<?>> scanPackageBySuper(String packageName, final Class<?> superClass) {
    return scanPackage(packageName, new ClassFilter() {
      @Override
      public boolean accept(Class<?> clazz) {
        return superClass.isAssignableFrom(clazz) && !superClass.equals(clazz);
      }
    });
  }
 
  /**
   * 扫面包路径下满足class过滤器条件的所有class文件,</br>
   * 如果包路径为 com.abs + A.class 但是输入 abs会产生classNotFoundException</br>
   * 因为className 应该为 com.abs.A 现在却成为abs.A,此工具类对该异常进行忽略处理,有可能是一个不完善的地方,以后需要进行修改</br>
   *
   * @param packageName 包路径 com | com. | com.abs | com.abs.
   * @param classFilter class过滤器,过滤掉不需要的class
   * @return 类集合
   */
  public static Set<Class<?>> scanPackage(String packageName, ClassFilter classFilter) {
    if(StrUtil.isBlank(packageName)) {
      packageName = StrUtil.EMPTY;
    }
    log.debug("Scan classes from package [{}]...", packageName);
    packageName = getWellFormedPackageName(packageName);
   
    final Set<Class<?>> classes = new HashSet<Class<?>>();
    for (String classPath : getClassPaths(packageName)) {
      log.debug("Scan classpath: [{}]", classPath);
      // 填充 classes
      fillClasses(classPath, packageName, classFilter, classes);
    }
   
    //如果在项目的ClassPath中未找到,去系统定义的ClassPath里找
    if(classes.isEmpty()) {
      for (String classPath : getJavaClassPaths()) {
        log.debug("Scan java classpath: [{}]", classPath);
        // 填充 classes
        fillClasses(new File(classPath), packageName, classFilter, classes);
      }
    }
    return classes;
  }

  /**
   * 获得指定类中的Public方法名<br>
   * 去重重载的方法
   * @param clazz 类
   */
  public final static Set<String> getMethods(Class<?> clazz) {
    HashSet<String> methodSet = new HashSet<String>();
    Method[] methodArray = clazz.getMethods();
    for (Method method : methodArray) {
      String methodName = method.getName();
      methodSet.add(methodName);
    }
    return methodSet;
  }
 
  /**
   * 获得ClassPath
   * @return ClassPath集合
   */
  public static Set<String> getClassPathResources(){
    return getClassPaths(StrUtil.EMPTY);
  }
 
  /**
   * 获得ClassPath
   * @param packageName 包名称
   * @return ClassPath路径字符串集合
   */
  public static Set<String> getClassPaths(String packageName){
    String packagePath = packageName.replace(StrUtil.DOT, StrUtil.SLASH);
    Enumeration<URL> resources;
    try {
      resources = getClassLoader().getResources(packagePath);
    } catch (IOException e) {
      throw new UtilException(StrUtil.format("Loading classPath [{}] error!", packagePath), e);
    }
    Set<String> paths = new HashSet<String>();
    while(resources.hasMoreElements()) {
      paths.add(resources.nextElement().getPath());
    }
    return paths;
  }
 
  /**
   * @return 获得Java ClassPath路径,不包括 jre
   */
  public static String[] getJavaClassPaths() {
    String[] classPaths = System.getProperty("java.class.path").split(System.getProperty("path.separator"));
    return classPaths;
  }
 
  /**
   * 强制转换类型
   * @param clazz 被转换成的类型
   * @param value 需要转换的对象
   * @return 转换后的对象
   */
  public static Object parse(Class<?> clazz, Object value) {
    try {
      return clazz.cast(value);
    } catch (ClassCastException e) {
      String valueStr = String.valueOf(value);
     
      Object result = parseBasic(clazz, valueStr);
      if(result != null) {
        return result;
      }
     
      if(Date.class.isAssignableFrom(clazz)) {
        //判断标准日期
        return DateUtil.parse(valueStr);
      } else if(clazz == BigDecimal.class) {
        //数学计算数字
        return new BigDecimal(valueStr);
      }else if(clazz == byte[].class) {
        //流,由于有字符编码问题,在此使用系统默认
        return valueStr.getBytes();
      }
     
      //未找到可转换的类型,返回原值
      return value;
    }
  }
 
  /**
   * 转换基本类型
   * @param clazz 转换到的类
   * @param valueStr 被转换的字符串
   * @return 转换后的对象,如果非基本类型,返回null
   */
  public static Object parseBasic(Class<?> clazz, String valueStr) {
    switch (BASIC_TYPE.valueOf(clazz.getSimpleName().toUpperCase())) {
      case STRING:
        return valueStr;
      case BYTE:
        if(clazz == byte.class) {
          return Byte.parseByte(valueStr);
        }
        return Byte.valueOf(valueStr);
      case SHORT:
        if(clazz == short.class) {
          return Short.parseShort(valueStr);
        }
        return Short.valueOf(valueStr);
      case INT:
        return Integer.parseInt(valueStr);
      case INTEGER:
        return Integer.valueOf(valueStr);
      case LONG:
        if(clazz == long.class) {
          return Long.parseLong(valueStr);
        }
        return Long.valueOf(valueStr);
      case DOUBLE:
        if(clazz == double.class) {
          return Double.parseDouble(valueStr);
        }
      case FLOAT:
        if(clazz == float.class) {
          return Float.parseFloat(valueStr);
        }
        return Float.valueOf(valueStr);
      case BOOLEAN:
        if(clazz == boolean.class) {
          return Boolean.parseBoolean(valueStr);
        }
        return Boolean.valueOf(valueStr);
      case CHAR:
        return valueStr.charAt(0);
      case CHARACTER:
        return Character.valueOf(valueStr.charAt(0));
      default:
        return null;
    }
  }
 
  /**
   * 转换基本类型
   * @param clazz 被转换为基本类型的类,必须为包装类型
   * @return 基本类型类
   */
  public static Class<?> castToPrimitive(Class<?> clazz) {
    if(null == clazz || clazz.isPrimitive()) {
      return clazz;
    }
   
    BASIC_TYPE basicType;
    try {
      basicType = BASIC_TYPE.valueOf(clazz.getSimpleName().toUpperCase());
    }catch(Exception e) {
      return clazz;
    }
    //基本类型
    switch (basicType) {
      case BYTE:
        return byte.class;
      case SHORT:
        return short.class;
      case INT:
        return int.class;
      case LONG:
        return long.class;
      case DOUBLE:
        return double.class;
      case FLOAT:
        return float.class;
      case BOOLEAN:
        return boolean.class;
      case CHAR:
        return char.class;
      default:
        return clazz;
    }
  }
 
  /**
   * @return 当前线程的class loader
   */
  public static ClassLoader getContextClassLoader() {
    return Thread.currentThread().getContextClassLoader();
  }
 
  /**
   * 获得class loader<br>
   * 若当前线程class loader不存在,取当前类的class loader
   * @return 类加载器
   */
  public static ClassLoader getClassLoader() {
    ClassLoader classLoader = getContextClassLoader();
    if(classLoader == null) {
      classLoader = ClassUtil.class.getClassLoader();
    }
    return classLoader;
  }

  /**
   * 实例化对象
   * @param clazz 类名
   * @return 对象
   */
  @SuppressWarnings("unchecked")
  public static <T> T newInstance(String clazz) {
    try {
      return (T) Class.forName(clazz).newInstance();
    } catch (Exception e) {
      throw new UtilException(StrUtil.format("Instance class [{}] error!", clazz), e);
    }
  }
 
  /**
   * 实例化对象
   * @param clazz 类
   * @return 对象
   */
  @SuppressWarnings("unchecked")
  public static <T> T newInstance(Class<?> clazz) {
    try {
      return (T) clazz.newInstance();
    } catch (Exception e) {
      throw new UtilException(StrUtil.format("Instance class [{}] error!", clazz), e);
    }
  }

  /**
   * 克隆对象
   * @param obj 被克隆对象
   * @return 克隆后的对象
   * @throws IOException
   * @throws ClassNotFoundException
   */
  @SuppressWarnings("unchecked")
  public static <T extends Serializable> T cloneObj(T obj) {
    final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
   
    try {
      final ObjectOutputStream out = new ObjectOutputStream(byteOut);
      out.writeObject(obj);
      final ObjectInputStream in =new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
      return (T) in.readObject();
    } catch (Exception e) {
      throw new UtilException(e);
    }
  }
 
  /**
   * 加载类
   * @param className 类名
   * @param isInitialized 是否初始化
   * @return
   */
  public static Class<?> loadClass(String className, boolean isInitialized) {
    Class<?> clazz;
    try {
      clazz = Class.forName(className, isInitialized, getClassLoader());
    }catch (ClassNotFoundException e) {
      throw new UtilException(e);
    }
    return clazz;
  }
 
  /**
   * 加载类并初始化
   * @param className 类名
   * @return
   */
  public static Class<?> loadClass(String className) {
    return loadClass(className, true);
  }
 
  //--------------------------------------------------------------------------------------------------- Private method start
  /**
   * 文件过滤器,过滤掉不需要的文件<br>
   * 只保留Class文件、目录和Jar
   */
  private static FileFilter fileFilter = new FileFilter(){
    @Override
    public boolean accept(File pathname) {
      return isClass(pathname.getName()) || pathname.isDirectory() || isJarFile(pathname);
    }
  };

  /**
   * 改变 com -> com. 避免在比较的时候把比如 completeTestSuite.class类扫描进去,如果没有"."</br>
   * 那class里面com开头的class类也会被扫描进去,其实名称后面或前面需要一个 ".",来添加包的特征
   *
   * @param packageName
   * @return 格式化后的包名
   */
  private static String getWellFormedPackageName(String packageName) {
    return packageName.lastIndexOf(StrUtil.DOT) != packageName.length() - 1 ? packageName + StrUtil.DOT : packageName;
  }

  /**
   * 填充满足条件的class 填充到 classes<br>
   * 同时会判断给定的路径是否为Jar包内的路径,如果是,则扫描此Jar包
   *
   * @param path Class文件路径或者所在目录Jar包路径
   * @param packageName 需要扫面的包名
   * @param classFilter class过滤器
   * @param classes List 集合
   */
  private static void fillClasses(String path, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
    //判定给定的路径是否为Jar
    int index = path.lastIndexOf(FileUtil.JAR_PATH_EXT);
    if(index != -1) {
      //Jar文件
      path = path.substring(0, index + FileUtil.JAR_FILE_EXT.length())//截取jar路径
      path = StrUtil.removePrefix(path, FileUtil.PATH_FILE_PRE)//去掉文件前缀
      processJarFile(new File(path), packageName, classFilter, classes);
    }else {
      fillClasses(new File(path), packageName, classFilter, classes);
    }
  }
 
  /**
   * 填充满足条件的class 填充到 classes
   *
   * @param file Class文件或者所在目录Jar包文件
   * @param packageName 需要扫面的包名
   * @param classFilter class过滤器
   * @param classes List 集合
   */
  private static void fillClasses(File file, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
    if (file.isDirectory()) {
      processDirectory(file, packageName, classFilter, classes);
    } else if (isClassFile(file)) {
      processClassFile(file, packageName, classFilter, classes);
    } else if (isJarFile(file)) {
      processJarFile(file, packageName, classFilter, classes);
    }
  }

  /**
   * 处理如果为目录的情况,需要递归调用 fillClasses方法
   *
   * @param directory 目录
   * @param packageName 包名
   * @param classFilter 类过滤器
   * @param classes 类集合
   */
  private static void processDirectory(File directory, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
    for (File file : directory.listFiles(fileFilter)) {
      fillClasses(file, packageName, classFilter, classes);
    }
  }

  /**
   * 处理为class文件的情况,填充满足条件的class 到 classes
   *
   * @param file class文件
   * @param packageName 包名
   * @param classFilter 类过滤器
   * @param classes 类集合
   */
  private static void processClassFile(File file, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
    final String filePathWithDot = file.getAbsolutePath().replace(File.separator, StrUtil.DOT);
    int subIndex = -1;
    if ((subIndex = filePathWithDot.indexOf(packageName)) != -1) {
      final String className = filePathWithDot.substring(subIndex).replace(FileUtil.CLASS_EXT, StrUtil.EMPTY);
      fillClass(className, packageName, classes, classFilter);
    }
  }

  /**
   * 处理为jar文件的情况,填充满足条件的class 到 classes
   *
   * @param file jar文件
   * @param packageName 包名
   * @param classFilter 类过滤器
   * @param classes 类集合
   */
  private static void processJarFile(File file, String packageName, ClassFilter classFilter, Set<Class<?>> classes) {
    try {
      for (JarEntry entry : Collections.list(new JarFile(file).entries())) {
        if (isClass(entry.getName())) {
          final String className = entry.getName().replace(StrUtil.SLASH, StrUtil.DOT).replace(FileUtil.CLASS_EXT, StrUtil.EMPTY);
          fillClass(className, packageName, classes, classFilter);
        }
      }
    } catch (Throwable ex) {
      log.error(ex.getMessage(), ex);
    }
  }

  /**
   * 填充class 到 classes
   *
   * @param className 类名
   * @param packageName 包名
   * @param classes 类集合
   * @param classFilter 类过滤器
   */
  private static void fillClass(String className, String packageName, Set<Class<?>> classes, ClassFilter classFilter) {
    if (className.startsWith(packageName)) {
      try {
        final Class<?> clazz = Class.forName(className, false, getClassLoader());
        if (classFilter == null || classFilter.accept(clazz)) {
          classes.add(clazz);
        }
      } catch (Throwable ex) {
        Log.error(log, ex, "Load class [{}] error!", className);
      }
    }
  }

  /**
   * @param file 文件
   * @return 是否为类文件
   */
  private static boolean isClassFile(File file) {
    return isClass(file.getName());
  }
 
  /**
   * @param fileName 文件名
   * @return 是否为类文件
   */
  private static boolean isClass(String fileName) {
    return fileName.endsWith(FileUtil.CLASS_EXT);
  }

  /**
   * @param file 文件
   * @return是否为Jar文件
   */
  private static boolean isJarFile(File file) {
    return file.getName().endsWith(FileUtil.JAR_FILE_EXT);
  }
  //--------------------------------------------------------------------------------------------------- Private method end
 
  /**
   * 类过滤器,用于过滤不需要加载的类<br>
   */
  public interface ClassFilter {
    boolean accept(Class<?> clazz);
  }
}
TOP

Related Classes of com.xiaoleilu.hutool.ClassUtil$ClassFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.