Package org.jtester.bytecode.reflector.helper

Source Code of org.jtester.bytecode.reflector.helper.ClazzHelper

package org.jtester.bytecode.reflector.helper;

import static ext.jtester.org.apache.commons.io.IOUtils.closeQuietly;
import static java.lang.reflect.Modifier.isStatic;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import mockit.Mockit;

import org.jtester.exception.JTesterException;
import org.jtester.module.core.helper.SpringModuleHelper;

import ext.jtester.objenesis.ObjenesisHelper;
import ext.jtester.org.apache.commons.io.IOUtils;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class ClazzHelper {
  private static final Map<String, Boolean> clazAvailableCache = new HashMap<String, Boolean>();

  /**
   * Utility method that verifies whether the class with the given fully
   * qualified classname is available in the classpath.
   *
   * @param className
   *            The name of the class
   * @return True if the class with the given name is available
   */
  public static boolean isClassAvailable(String className) {
    Boolean isAvailable = clazAvailableCache.get(className);
    if (isAvailable != null) {
      return isAvailable;
    }
    try {
      Thread.currentThread().getContextClassLoader().loadClass(className);
      clazAvailableCache.put(className, true);
      return true;
    } catch (ClassNotFoundException e) {
      clazAvailableCache.put(className, false);
      return false;
    }
  }

  /**
   * Gets the class for the given name. An JTesterException is thrown when the
   * class could not be loaded.
   *
   * @param className
   *            The name of the class, not null
   * @return The class, not null
   */
  public static <T> Class<T> getClazz(String className) {
    try {
      return (Class<T>) Class.forName(className);
    } catch (Throwable t) {
      throw new JTesterException("Could not load class with name " + className, t);
    }
  }

  /**
   * @param className
   *            The name of the class to check, not null
   * @return True if the classfile exists in the classpath
   */
  public static boolean classFileExistsInClasspath(String className) {
    String classFileName = className.replace('.', '/') + ".class";
    return ClazzHelper.class.getClassLoader().getResource(classFileName) != null;
  }

  /**
   * 类路径中是否有 org.hibernate.tool.hbm2ddl.SchemaExport class
   *
   * @return
   */
  public final static boolean doesImportSchemaExport() {
    try {
      Class.forName("org.hibernate.tool.hbm2ddl.SchemaExport");
      return true;
    } catch (ClassNotFoundException e) {
      return false;
    }
  }

  public final static String getPackFromClassName(String clazzName) {
    int index = clazzName.lastIndexOf(".");
    String pack = "";
    if (index > 0) {
      pack = clazzName.substring(0, index);
    }
    return pack;
  }

  /**
   * 根据类名获得package的路径<br>
   * a.b.c.ImplClazz 返回 a/b/c
   *
   * @param clazzName
   * @return
   */
  public final static String getPathFromPath(String clazzName) {
    String pack = getPackFromClassName(clazzName);
    return pack.replace(".", "/");
  }

  /**
   * 根据类名获得package的路径<br>
   * a.b.c.ImplClazz 返回 "a/b/c"<br>
   * if clazz==null, 返回 ""
   *
   * @param clazzName
   * @return
   */
  public final static String getPathFromPath(Class clazz) {
    if (clazz == null) {
      return "";
    } else {
      return getPathFromPath(clazz.getName());
    }
  }

  public final static void generateClazz(String clazzName, byte[] r) throws IOException {
    // debug,调试生成的字节码
    FileOutputStream file = new FileOutputStream("d:/" + clazzName.substring(clazzName.lastIndexOf('.') + 1)
        + ".class");
    file.write(r);
    file.flush();
    file.close();
  }

  /**
   * package名称有效字符表达式
   */
  public final static String VALID_PACK_REGULAR = "[^\\.]*";

  /**
   * 将带有星号的package名称转换为正则表达式
   *
   * @param regexPackage
   *            带有星号的package名称,比如 com.**.service.*Impl
   * @return
   */
  public static String getPackageRegex(String regexPackage) {
    String _interfaceKey = regexPackage.replace('*', '#');// 先把*替换成不会被使用的字符#,避免后面的正则表达式替换错误
    String regex = _interfaceKey.replace(".", "\\.");
    regex = regex.replace("\\.##\\.", "(\\.|\\..*\\.)");
    regex = regex.replace("##\\.", ".*\\.");
    regex = regex.replace("#", VALID_PACK_REGULAR);
    return regex;
  }

  /**
   * 判断类型是否是接口或者抽象类
   *
   * @param type
   * @return
   */
  public static boolean isInterfaceOrAbstract(Class type) {
    if (type == null) {
      throw new RuntimeException("type can't be null.");
    }
    if (type.isInterface()) {
      return true;
    } else if (Modifier.isAbstract(type.getModifiers())) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * 从void setBeanName(Type instance)方法中解析出beanName
   *
   * @param method
   * @return
   */
  public static String exactBeanName(Method method) {
    String methodname = method.getName();
    if (methodname.equalsIgnoreCase("set") || methodname.startsWith("set") == false) {
      return null;
    }
    String beanName = methodname.substring(3);
    beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
    return beanName;
  }

  /**
   * 创建className的实例<br>
   * Creates an instance of the class with the given name. The class's no
   * argument constructor is used to create an instance.
   *
   * @param className
   *            The name of the class, not null
   *
   * @return An instance of this class
   * @throws JTesterException
   *             if the class could not be found or no instance could be
   *             created
   */
  public static <T> T createInstanceOfType(String className) {
    try {
      Class type = Class.forName(className);
      return (T) newInstance(type);
    } catch (ClassCastException e) {
      throw new JTesterException("Class " + className + " is not of expected type.", e);
    } catch (NoClassDefFoundError e) {
      throw new JTesterException("Unable to load class " + className, e);
    } catch (ClassNotFoundException e) {
      throw new JTesterException("Class " + className + " not found", e);
    } catch (JTesterException e) {
      throw e;
    } catch (Throwable e) {
      throw new JTesterException("Error while instantiating class " + className, e);
    }
  }

  /**
   * Checks whether the given fromType is assignable to the given toType, also
   * taking into account possible auto-boxing.<br>
   * Check if the right-hand side type may be assigned to the left-hand side
   * type following the Java generics rules.
   *
   * @param fromType
   *            The from type, not null
   * @param toType
   *            The to type, not null
   * @return True if assignable
   */
  public static boolean isAssignable(Type fromType, Type toType) {
    if (fromType instanceof Class && toType instanceof Class) {
      Class fromClass = (Class) fromType;
      Class toClass = (Class) toType;

      // handle auto boxing types
      if (boolean.class.equals(fromClass) && Boolean.class.isAssignableFrom(toClass)
          || boolean.class.equals(toClass) && Boolean.class.isAssignableFrom(fromClass)) {
        return true;
      }
      if (char.class.equals(fromClass) && Character.class.isAssignableFrom(toClass) || char.class.equals(toClass)
          && Character.class.isAssignableFrom(fromClass)) {
        return true;
      }
      if (int.class.equals(fromClass) && Integer.class.isAssignableFrom(toClass) || int.class.equals(toClass)
          && Integer.class.isAssignableFrom(fromClass)) {
        return true;
      }
      if (long.class.equals(fromClass) && Long.class.isAssignableFrom(toClass) || long.class.equals(toClass)
          && Long.class.isAssignableFrom(fromClass)) {
        return true;
      }
      if (float.class.equals(fromClass) && Float.class.isAssignableFrom(toClass) || float.class.equals(toClass)
          && Float.class.isAssignableFrom(fromClass)) {
        return true;
      }
      if (double.class.equals(fromClass) && Double.class.isAssignableFrom(toClass)
          || double.class.equals(toClass) && Double.class.isAssignableFrom(fromClass)) {
        return true;
      }
      return toClass.isAssignableFrom(fromClass);
    } else {
      if (toType.equals(fromType)) {
        return true;
      }
      if (toType instanceof Class && fromType instanceof Class) {
        return ((Class) toType).isAssignableFrom((Class) fromType);
      }
      if (toType instanceof ParameterizedType && fromType instanceof ParameterizedType) {
        return isAssignable((ParameterizedType) toType, (ParameterizedType) fromType);
      }
      if (toType instanceof WildcardType) {
        return isAssignable((WildcardType) toType, fromType);
      }
      return false;
    }
  }

  private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType) {
    if (lhsType.equals(rhsType)) {
      return true;
    }
    Type[] lhsTypeArguments = lhsType.getActualTypeArguments();
    Type[] rhsTypeArguments = rhsType.getActualTypeArguments();
    if (lhsTypeArguments.length != rhsTypeArguments.length) {
      return false;
    }
    for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) {
      Type lhsArg = lhsTypeArguments[i];
      Type rhsArg = rhsTypeArguments[i];
      if (!lhsArg.equals(rhsArg)
          && !(lhsArg instanceof WildcardType && isAssignable((WildcardType) lhsArg, rhsArg))) {
        return false;
      }
    }
    return true;
  }

  private static boolean isAssignable(WildcardType lhsType, Type rhsType) {
    Type[] upperBounds = lhsType.getUpperBounds();
    Type[] lowerBounds = lhsType.getLowerBounds();
    for (int size = upperBounds.length, i = 0; i < size; ++i) {
      if (!isAssignable(upperBounds[i], rhsType)) {
        return false;
      }
    }
    for (int size = lowerBounds.length, i = 0; i < size; ++i) {
      if (!isAssignable(rhsType, lowerBounds[i])) {
        return false;
      }
    }
    return true;
  }

  /**
   * 根据字符串获取枚举值<br>
   * Gets the enum value that has the given name.
   *
   * @param enumClass
   *            The enum class, not null
   * @param enumValueName
   *            The name of the enum value, not null
   * @return The actual enum value, not null
   * @throws JTesterException
   *             if no value could be found with the given name
   */
  public static <T extends Enum<?>> T getEnumValue(Class<T> enumClass, String enumValueName) {
    T[] enumValues = enumClass.getEnumConstants();
    for (T enumValue : enumValues) {
      if (enumValueName.equalsIgnoreCase(enumValue.name())) {

        return enumValue;
      }
    }
    throw new JTesterException("Unable to find a enum value in enum: " + enumClass + ", with value name: "
        + enumValueName);
  }

  /**
   * 获得泛型字段的参数类类型<br>
   * Gets the T from a Class<T> field declaration. An exception is raised if
   * the field type is not generic or has more than 1 generic type
   *
   * @param field
   *            The field to get the type from, not null
   * @return The declared generic type
   */
  public static Type getGenericType(Field field) {
    Type type = field.getGenericType();
    if (type instanceof ParameterizedType) {
      Type[] argumentTypes = ((ParameterizedType) type).getActualTypeArguments();
      if (argumentTypes.length == 1) {
        return argumentTypes[0];
      }
      throw new JTesterException("Unable to determine unique generic type for field: " + field
          + ". The field type declares more than one generic type: " + type);
    }
    throw new JTesterException("Unable to determine unique generic type for field: " + field
        + ". Field type is not a generic type: " + type);
  }

  /**
   * Gets the class instance for the given type instance.
   *
   * @param type
   *            The type to get a class instance for, not null
   * @return The class instance, not null
   */
  public static <T> Class<T> getClassForType(Type type) {
    if (type instanceof Class) {
      return (Class<T>) type;
    }
    if (type instanceof ParameterizedType) {
      return (Class<T>) ((ParameterizedType) type).getRawType();
    }
    throw new JTesterException("Unable to convert Type instance " + type + " to a Class instance.");
  }

  /**
   * 读取class的字节码内容byte[]
   *
   * @param clazz
   * @return
   */
  public static byte[] getBytes(Class clazz) {
    String name = clazz.getName().replace('.', '/') + ".class";
    InputStream iStream = clazz.getClassLoader().getResourceAsStream(name);
    try {
      ByteArrayOutputStream oStream = new ByteArrayOutputStream();

      IOUtils.copy(iStream, oStream);
      return oStream.toByteArray();
    } catch (IOException e) {
      throw new RuntimeException(e);
    } finally {
      closeQuietly(iStream);
    }
  }

  /**
   * 创建claz对象实例<br>
   * 不是通过 new Construction()形式
   *
   * @param <T>
   * @param claz
   * @return
   */
  public static <T> T newInstance(Class<T> claz) {

    if (claz.isMemberClass() && !isStatic(claz.getModifiers())) {
      throw new JTesterException(
          "Creation of an instance of a non-static innerclass is not possible using reflection. The type "
              + claz.getSimpleName()
              + " is only known in the context of an instance of the enclosing class "
              + claz.getEnclosingClass().getSimpleName()
              + ". Declare the innerclass as static to make construction possible.");
    }

    if (claz.isInterface()) {
      return Mockit.newEmptyProxy(claz);
    }
    int modifiers = claz.getModifiers();
    if (Modifier.isAbstract(modifiers)) {
      throw new RuntimeException("unsupport abstract class!");
    }

    try {
      Constructor constructor = claz.getDeclaredConstructor();
      if (constructor != null) {
        boolean isAccessor = constructor.isAccessible();
        constructor.setAccessible(true);
        Object o = constructor.newInstance();
        constructor.setAccessible(isAccessor);
        return (T) o;
      }
    } catch (Throwable e) {
      return (T) ObjenesisHelper.newInstance(claz);
    }
    return (T) ObjenesisHelper.newInstance(claz);
  }

  /**
   * 返回可以class中定义的字段(包含父类定义的)<br>
   *
   * @param clazz
   * @param filters
   *            需要过滤掉的字段
   * @param includeStatic
   *            是否包含static修饰的字段
   * @param includeFinal
   *            是否包含final修饰的字段
   * @param includeTransient
   *            是否包含transient修饰的字段
   * @return
   */
  public static final List<Field> getAllFields(Class clazz, Collection<String> filters, boolean includeStatic,
      boolean includeFinal, boolean includeTransient) {
    List<Field> jsonFields = new ArrayList<Field>();

    List<Field> fields = FieldHelper.getAllFields(clazz);
    for (Field field : fields) {
      String fieldname = field.getName();
      if (filters != null && filters.contains(fieldname)) {
        continue;
      }
      int modifier = field.getModifiers();
      if (!includeStatic && Modifier.isStatic(modifier)) {
        continue;
      }
      if (!includeFinal && Modifier.isFinal(modifier)) {
        continue;
      }
      if (!includeTransient && Modifier.isTransient(modifier)) {
        continue;
      }
      if (jsonFields.contains(field)) {
        continue;
      }
      jsonFields.add(field);
    }
    return jsonFields;
  }

  // private final static String Anonymous_Type_Pattern = ".*\\$\\d+.*";
  private final static String Proxy_Type_Pattern = ".*\\$[Pp]roxy\\d+.*";

  /**
   * 返回非代理类的类型
   *
   * @param type
   * @return
   */
  public static Class getUnProxyType(Class clazz) {
    if (Proxy.isProxyClass(clazz)) {
      return Object.class;
    }
    Class type = clazz;
    while (type.isAnonymousClass() || type.getName().matches(Proxy_Type_Pattern)) {
      type = type.getSuperclass();
    }

    return type;
  }

  /**
   * 如果是spring代理对象,获得被代理的目标对象
   *
   * @param target
   * @return
   */
  public static Object getProxiedObject(Object target) {
    if (ClazzHelper.isClassAvailable("org.springframework.aop.framework.Advised")) {
      Object o = SpringModuleHelper.getAdvisedObject(target);
      return o;
    } else {
      return target;
    }
  }
}
TOP

Related Classes of org.jtester.bytecode.reflector.helper.ClazzHelper

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.