首页

基于spring-beans实现工具类BeanUtils基于Class实例化注入对象及查找方法、复制属性等操作

标签:springframework,beans工具类,instantiateClass,findMethod,copyProperties     发布时间:2017-12-12   

一、前言

基于spring-beans(4.1.4)的工具类org.springframework.beans.BeanUtils对注入spring对象按照Class实例化instantiateClass、class对象方法名称methodName查找findMethod、属性查找对于class类信息findPropertyType、对象属性复制copyProperties等常用操作,具体如下源码所示。

二、源码说明

package org.springframework.beans;@b@@b@import java.beans.PropertyDescriptor;@b@import java.beans.PropertyEditor;@b@import java.lang.reflect.Constructor;@b@import java.lang.reflect.InvocationTargetException;@b@import java.lang.reflect.Method;@b@import java.lang.reflect.Modifier;@b@import java.net.URI;@b@import java.net.URL;@b@import java.util.Arrays;@b@import java.util.Collections;@b@import java.util.Date;@b@import java.util.List;@b@import java.util.Locale;@b@import java.util.Set;@b@import org.apache.commons.logging.Log;@b@import org.apache.commons.logging.LogFactory;@b@import org.springframework.core.MethodParameter;@b@import org.springframework.util.Assert;@b@import org.springframework.util.ClassUtils;@b@import org.springframework.util.ConcurrentReferenceHashMap;@b@import org.springframework.util.ReflectionUtils;@b@import org.springframework.util.StringUtils;@b@@b@public abstract class BeanUtils@b@{@b@  private static final Log logger = LogFactory.getLog(BeanUtils.class);@b@  private static final Set<Class<?>> unknownEditorTypes = Collections.newSetFromMap(new ConcurrentReferenceHashMap(64));@b@@b@  public static <T> T instantiate(Class<T> clazz)@b@    throws BeanInstantiationException@b@  {@b@    Assert.notNull(clazz, "Class must not be null");@b@    if (clazz.isInterface())@b@      throw new BeanInstantiationException(clazz, "Specified class is an interface");@b@    try@b@    {@b@      return clazz.newInstance();@b@    }@b@    catch (InstantiationException ex) {@b@      throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex);@b@    }@b@    catch (IllegalAccessException ex) {@b@      throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex);@b@    }@b@  }@b@@b@  public static <T> T instantiateClass(Class<T> clazz)@b@    throws BeanInstantiationException@b@  {@b@    Assert.notNull(clazz, "Class must not be null");@b@    if (clazz.isInterface())@b@      throw new BeanInstantiationException(clazz, "Specified class is an interface");@b@    try@b@    {@b@      return instantiateClass(clazz.getDeclaredConstructor(new Class[0]), new Object[0]);@b@    }@b@    catch (NoSuchMethodException ex) {@b@      throw new BeanInstantiationException(clazz, "No default constructor found", ex);@b@    }@b@  }@b@@b@  public static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo)@b@    throws BeanInstantiationException@b@  {@b@    Assert.isAssignable(assignableTo, clazz);@b@    return instantiateClass(clazz);@b@  }@b@@b@  public static <T> T instantiateClass(Constructor<T> ctor, Object[] args)@b@    throws BeanInstantiationException@b@  {@b@    Assert.notNull(ctor, "Constructor must not be null");@b@    try {@b@      ReflectionUtils.makeAccessible(ctor);@b@      return ctor.newInstance(args);@b@    }@b@    catch (InstantiationException ex) {@b@      throw new BeanInstantiationException(ctor.getDeclaringClass(), "Is it an abstract class?", ex);@b@    }@b@    catch (IllegalAccessException ex)@b@    {@b@      throw new BeanInstantiationException(ctor.getDeclaringClass(), "Is the constructor accessible?", ex);@b@    }@b@    catch (IllegalArgumentException ex)@b@    {@b@      throw new BeanInstantiationException(ctor.getDeclaringClass(), "Illegal arguments for constructor", ex);@b@    }@b@    catch (InvocationTargetException ex)@b@    {@b@      throw new BeanInstantiationException(ctor.getDeclaringClass(), "Constructor threw exception", ex@b@        .getTargetException());@b@    }@b@  }@b@@b@  public static Method findMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes)@b@  {@b@    try@b@    {@b@      return clazz.getMethod(methodName, paramTypes);@b@    } catch (NoSuchMethodException ex) {@b@    }@b@    return findDeclaredMethod(clazz, methodName, paramTypes);@b@  }@b@@b@  public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes)@b@  {@b@    try@b@    {@b@      return clazz.getDeclaredMethod(methodName, paramTypes);@b@    }@b@    catch (NoSuchMethodException ex) {@b@      if (clazz.getSuperclass() != null)@b@        return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes);@b@    }@b@    return null;@b@  }@b@@b@  public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)@b@    throws IllegalArgumentException@b@  {@b@    Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);@b@    if (targetMethod == null)@b@      targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);@b@@b@    return targetMethod;@b@  }@b@@b@  public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)@b@    throws IllegalArgumentException@b@  {@b@    Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);@b@    if ((targetMethod == null) && (clazz.getSuperclass() != null))@b@      targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);@b@@b@    return targetMethod;@b@  }@b@@b@  public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)@b@    throws IllegalArgumentException@b@  {@b@    Method targetMethod = null;@b@    int numMethodsFoundWithCurrentMinimumArgs = 0;@b@    Method[] arrayOfMethod = methods; int i = arrayOfMethod.length; for (int j = 0; j < i; ++j) { Method method = arrayOfMethod[j];@b@      if (method.getName().equals(methodName)) {@b@        int numParams = method.getParameterTypes().length;@b@        if ((targetMethod == null) || (numParams < targetMethod.getParameterTypes().length)) {@b@          targetMethod = method;@b@          numMethodsFoundWithCurrentMinimumArgs = 1;@b@        }@b@        else if (targetMethod.getParameterTypes().length == numParams)@b@        {@b@          ++numMethodsFoundWithCurrentMinimumArgs;@b@        }@b@      }@b@    }@b@@b@    if (numMethodsFoundWithCurrentMinimumArgs > 1) {@b@      throw new IllegalArgumentException("Cannot resolve method '" + methodName + "' to a unique method. Attempted to resolve to overloaded method with " + "the least number of parameters, but there were " + numMethodsFoundWithCurrentMinimumArgs + " candidates.");@b@    }@b@@b@    return targetMethod;@b@  }@b@@b@  public static Method resolveSignature(String signature, Class<?> clazz)@b@  {@b@    Assert.hasText(signature, "'signature' must not be empty");@b@    Assert.notNull(clazz, "Class must not be null");@b@    int firstParen = signature.indexOf("(");@b@    int lastParen = signature.indexOf(")");@b@    if ((firstParen > -1) && (lastParen == -1)) {@b@      throw new IllegalArgumentException("Invalid method signature '" + signature + "': expected closing ')' for args list");@b@    }@b@@b@    if ((lastParen > -1) && (firstParen == -1)) {@b@      throw new IllegalArgumentException("Invalid method signature '" + signature + "': expected opening '(' for args list");@b@    }@b@@b@    if ((firstParen == -1) && (lastParen == -1)) {@b@      return findMethodWithMinimalParameters(clazz, signature);@b@    }@b@@b@    String methodName = signature.substring(0, firstParen);@b@@b@    String[] parameterTypeNames = StringUtils.commaDelimitedListToStringArray(signature@b@      .substring(firstParen + 1, lastParen));@b@@b@    Class[] parameterTypes = new Class[parameterTypeNames.length];@b@    for (int i = 0; i < parameterTypeNames.length; ++i) {@b@      String parameterTypeName = parameterTypeNames[i].trim();@b@      try {@b@        parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());@b@      }@b@      catch (Throwable ex) {@b@        throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" + parameterTypeName + "] for argument " + i + ". Root cause: " + ex);@b@      }@b@    }@b@@b@    return findMethod(clazz, methodName, parameterTypes);@b@  }@b@@b@  public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz)@b@    throws BeansException@b@  {@b@    CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);@b@    return cr.getPropertyDescriptors();@b@  }@b@@b@  public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName)@b@    throws BeansException@b@  {@b@    CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);@b@    return cr.getPropertyDescriptor(propertyName);@b@  }@b@@b@  public static PropertyDescriptor findPropertyForMethod(Method method)@b@    throws BeansException@b@  {@b@    return findPropertyForMethod(method, method.getDeclaringClass());@b@  }@b@@b@  public static PropertyDescriptor findPropertyForMethod(Method method, Class<?> clazz)@b@    throws BeansException@b@  {@b@    Assert.notNull(method, "Method must not be null");@b@    PropertyDescriptor[] pds = getPropertyDescriptors(clazz);@b@    PropertyDescriptor[] arrayOfPropertyDescriptor1 = pds; int i = arrayOfPropertyDescriptor1.length; for (int j = 0; j < i; ++j) { PropertyDescriptor pd = arrayOfPropertyDescriptor1[j];@b@      if ((method.equals(pd.getReadMethod())) || (method.equals(pd.getWriteMethod())))@b@        return pd;@b@    }@b@@b@    return null;@b@  }@b@@b@  public static PropertyEditor findEditorByConvention(Class<?> targetType)@b@  {@b@    if ((targetType == null) || (targetType.isArray()) || (unknownEditorTypes.contains(targetType)))@b@      return null;@b@@b@    ClassLoader cl = targetType.getClassLoader();@b@    if (cl == null)@b@      try {@b@        cl = ClassLoader.getSystemClassLoader();@b@        if (cl == null)@b@          return null;@b@@b@      }@b@      catch (Throwable ex)@b@      {@b@        if (logger.isDebugEnabled())@b@          logger.debug("Could not access system ClassLoader: " + ex);@b@@b@        return null;@b@      }@b@@b@    String editorName = targetType.getName() + "Editor";@b@    try {@b@      Class editorClass = cl.loadClass(editorName);@b@      if (!(PropertyEditor.class.isAssignableFrom(editorClass))) {@b@        if (logger.isWarnEnabled()) {@b@          logger.warn("Editor class [" + editorName + "] does not implement [java.beans.PropertyEditor] interface");@b@        }@b@@b@        unknownEditorTypes.add(targetType);@b@        return null;@b@      }@b@      return ((PropertyEditor)instantiateClass(editorClass));@b@    }@b@    catch (ClassNotFoundException ex) {@b@      if (logger.isDebugEnabled())@b@        logger.debug("No property editor [" + editorName + "] found for type " + targetType@b@          .getName() + " according to 'Editor' suffix convention");@b@@b@      unknownEditorTypes.add(targetType); }@b@    return null;@b@  }@b@@b@  public static Class<?> findPropertyType(String propertyName, Class<?>[] beanClasses)@b@  {@b@    Class[] arrayOfClass;@b@    int j;@b@    if (beanClasses != null) {@b@      arrayOfClass = beanClasses; int i = arrayOfClass.length; for (j = 0; j < i; ++j) { Class beanClass = arrayOfClass[j];@b@        PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName);@b@        if (pd != null)@b@          return pd.getPropertyType();@b@      }@b@    }@b@@b@    return Object.class;@b@  }@b@@b@  public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd)@b@  {@b@    if (pd instanceof GenericTypeAwarePropertyDescriptor) {@b@      return new MethodParameter(((GenericTypeAwarePropertyDescriptor)pd).getWriteMethodParameter());@b@    }@b@@b@    return new MethodParameter(pd.getWriteMethod(), 0);@b@  }@b@@b@  public static boolean isSimpleProperty(Class<?> clazz)@b@  {@b@    Assert.notNull(clazz, "Class must not be null");@b@    return ((isSimpleValueType(clazz)) || ((clazz.isArray()) && (isSimpleValueType(clazz.getComponentType()))));@b@  }@b@@b@  public static boolean isSimpleValueType(Class<?> clazz)@b@  {@b@    return ((ClassUtils.isPrimitiveOrWrapper(clazz)) || (clazz.isEnum()) || @b@      (CharSequence.class@b@      .isAssignableFrom(clazz)) || @b@      (Number.class@b@      .isAssignableFrom(clazz)) || @b@      (Date.class@b@      .isAssignableFrom(clazz)) || @b@      (clazz@b@      .equals(URI.class)) || @b@      (clazz.equals(URL.class)) || @b@      (clazz@b@      .equals(Locale.class)) || @b@      (clazz.equals(Class.class)));@b@  }@b@@b@  public static void copyProperties(Object source, Object target)@b@    throws BeansException@b@  {@b@    copyProperties(source, target, null, (String[])null);@b@  }@b@@b@  public static void copyProperties(Object source, Object target, Class<?> editable)@b@    throws BeansException@b@  {@b@    copyProperties(source, target, editable, (String[])null);@b@  }@b@@b@  public static void copyProperties(Object source, Object target, String[] ignoreProperties)@b@    throws BeansException@b@  {@b@    copyProperties(source, target, null, ignoreProperties);@b@  }@b@@b@  private static void copyProperties(Object source, Object target, Class<?> editable, String[] ignoreProperties)@b@    throws BeansException@b@  {@b@    Assert.notNull(source, "Source must not be null");@b@    Assert.notNull(target, "Target must not be null");@b@@b@    Class actualEditable = target.getClass();@b@    if (editable != null) {@b@      if (!(editable.isInstance(target)))@b@      {@b@        throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable@b@          .getName() + "]");@b@      }@b@      actualEditable = editable;@b@    }@b@    PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);@b@    List ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;@b@@b@    PropertyDescriptor[] arrayOfPropertyDescriptor1 = targetPds; int i = arrayOfPropertyDescriptor1.length; for (int j = 0; j < i; ++j) { PropertyDescriptor targetPd = arrayOfPropertyDescriptor1[j];@b@      Method writeMethod = targetPd.getWriteMethod();@b@      if ((writeMethod != null) && (((ignoreList == null) || (!(ignoreList.contains(targetPd.getName())))))) {@b@        PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());@b@        if (sourcePd != null) {@b@          Method readMethod = sourcePd.getReadMethod();@b@          if ((readMethod != null) && @b@            (ClassUtils.isAssignable(writeMethod@b@            .getParameterTypes()[0], readMethod.getReturnType())))@b@            try {@b@              if (!(Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())))@b@                readMethod.setAccessible(true);@b@@b@              Object value = readMethod.invoke(source, new Object[0]);@b@              if (!(Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())))@b@                writeMethod.setAccessible(true);@b@@b@              writeMethod.invoke(target, new Object[] { value });@b@            }@b@            catch (Throwable ex)@b@            {@b@              throw new FatalBeanException("Could not copy property '" + targetPd@b@                .getName() + "' from source to target", ex);@b@            }@b@        }@b@      }@b@    }@b@  }@b@}