Spring中反射相关 BeanUtils.java 源码

来源:互联网 发布:c md5解密算法代码 编辑:程序博客网 时间:2024/05/16 09:38
  1. /** 
  2.  * Copyright 2002-2010 the original author or authors. 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.    
  17. package org.springframework.beans;  
  18.    
  19. import java.beans.PropertyDescriptor;  
  20. import java.beans.PropertyEditor;  
  21. import java.lang.reflect.Constructor;  
  22. import java.lang.reflect.InvocationTargetException;  
  23. import java.lang.reflect.Method;  
  24. import java.lang.reflect.Modifier;  
  25. import java.net.URI;  
  26. import java.net.URL;  
  27. import java.util.Arrays;  
  28. import java.util.Collections;  
  29. import java.util.Date;  
  30. import java.util.List;  
  31. import java.util.Locale;  
  32. import java.util.Map;  
  33. import java.util.WeakHashMap;  
  34.    
  35. import org.apache.commons.logging.Log;  
  36. import org.apache.commons.logging.LogFactory;  
  37.    
  38. import org.springframework.core.MethodParameter;  
  39. import org.springframework.util.Assert;  
  40. import org.springframework.util.ClassUtils;  
  41. import org.springframework.util.ReflectionUtils;  
  42. import org.springframework.util.StringUtils;  
  43.    
  44. /*** 
  45.  * Static convenience methods for JavaBeans: for instantiating beans, 
  46.  * checking bean property types, copying bean properties, etc. 
  47.  * 
  48.  * <p>Mainly for use within the framework, but to some degree also 
  49.  * useful for application classes. 
  50.  * 
  51.  * @author Rod Johnson 
  52.  * @author Juergen Hoeller 
  53.  * @author Rob Harrop 
  54.  * @author Sam Brannen 
  55.  */  
  56. public abstract class BeanUtils {  
  57.    
  58.     private static final Log logger = LogFactory.getLog(BeanUtils.class);  
  59.    
  60.     private static final Map<Class<?>, Boolean> unknownEditorTypes =  
  61.             Collections.synchronizedMap(new WeakHashMap<Class<?>, Boolean>());  
  62.    
  63.    
  64.     /*** 
  65.      * Convenience method to instantiate a class using its no-arg constructor. 
  66.      * As this method doesn't try to load classes by name, it should avoid 
  67.      * class-loading issues. 
  68.      * @param clazz class to instantiate 
  69.      * @return the new instance 
  70.      * @throws BeanInstantiationException if the bean cannot be instantiated 
  71.      */  
  72.     public static <T> T instantiate(Class<T> clazz) throws BeanInstantiationException {  
  73.         Assert.notNull(clazz, "Class must not be null");  
  74.         if (clazz.isInterface()) {  
  75.             throw new BeanInstantiationException(clazz, "Specified class is an interface");  
  76.         }  
  77.         try {  
  78.             return clazz.newInstance();  
  79.         }  
  80.         catch (InstantiationException ex) {  
  81.             throw new BeanInstantiationException(clazz, "Is it an abstract class?", ex);  
  82.         }  
  83.         catch (IllegalAccessException ex) {  
  84.             throw new BeanInstantiationException(clazz, "Is the constructor accessible?", ex);  
  85.         }  
  86.     }  
  87.    
  88.     /*** 
  89.      * Convenience method to instantiate a class using its no-arg constructor. 
  90.      * As this method doesn't try to load classes by name, it should avoid 
  91.      * class-loading issues. 
  92.      * <p>Note that this method tries to set the constructor accessible 
  93.      * if given a non-accessible (that is, non-public) constructor. 
  94.      * @param clazz class to instantiate 
  95.      * @return the new instance 
  96.      * @throws BeanInstantiationException if the bean cannot be instantiated 
  97.      */  
  98.     public static <T> T instantiateClass(Class<T> clazz) throws BeanInstantiationException {  
  99.         Assert.notNull(clazz, "Class must not be null");  
  100.         if (clazz.isInterface()) {  
  101.             throw new BeanInstantiationException(clazz, "Specified class is an interface");  
  102.         }  
  103.         try {  
  104.             return instantiateClass(clazz.getDeclaredConstructor());  
  105.         }  
  106.         catch (NoSuchMethodException ex) {  
  107.             throw new BeanInstantiationException(clazz, "No default constructor found", ex);  
  108.         }  
  109.     }  
  110.    
  111.     /*** 
  112.      * Convenience method to instantiate a class using the given constructor. 
  113.      * As this method doesn't try to load classes by name, it should avoid 
  114.      * class-loading issues. 
  115.      * <p>Note that this method tries to set the constructor accessible 
  116.      * if given a non-accessible (that is, non-public) constructor. 
  117.      * @param ctor the constructor to instantiate 
  118.      * @param args the constructor arguments to apply 
  119.      * @return the new instance 
  120.      * @throws BeanInstantiationException if the bean cannot be instantiated 
  121.      */  
  122.     public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {  
  123.         Assert.notNull(ctor, "Constructor must not be null");  
  124.         try {  
  125.             ReflectionUtils.makeAccessible(ctor);  
  126.             return ctor.newInstance(args);  
  127.         }  
  128.         catch (InstantiationException ex) {  
  129.             throw new BeanInstantiationException(ctor.getDeclaringClass(),  
  130.                     "Is it an abstract class?", ex);  
  131.         }  
  132.         catch (IllegalAccessException ex) {  
  133.             throw new BeanInstantiationException(ctor.getDeclaringClass(),  
  134.                     "Is the constructor accessible?", ex);  
  135.         }  
  136.         catch (IllegalArgumentException ex) {  
  137.             throw new BeanInstantiationException(ctor.getDeclaringClass(),  
  138.                     "Illegal arguments for constructor", ex);  
  139.         }  
  140.         catch (InvocationTargetException ex) {  
  141.             throw new BeanInstantiationException(ctor.getDeclaringClass(),  
  142.                     "Constructor threw exception", ex.getTargetException());  
  143.         }  
  144.     }  
  145.    
  146.     /*** 
  147.      * Find a method with the given method name and the given parameter types, 
  148.      * declared on the given class or one of its superclasses. Prefers public methods, 
  149.      * but will return a protected, package access, or private method too. 
  150.      * <p>Checks <code>Class.getMethod</code> first, falling back to 
  151.      * <code>findDeclaredMethod</code>. This allows to find public methods 
  152.      * without issues even in environments with restricted Java security settings. 
  153.      * @param clazz the class to check 
  154.      * @param methodName the name of the method to find 
  155.      * @param paramTypes the parameter types of the method to find 
  156.      * @return the Method object, or <code>null</code> if not found 
  157.      * @see java.lang.Class#getMethod 
  158.      * @see #findDeclaredMethod 
  159.      */  
  160.     public static Method findMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {  
  161.         try {  
  162.             return clazz.getMethod(methodName, paramTypes);  
  163.         }  
  164.         catch (NoSuchMethodException ex) {  
  165.             return findDeclaredMethod(clazz, methodName, paramTypes);  
  166.         }  
  167.     }  
  168.    
  169.     /*** 
  170.      * Find a method with the given method name and the given parameter types, 
  171.      * declared on the given class or one of its superclasses. Will return a public, 
  172.      * protected, package access, or private method. 
  173.      * <p>Checks <code>Class.getDeclaredMethod</code>, cascading upwards to all superclasses. 
  174.      * @param clazz the class to check 
  175.      * @param methodName the name of the method to find 
  176.      * @param paramTypes the parameter types of the method to find 
  177.      * @return the Method object, or <code>null</code> if not found 
  178.      * @see java.lang.Class#getDeclaredMethod 
  179.      */  
  180.     public static Method findDeclaredMethod(Class<?> clazz, String methodName, Class<?>[] paramTypes) {  
  181.         try {  
  182.             return clazz.getDeclaredMethod(methodName, paramTypes);  
  183.         }  
  184.         catch (NoSuchMethodException ex) {  
  185.             if (clazz.getSuperclass() != null) {  
  186.                 return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes);  
  187.             }  
  188.             return null;  
  189.         }  
  190.     }  
  191.    
  192.     /*** 
  193.      * Find a method with the given method name and minimal parameters (best case: none), 
  194.      * declared on the given class or one of its superclasses. Prefers public methods, 
  195.      * but will return a protected, package access, or private method too. 
  196.      * <p>Checks <code>Class.getMethods</code> first, falling back to 
  197.      * <code>findDeclaredMethodWithMinimalParameters</code>. This allows for finding public 
  198.      * methods without issues even in environments with restricted Java security settings. 
  199.      * @param clazz the class to check 
  200.      * @param methodName the name of the method to find 
  201.      * @return the Method object, or <code>null</code> if not found 
  202.      * @throws IllegalArgumentException if methods of the given name were found but 
  203.      * could not be resolved to a unique method with minimal parameters 
  204.      * @see java.lang.Class#getMethods 
  205.      * @see #findDeclaredMethodWithMinimalParameters 
  206.      */  
  207.     public static Method findMethodWithMinimalParameters(Class<?> clazz, String methodName)  
  208.             throws IllegalArgumentException {  
  209.    
  210.         Method targetMethod = findMethodWithMinimalParameters(clazz.getMethods(), methodName);  
  211.         if (targetMethod == null) {  
  212.             targetMethod = findDeclaredMethodWithMinimalParameters(clazz, methodName);  
  213.         }  
  214.         return targetMethod;  
  215.     }  
  216.    
  217.     /*** 
  218.      * Find a method with the given method name and minimal parameters (best case: none), 
  219.      * declared on the given class or one of its superclasses. Will return a public, 
  220.      * protected, package access, or private method. 
  221.      * <p>Checks <code>Class.getDeclaredMethods</code>, cascading upwards to all superclasses. 
  222.      * @param clazz the class to check 
  223.      * @param methodName the name of the method to find 
  224.      * @return the Method object, or <code>null</code> if not found 
  225.      * @throws IllegalArgumentException if methods of the given name were found but 
  226.      * could not be resolved to a unique method with minimal parameters 
  227.      * @see java.lang.Class#getDeclaredMethods 
  228.      */  
  229.     public static Method findDeclaredMethodWithMinimalParameters(Class<?> clazz, String methodName)  
  230.             throws IllegalArgumentException {  
  231.    
  232.         Method targetMethod = findMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName);  
  233.         if (targetMethod == null && clazz.getSuperclass() != null) {  
  234.             targetMethod = findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName);  
  235.         }  
  236.         return targetMethod;  
  237.     }  
  238.    
  239.     /*** 
  240.      * Find a method with the given method name and minimal parameters (best case: none) 
  241.      * in the given list of methods. 
  242.      * @param methods the methods to check 
  243.      * @param methodName the name of the method to find 
  244.      * @return the Method object, or <code>null</code> if not found 
  245.      * @throws IllegalArgumentException if methods of the given name were found but 
  246.      * could not be resolved to a unique method with minimal parameters 
  247.      */  
  248.     public static Method findMethodWithMinimalParameters(Method[] methods, String methodName)  
  249.             throws IllegalArgumentException {  
  250.    
  251.         Method targetMethod = null;  
  252.         int numMethodsFoundWithCurrentMinimumArgs = 0;  
  253.         for (Method method : methods) {  
  254.             if (method.getName().equals(methodName)) {  
  255.                 int numParams = method.getParameterTypes().length;  
  256.                 if (targetMethod == null || numParams < targetMethod.getParameterTypes().length) {  
  257.                     targetMethod = method;  
  258.                     numMethodsFoundWithCurrentMinimumArgs = 1;  
  259.                 }  
  260.                 else {  
  261.                     if (targetMethod.getParameterTypes().length == numParams) {  
  262.                         // Additional candidate with same length.  
  263.                         numMethodsFoundWithCurrentMinimumArgs++;  
  264.                     }  
  265.                 }  
  266.             }  
  267.         }  
  268.         if (numMethodsFoundWithCurrentMinimumArgs > 1) {  
  269.             throw new IllegalArgumentException("Cannot resolve method '" + methodName +  
  270.                     "' to a unique method. Attempted to resolve to overloaded method with " +  
  271.                     "the least number of parameters, but there were " +  
  272.                     numMethodsFoundWithCurrentMinimumArgs + " candidates.");  
  273.         }  
  274.         return targetMethod;  
  275.     }  
  276.    
  277.     /*** 
  278.      * Parse a method signature in the form <code>methodName[([arg_list])]</code>, 
  279.      * where <code>arg_list</code> is an optional, comma-separated list of fully-qualified 
  280.      * type names, and attempts to resolve that signature against the supplied <code>Class</code>. 
  281.      * <p>When not supplying an argument list (<code>methodName</code>) the method whose name 
  282.      * matches and has the least number of parameters will be returned. When supplying an 
  283.      * argument type list, only the method whose name and argument types match will be returned. 
  284.      * <p>Note then that <code>methodName</code> and <code>methodName()</code> are <strong>not</strong> 
  285.      * resolved in the same way. The signature <code>methodName</code> means the method called 
  286.      * <code>methodName</code> with the least number of arguments, whereas <code>methodName()</code> 
  287.      * means the method called <code>methodName</code> with exactly 0 arguments. 
  288.      * <p>If no method can be found, then <code>null</code> is returned. 
  289.      * @param signature the method signature as String representation 
  290.      * @param clazz the class to resolve the method signature against 
  291.      * @return the resolved Method 
  292.      * @see #findMethod 
  293.      * @see #findMethodWithMinimalParameters 
  294.      */  
  295.     public static Method resolveSignature(String signature, Class<?> clazz) {  
  296.         Assert.hasText(signature, "'signature' must not be empty");  
  297.         Assert.notNull(clazz, "Class must not be null");  
  298.    
  299.         int firstParen = signature.indexOf("(");  
  300.         int lastParen = signature.indexOf(")");  
  301.    
  302.         if (firstParen > -1 && lastParen == -1) {  
  303.             throw new IllegalArgumentException("Invalid method signature '" + signature +  
  304.                     "': expected closing ')' for args list");  
  305.         }  
  306.         else if (lastParen > -1 && firstParen == -1) {  
  307.             throw new IllegalArgumentException("Invalid method signature '" + signature +  
  308.                     "': expected opening '(' for args list");  
  309.         }  
  310.         else if (firstParen == -1 && lastParen == -1) {  
  311.             return findMethodWithMinimalParameters(clazz, signature);  
  312.         }  
  313.         else {  
  314.             String methodName = signature.substring(0, firstParen);  
  315.             String[] parameterTypeNames =  
  316.                     StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen));  
  317.             Class<?>[] parameterTypes = new Class[parameterTypeNames.length];  
  318.             for (int i = 0; i < parameterTypeNames.length; i++) {  
  319.                 String parameterTypeName = parameterTypeNames[i].trim();  
  320.                 try {  
  321.                     parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader());  
  322.                 }  
  323.                 catch (Throwable ex) {  
  324.                     throw new IllegalArgumentException("Invalid method signature: unable to resolve type [" +  
  325.                             parameterTypeName + "] for argument " + i + ". Root cause: " + ex);  
  326.                 }  
  327.             }  
  328.             return findMethod(clazz, methodName, parameterTypes);  
  329.         }  
  330.     }  
  331.    
  332.    
  333.     /*** 
  334.      * Retrieve the JavaBeans <code>PropertyDescriptor</code>s of a given class. 
  335.      * @param clazz the Class to retrieve the PropertyDescriptors for 
  336.      * @return an array of <code>PropertyDescriptors</code> for the given class 
  337.      * @throws BeansException if PropertyDescriptor look fails 
  338.      */  
  339.     public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws BeansException {  
  340.         CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);  
  341.         return cr.getPropertyDescriptors();  
  342.     }  
  343.    
  344.     /*** 
  345.      * Retrieve the JavaBeans <code>PropertyDescriptors</code> for the given property. 
  346.      * @param clazz the Class to retrieve the PropertyDescriptor for 
  347.      * @param propertyName the name of the property 
  348.      * @return the corresponding PropertyDescriptor, or <code>null</code> if none 
  349.      * @throws BeansException if PropertyDescriptor lookup fails 
  350.      */  
  351.     public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName)  
  352.             throws BeansException {  
  353.    
  354.         CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz);  
  355.         return cr.getPropertyDescriptor(propertyName);  
  356.     }  
  357.    
  358.     /*** 
  359.      * Find a JavaBeans <code>PropertyDescriptor</code> for the given method, 
  360.      * with the method either being the read method or the write method for 
  361.      * that bean property. 
  362.      * @param method the method to find a corresponding PropertyDescriptor for 
  363.      * @return the corresponding PropertyDescriptor, or <code>null</code> if none 
  364.      * @throws BeansException if PropertyDescriptor lookup fails 
  365.      */  
  366.     public static PropertyDescriptor findPropertyForMethod(Method method) throws BeansException {  
  367.         Assert.notNull(method, "Method must not be null");  
  368.         PropertyDescriptor[] pds = getPropertyDescriptors(method.getDeclaringClass());  
  369.         for (PropertyDescriptor pd : pds) {  
  370.             if (method.equals(pd.getReadMethod()) || method.equals(pd.getWriteMethod())) {  
  371.                 return pd;  
  372.             }  
  373.         }  
  374.         return null;  
  375.     }  
  376.    
  377.     /*** 
  378.      * Find a JavaBeans PropertyEditor following the 'Editor' suffix convention 
  379.      * (e.g. "mypackage.MyDomainClass" -> "mypackage.MyDomainClassEditor"). 
  380.      * <p>Compatible to the standard JavaBeans convention as implemented by 
  381.      * {@link java.beans.PropertyEditorManager} but isolated from the latter's 
  382.      * registered default editors for primitive types. 
  383.      * @param targetType the type to find an editor for 
  384.      * @return the corresponding editor, or <code>null</code> if none found 
  385.      */  
  386.     public static PropertyEditor findEditorByConvention(Class<?> targetType) {  
  387.         if (targetType == null || targetType.isArray() || unknownEditorTypes.containsKey(targetType)) {  
  388.             return null;  
  389.         }  
  390.         ClassLoader cl = targetType.getClassLoader();  
  391.         if (cl == null) {  
  392.             try {  
  393.                 cl = ClassLoader.getSystemClassLoader();  
  394.                 if (cl == null) {  
  395.                     return null;  
  396.                 }  
  397.             }  
  398.             catch (Throwable ex) {  
  399.                 // e.g. AccessControlException on Google App Engine  
  400.                 if (logger.isDebugEnabled()) {  
  401.                     logger.debug("Could not access system ClassLoader: " + ex);  
  402.                 }  
  403.                 return null;  
  404.             }  
  405.         }  
  406.         String editorName = targetType.getName() + "Editor";  
  407.         try {  
  408.             Class<?> editorClass = cl.loadClass(editorName);  
  409.             if (!PropertyEditor.class.isAssignableFrom(editorClass)) {  
  410.                 if (logger.isWarnEnabled()) {  
  411.                     logger.warn("Editor class [" + editorName +  
  412.                             "] does not implement [java.beans.PropertyEditor] interface");  
  413.                 }  
  414.                 unknownEditorTypes.put(targetType, Boolean.TRUE);  
  415.                 return null;  
  416.             }  
  417.             return (PropertyEditor) instantiateClass(editorClass);  
  418.         }  
  419.         catch (ClassNotFoundException ex) {  
  420.             if (logger.isDebugEnabled()) {  
  421.                 logger.debug("No property editor [" + editorName + "] found for type " +  
  422.                         targetType.getName() + " according to 'Editor' suffix convention");  
  423.             }  
  424.             unknownEditorTypes.put(targetType, Boolean.TRUE);  
  425.             return null;  
  426.         }  
  427.     }  
  428.    
  429.     /*** 
  430.      * Determine the bean property type for the given property from the 
  431.      * given classes/interfaces, if possible. 
  432.      * @param propertyName the name of the bean property 
  433.      * @param beanClasses the classes to check against 
  434.      * @return the property type, or <code>Object.class</code> as fallback 
  435.      */  
  436.     public static Class<?> findPropertyType(String propertyName, Class<?>[] beanClasses) {  
  437.         if (beanClasses != null) {  
  438.             for (Class<?> beanClass : beanClasses) {  
  439.                 PropertyDescriptor pd = getPropertyDescriptor(beanClass, propertyName);  
  440.                 if (pd != null) {  
  441.                     return pd.getPropertyType();  
  442.                 }  
  443.             }  
  444.         }  
  445.         return Object.class;  
  446.     }  
  447.    
  448.     /*** 
  449.      * Obtain a new MethodParameter object for the write method of the 
  450.      * specified property. 
  451.      * @param pd the PropertyDescriptor for the property 
  452.      * @return a corresponding MethodParameter object 
  453.      */  
  454.     public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) {  
  455.         if (pd instanceof GenericTypeAwarePropertyDescriptor) {  
  456.             return new MethodParameter(  
  457.                     ((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodParameter());  
  458.         }  
  459.         else {  
  460.             return new MethodParameter(pd.getWriteMethod(), 0);  
  461.         }  
  462.     }  
  463.    
  464.     /*** 
  465.      * Check if the given type represents a "simple" property: 
  466.      * a primitive, a String or other CharSequence, a Number, a Date, 
  467.      * a URI, a URL, a Locale, a Class, or a corresponding array. 
  468.      * <p>Used to determine properties to check for a "simple" dependency-check. 
  469.      * @param clazz the type to check 
  470.      * @return whether the given type represents a "simple" property 
  471.      * @see org.springframework.beans.factory.support.RootBeanDefinition#DEPENDENCY_CHECK_SIMPLE 
  472.      * @see org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#checkDependencies 
  473.      */  
  474.     public static boolean isSimpleProperty(Class<?> clazz) {  
  475.         Assert.notNull(clazz, "Class must not be null");  
  476.         return isSimpleValueType(clazz) || (clazz.isArray() && isSimpleValueType(clazz.getComponentType()));  
  477.     }  
  478.    
  479.     /*** 
  480.      * Check if the given type represents a "simple" value type: 
  481.      * a primitive, a String or other CharSequence, a Number, a Date, 
  482.      * a URI, a URL, a Locale or a Class. 
  483.      * @param clazz the type to check 
  484.      * @return whether the given type represents a "simple" value type 
  485.      */  
  486.     public static boolean isSimpleValueType(Class<?> clazz) {  
  487.         return ClassUtils.isPrimitiveOrWrapper(clazz) || clazz.isEnum() ||  
  488.                 CharSequence.class.isAssignableFrom(clazz) ||  
  489.                 Number.class.isAssignableFrom(clazz) ||  
  490.                 Date.class.isAssignableFrom(clazz) ||  
  491.                 clazz.equals(URI.class) || clazz.equals(URL.class) ||  
  492.                 clazz.equals(Locale.class) || clazz.equals(Class.class);  
  493.     }  
  494.    
  495.    
  496.     /*** 
  497.      * Copy the property values of the given source bean into the target bean. 
  498.      * <p>Note: The source and target classes do not have to match or even be derived 
  499.      * from each other, as long as the properties match. Any bean properties that the 
  500.      * source bean exposes but the target bean does not will silently be ignored. 
  501.      * <p>This is just a convenience method. For more complex transfer needs, 
  502.      * consider using a full BeanWrapper. 
  503.      * @param source the source bean 
  504.      * @param target the target bean 
  505.      * @throws BeansException if the copying failed 
  506.      * @see BeanWrapper 
  507.      */  
  508.     public static void copyProperties(Object source, Object target) throws BeansException {  
  509.         copyProperties(source, target, nullnull);  
  510.     }  
  511.    
  512.     /*** 
  513.      * Copy the property values of the given source bean into the given target bean, 
  514.      * only setting properties defined in the given "editable" class (or interface). 
  515.      * <p>Note: The source and target classes do not have to match or even be derived 
  516.      * from each other, as long as the properties match. Any bean properties that the 
  517.      * source bean exposes but the target bean does not will silently be ignored. 
  518.      * <p>This is just a convenience method. For more complex transfer needs, 
  519.      * consider using a full BeanWrapper. 
  520.      * @param source the source bean 
  521.      * @param target the target bean 
  522.      * @param editable the class (or interface) to restrict property setting to 
  523.      * @throws BeansException if the copying failed 
  524.      * @see BeanWrapper 
  525.      */  
  526.     public static void copyProperties(Object source, Object target, Class<?> editable)  
  527.             throws BeansException {  
  528.    
  529.         copyProperties(source, target, editable, null);  
  530.     }  
  531.    
  532.     /*** 
  533.      * Copy the property values of the given source bean into the given target bean, 
  534.      * ignoring the given "ignoreProperties". 
  535.      * <p>Note: The source and target classes do not have to match or even be derived 
  536.      * from each other, as long as the properties match. Any bean properties that the 
  537.      * source bean exposes but the target bean does not will silently be ignored. 
  538.      * <p>This is just a convenience method. For more complex transfer needs, 
  539.      * consider using a full BeanWrapper. 
  540.      * @param source the source bean 
  541.      * @param target the target bean 
  542.      * @param ignoreProperties array of property names to ignore 
  543.      * @throws BeansException if the copying failed 
  544.      * @see BeanWrapper 
  545.      */  
  546.     public static void copyProperties(Object source, Object target, String[] ignoreProperties)  
  547.             throws BeansException {  
  548.    
  549.         copyProperties(source, target, null, ignoreProperties);  
  550.     }  
  551.    
  552.     /*** 
  553.      * Copy the property values of the given source bean into the given target bean. 
  554.      * <p>Note: The source and target classes do not have to match or even be derived 
  555.      * from each other, as long as the properties match. Any bean properties that the 
  556.      * source bean exposes but the target bean does not will silently be ignored. 
  557.      * @param source the source bean 
  558.      * @param target the target bean 
  559.      * @param editable the class (or interface) to restrict property setting to 
  560.      * @param ignoreProperties array of property names to ignore 
  561.      * @throws BeansException if the copying failed 
  562.      * @see BeanWrapper 
  563.      */  
  564.     private static void copyProperties(Object source, Object target, Class<?> editable, String[] ignoreProperties)  
  565.             throws BeansException {  
  566.    
  567.         Assert.notNull(source, "Source must not be null");  
  568.         Assert.notNull(target, "Target must not be null");  
  569.    
  570.         Class<?> actualEditable = target.getClass();  
  571.         if (editable != null) {  
  572.             if (!editable.isInstance(target)) {  
  573.                 throw new IllegalArgumentException("Target class [" + target.getClass().getName() +  
  574.                         "] not assignable to Editable class [" + editable.getName() + "]");  
  575.             }  
  576.             actualEditable = editable;  
  577.         }  
  578.         PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);  
  579.         List<String> ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null;  
  580.    
  581.         for (PropertyDescriptor targetPd : targetPds) {  
  582.             if (targetPd.getWriteMethod() != null &&  
  583.                     (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) {  
  584.                 PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());  
  585.                 if (sourcePd != null && sourcePd.getReadMethod() != null) {  
  586.                     try {  
  587.                         Method readMethod = sourcePd.getReadMethod();  
  588.                         if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {  
  589.                             readMethod.setAccessible(true);  
  590.                         }  
  591.                         Object value = readMethod.invoke(source);  
  592.                         Method writeMethod = targetPd.getWriteMethod();  
  593.                         if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {  
  594.                             writeMethod.setAccessible(true);  
  595.                         }  
  596.                         writeMethod.invoke(target, value);  
  597.                     }  
  598.                     catch (Throwable ex) {  
  599.                         throw new FatalBeanException("Could not copy properties from source to target", ex);  
  600.                     }  
  601.                 }  
  602.             }  
  603.         }  
  604.     }  
  605.    

0 0
原创粉丝点击