1.自定义工具类 - 通过该工具类实现对象属性的修改、属性名称获取值、深度克隆属性的内容,使用业务抽象层面的初始化改造、遍历修改或动态修改任意类属性等场景,具体代码示例如下import java.lang.reflect.Field;@b@import java.math.BigDecimal;@b@import java.util.Date;@b@import com.xwood.common.util.DateUtils;@b@@b@public class ReflectUtil {@b@/**@b@ * 获取类的字段值@b@ * @param source 类的对象@b@ * @param fieldName 字段名称@b@ * @return@b@ * @throws NoSuchFieldException @b@ */@b@public static Object getFieldValue(Object source,String fieldName) throws NoSuchFieldException@b@{@b@Object o = null;@b@try {@b@Field field = source.getClass().getDeclaredField(fieldName);@b@field.setAccessible(true);@b@o = field.get(source);@b@} catch (SecurityException e) {@b@e.printStackTrace();@b@} catch (NoSuchFieldException e) {@b@throw e;@b@} catch (IllegalArgumentException e) {@b@e.printStackTrace();@b@} catch (IllegalAccessException e) {@b@e.printStackTrace();@b@}@b@return o;@b@}@b@@b@/**@b@ * 设置字段值@b@ * @param source@b@ * @param fieldName@b@ * @param fieldvalue@b@ * @throws NoSuchFieldException @b@ */@b@public static void setFiledValue(Object source,String fieldName,Object fieldvalue) throws NoSuchFieldException@b@{@b@try {@b@Field field = source.getClass().getDeclaredField(fieldName);@b@field.setAccessible(true);@b@setValue(source, field, fieldvalue);@b@} catch (SecurityException e) {@b@e.printStackTrace();@b@} catch (NoSuchFieldException e) {@b@throw e;@b@} catch (IllegalArgumentException e) {@b@e.printStackTrace();@b@} catch (IllegalAccessException e) {@b@e.printStackTrace();@b@}@b@}@b@@b@/**@b@ * @see ObjectConvertorUtils@b@ */@b@private static void setValue(Object obj, Field field, Object value) throws IllegalAccessException{@b@if(value == null){@b@return;@b@}@b@try{@b@field.set(obj, value);@b@}catch(IllegalArgumentException e){@b@field.set(obj, getRealValue(field.getType(),value));@b@}@b@}@b@@b@private static Object getRealValue(Class> type, Object value){@b@if(int.class.isAssignableFrom(type)){@b@return new Integer(value.toString());@b@}else if (Integer.class.isAssignableFrom(type)) {@b@return new Integer(value.toString());@b@}else if(long.class.isAssignableFrom(type)){@b@return new Long(value.toString());@b@}else if(boolean.class.isAssignableFrom(type)){@b@return new Boolean(value.toString());@b@}else if(double.class.isAssignableFrom(type)){@b@return new Double(value.toString());@b@}else if(char.class.isAssignableFrom(type)){@b@return (Character) value.toString().charAt(0);@b@}else if(short.class.isAssignableFrom(type)){@b@return new Short(value.toString());@b@}else if(float.class.isAssignableFrom(type)){@b@return new Float(value.toString());@b@}else if(byte.class.isAssignableFrom(type)){@b@return new Byte(value.toString());@b@}else if(BigDecimal.class.isAssignableFrom(type)){@b@return new BigDecimal(value.toString());@b@}@b@if(Date.class.isAssignableFrom(type)){@b@return DateUtils.string2Date(value.toString());@b@}@b@return null;@b@}@b@}
2.基于spring的org.springframework.util.ReflectionUtils类,源码如下import java.lang.reflect.Constructor;@b@import java.lang.reflect.Field;@b@import java.lang.reflect.InvocationTargetException;@b@import java.lang.reflect.Method;@b@import java.lang.reflect.Modifier;@b@import java.lang.reflect.UndeclaredThrowableException;@b@import java.sql.SQLException;@b@import java.util.ArrayList;@b@import java.util.Arrays;@b@import java.util.List;@b@import java.util.regex.Pattern;@b@@b@/**@b@ * Simple utility class for working with the reflection API and handling@b@ * reflection exceptions.@b@ *@b@ *
Only intended for internal use.@b@ *@b@ * @author Juergen Hoeller@b@ * @author Rob Harrop@b@ * @author Rod Johnson@b@ * @author Costin Leau@b@ * @author Sam Brannen@b@ * @author Chris Beams@b@ * @since 1.2.2@b@ */@b@public abstract class ReflectionUtils {@b@@b@private static final Pattern CGLIB_RENAMED_METHOD_PATTERN = Pattern.compile("CGLIB\\$(.+)\\$\\d+");@b@@b@/**@b@ * Attempt to find a {@link Field field} on the supplied {@link Class} with the@b@ * supplied name
. Searches all superclasses up to {@link Object}.@b@ * @param clazz the class to introspect@b@ * @param name the name of the field@b@ * @return the corresponding Field object, or null
if not found@b@ */@b@public static Field findField(Class> clazz, String name) {@b@return findField(clazz, name, null);@b@}@b@@b@/**@b@ * Attempt to find a {@link Field field} on the supplied {@link Class} with the@b@ * supplied name
and/or {@link Class type}. Searches all superclasses@b@ * up to {@link Object}.@b@ * @param clazz the class to introspect@b@ * @param name the name of the field (may be null
if type is specified)@b@ * @param type the type of the field (may be null
if name is specified)@b@ * @return the corresponding Field object, or null
if not found@b@ */@b@public static Field findField(Class> clazz, String name, Class> type) {@b@Assert.notNull(clazz, "Class must not be null");@b@Assert.isTrue(name != null || type != null, "Either name or type of the field must be specified");@b@Class> searchType = clazz;@b@while (!Object.class.equals(searchType) && searchType != null) {@b@Field[] fields = searchType.getDeclaredFields();@b@for (Field field : fields) {@b@if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) {@b@return field;@b@}@b@}@b@searchType = searchType.getSuperclass();@b@}@b@return null;@b@}@b@@b@/**@b@ * Set the field represented by the supplied {@link Field field object} on the@b@ * specified {@link Object target object} to the specified value
.@b@ * In accordance with {@link Field#set(Object, Object)} semantics, the new value@b@ * is automatically unwrapped if the underlying field has a primitive type.@b@ *
Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}.@b@ * @param field the field to set@b@ * @param target the target object on which to set the field@b@ * @param value the value to set; may be null
@b@ */@b@public static void setField(Field field, Object target, Object value) {@b@try {@b@field.set(target, value);@b@}@b@catch (IllegalAccessException ex) {@b@handleReflectionException(ex);@b@throw new IllegalStateException("Unexpected reflection exception - " + ex.getClass().getName() + ": "@b@+ ex.getMessage());@b@}@b@}@b@@b@/**@b@ * Get the field represented by the supplied {@link Field field object} on the@b@ * specified {@link Object target object}. In accordance with {@link Field#get(Object)}@b@ * semantics, the returned value is automatically wrapped if the underlying field@b@ * has a primitive type.@b@ *
Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}.@b@ * @param field the field to get@b@ * @param target the target object from which to get the field@b@ * @return the field's current value@b@ */@b@public static Object getField(Field field, Object target) {@b@try {@b@return field.get(target);@b@}@b@catch (IllegalAccessException ex) {@b@handleReflectionException(ex);@b@throw new IllegalStateException(@b@"Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage());@b@}@b@}@b@@b@/**@b@ * Attempt to find a {@link Method} on the supplied class with the supplied name@b@ * and no parameters. Searches all superclasses up to Object
.@b@ *
Returns null
if no {@link Method} can be found.@b@ * @param clazz the class to introspect@b@ * @param name the name of the method@b@ * @return the Method object, or null
if none found@b@ */@b@public static Method findMethod(Class> clazz, String name) {@b@return findMethod(clazz, name, new Class[0]);@b@}@b@@b@/**@b@ * Attempt to find a {@link Method} on the supplied class with the supplied name@b@ * and parameter types. Searches all superclasses up to Object
.@b@ *
Returns null
if no {@link Method} can be found.@b@ * @param clazz the class to introspect@b@ * @param name the name of the method@b@ * @param paramTypes the parameter types of the method@b@ * (may be null
to indicate any signature)@b@ * @return the Method object, or null
if none found@b@ */@b@public static Method findMethod(Class> clazz, String name, Class>... paramTypes) {@b@Assert.notNull(clazz, "Class must not be null");@b@Assert.notNull(name, "Method name must not be null");@b@Class> searchType = clazz;@b@while (searchType != null) {@b@Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());@b@for (Method method : methods) {@b@if (name.equals(method.getName())@b@&& (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) {@b@return method;@b@}@b@}@b@searchType = searchType.getSuperclass();@b@}@b@return null;@b@}@b@@b@/**@b@ * Invoke the specified {@link Method} against the supplied target object with no arguments.@b@ * The target object can be null
when invoking a static {@link Method}.@b@ *
Thrown exceptions are handled via a call to {@link #handleReflectionException}.@b@ * @param method the method to invoke@b@ * @param target the target object to invoke the method on@b@ * @return the invocation result, if any@b@ * @see #invokeMethod(java.lang.reflect.Method, Object, Object[])@b@ */@b@public static Object invokeMethod(Method method, Object target) {@b@return invokeMethod(method, target, new Object[0]);@b@}@b@@b@/**@b@ * Invoke the specified {@link Method} against the supplied target object with the@b@ * supplied arguments. The target object can be null
when invoking a@b@ * static {@link Method}.@b@ *
Thrown exceptions are handled via a call to {@link #handleReflectionException}.@b@ * @param method the method to invoke@b@ * @param target the target object to invoke the method on@b@ * @param args the invocation arguments (may be null
)@b@ * @return the invocation result, if any@b@ */@b@public static Object invokeMethod(Method method, Object target, Object... args) {@b@try {@b@return method.invoke(target, args);@b@}@b@catch (Exception ex) {@b@handleReflectionException(ex);@b@}@b@throw new IllegalStateException("Should never get here");@b@}@b@@b@/**@b@ * Invoke the specified JDBC API {@link Method} against the supplied target@b@ * object with no arguments.@b@ * @param method the method to invoke@b@ * @param target the target object to invoke the method on@b@ * @return the invocation result, if any@b@ * @throws SQLException the JDBC API SQLException to rethrow (if any)@b@ * @see #invokeJdbcMethod(java.lang.reflect.Method, Object, Object[])@b@ */@b@public static Object invokeJdbcMethod(Method method, Object target) throws SQLException {@b@return invokeJdbcMethod(method, target, new Object[0]);@b@}@b@@b@/**@b@ * Invoke the specified JDBC API {@link Method} against the supplied target@b@ * object with the supplied arguments.@b@ * @param method the method to invoke@b@ * @param target the target object to invoke the method on@b@ * @param args the invocation arguments (may be null
)@b@ * @return the invocation result, if any@b@ * @throws SQLException the JDBC API SQLException to rethrow (if any)@b@ * @see #invokeMethod(java.lang.reflect.Method, Object, Object[])@b@ */@b@public static Object invokeJdbcMethod(Method method, Object target, Object... args) throws SQLException {@b@try {@b@return method.invoke(target, args);@b@}@b@catch (IllegalAccessException ex) {@b@handleReflectionException(ex);@b@}@b@catch (InvocationTargetException ex) {@b@if (ex.getTargetException() instanceof SQLException) {@b@throw (SQLException) ex.getTargetException();@b@}@b@handleInvocationTargetException(ex);@b@}@b@throw new IllegalStateException("Should never get here");@b@}@b@@b@/**@b@ * Handle the given reflection exception. Should only be called if no@b@ * checked exception is expected to be thrown by the target method.@b@ *
Throws the underlying RuntimeException or Error in case of an@b@ * InvocationTargetException with such a root cause. Throws an@b@ * IllegalStateException with an appropriate message else.@b@ * @param ex the reflection exception to handle@b@ */@b@public static void handleReflectionException(Exception ex) {@b@if (ex instanceof NoSuchMethodException) {@b@throw new IllegalStateException("Method not found: " + ex.getMessage());@b@}@b@if (ex instanceof IllegalAccessException) {@b@throw new IllegalStateException("Could not access method: " + ex.getMessage());@b@}@b@if (ex instanceof InvocationTargetException) {@b@handleInvocationTargetException((InvocationTargetException) ex);@b@}@b@if (ex instanceof RuntimeException) {@b@throw (RuntimeException) ex;@b@}@b@throw new UndeclaredThrowableException(ex);@b@}@b@@b@/**@b@ * Handle the given invocation target exception. Should only be called if no@b@ * checked exception is expected to be thrown by the target method.@b@ *
Throws the underlying RuntimeException or Error in case of such a root@b@ * cause. Throws an IllegalStateException else.@b@ * @param ex the invocation target exception to handle@b@ */@b@public static void handleInvocationTargetException(InvocationTargetException ex) {@b@rethrowRuntimeException(ex.getTargetException());@b@}@b@@b@/**@b@ * Rethrow the given {@link Throwable exception}, which is presumably the@b@ * target exception of an {@link InvocationTargetException}. Should@b@ * only be called if no checked exception is expected to be thrown by the@b@ * target method.@b@ *
Rethrows the underlying exception cast to an {@link RuntimeException} or@b@ * {@link Error} if appropriate; otherwise, throws an@b@ * {@link IllegalStateException}.@b@ * @param ex the exception to rethrow@b@ * @throws RuntimeException the rethrown exception@b@ */@b@public static void rethrowRuntimeException(Throwable ex) {@b@if (ex instanceof RuntimeException) {@b@throw (RuntimeException) ex;@b@}@b@if (ex instanceof Error) {@b@throw (Error) ex;@b@}@b@throw new UndeclaredThrowableException(ex);@b@}@b@@b@/**@b@ * Rethrow the given {@link Throwable exception}, which is presumably the@b@ * target exception of an {@link InvocationTargetException}. Should@b@ * only be called if no checked exception is expected to be thrown by the@b@ * target method.@b@ *
Rethrows the underlying exception cast to an {@link Exception} or@b@ * {@link Error} if appropriate; otherwise, throws an@b@ * {@link IllegalStateException}.@b@ * @param ex the exception to rethrow@b@ * @throws Exception the rethrown exception (in case of a checked exception)@b@ */@b@public static void rethrowException(Throwable ex) throws Exception {@b@if (ex instanceof Exception) {@b@throw (Exception) ex;@b@}@b@if (ex instanceof Error) {@b@throw (Error) ex;@b@}@b@throw new UndeclaredThrowableException(ex);@b@}@b@@b@/**@b@ * Determine whether the given method explicitly declares the given@b@ * exception or one of its superclasses, which means that an exception of@b@ * that type can be propagated as-is within a reflective invocation.@b@ * @param method the declaring method@b@ * @param exceptionType the exception to throw@b@ * @return true
if the exception can be thrown as-is;@b@ * false
if it needs to be wrapped@b@ */@b@public static boolean declaresException(Method method, Class> exceptionType) {@b@Assert.notNull(method, "Method must not be null");@b@Class>[] declaredExceptions = method.getExceptionTypes();@b@for (Class> declaredException : declaredExceptions) {@b@if (declaredException.isAssignableFrom(exceptionType)) {@b@return true;@b@}@b@}@b@return false;@b@}@b@@b@/**@b@ * Determine whether the given field is a "public static final" constant.@b@ * @param field the field to check@b@ */@b@public static boolean isPublicStaticFinal(Field field) {@b@int modifiers = field.getModifiers();@b@return (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers));@b@}@b@@b@/**@b@ * Determine whether the given method is an "equals" method.@b@ * @see java.lang.Object#equals(Object)@b@ */@b@public static boolean isEqualsMethod(Method method) {@b@if (method == null || !method.getName().equals("equals")) {@b@return false;@b@}@b@Class>[] paramTypes = method.getParameterTypes();@b@return (paramTypes.length == 1 && paramTypes[0] == Object.class);@b@}@b@@b@/**@b@ * Determine whether the given method is a "hashCode" method.@b@ * @see java.lang.Object#hashCode()@b@ */@b@public static boolean isHashCodeMethod(Method method) {@b@return (method != null && method.getName().equals("hashCode") && method.getParameterTypes().length == 0);@b@}@b@@b@/**@b@ * Determine whether the given method is a "toString" method.@b@ * @see java.lang.Object#toString()@b@ */@b@public static boolean isToStringMethod(Method method) {@b@return (method != null && method.getName().equals("toString") && method.getParameterTypes().length == 0);@b@}@b@@b@/**@b@ * Determine whether the given method is originally declared by {@link java.lang.Object}.@b@ */@b@public static boolean isObjectMethod(Method method) {@b@try {@b@Object.class.getDeclaredMethod(method.getName(), method.getParameterTypes());@b@return true;@b@} catch (SecurityException ex) {@b@return false;@b@} catch (NoSuchMethodException ex) {@b@return false;@b@}@b@}@b@@b@/**@b@ * Determine whether the given method is a CGLIB 'renamed' method, following@b@ * the pattern "CGLIB$methodName$0".@b@ * @param renamedMethod the method to check@b@ * @see org.springframework.cglib.proxy.Enhancer#rename@b@ */@b@public static boolean isCglibRenamedMethod(Method renamedMethod) {@b@return CGLIB_RENAMED_METHOD_PATTERN.matcher(renamedMethod.getName()).matches();@b@}@b@@b@/**@b@ * Make the given field accessible, explicitly setting it accessible if@b@ * necessary. The setAccessible(true)
method is only called@b@ * when actually necessary, to avoid unnecessary conflicts with a JVM@b@ * SecurityManager (if active).@b@ * @param field the field to make accessible@b@ * @see java.lang.reflect.Field#setAccessible@b@ */@b@public static void makeAccessible(Field field) {@b@if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) ||@b@Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {@b@field.setAccessible(true);@b@}@b@}@b@@b@/**@b@ * Make the given method accessible, explicitly setting it accessible if@b@ * necessary. The setAccessible(true)
method is only called@b@ * when actually necessary, to avoid unnecessary conflicts with a JVM@b@ * SecurityManager (if active).@b@ * @param method the method to make accessible@b@ * @see java.lang.reflect.Method#setAccessible@b@ */@b@public static void makeAccessible(Method method) {@b@if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))@b@&& !method.isAccessible()) {@b@method.setAccessible(true);@b@}@b@}@b@@b@/**@b@ * Make the given constructor accessible, explicitly setting it accessible@b@ * if necessary. The setAccessible(true)
method is only called@b@ * when actually necessary, to avoid unnecessary conflicts with a JVM@b@ * SecurityManager (if active).@b@ * @param ctor the constructor to make accessible@b@ * @see java.lang.reflect.Constructor#setAccessible@b@ */@b@public static void makeAccessible(Constructor> ctor) {@b@if ((!Modifier.isPublic(ctor.getModifiers()) || !Modifier.isPublic(ctor.getDeclaringClass().getModifiers()))@b@&& !ctor.isAccessible()) {@b@ctor.setAccessible(true);@b@}@b@}@b@@b@/**@b@ * Perform the given callback operation on all matching methods of the given@b@ * class and superclasses.@b@ *
The same named method occurring on subclass and superclass will appear@b@ * twice, unless excluded by a {@link MethodFilter}.@b@ * @param clazz class to start looking at@b@ * @param mc the callback to invoke for each method@b@ * @see #doWithMethods(Class, MethodCallback, MethodFilter)@b@ */@b@public static void doWithMethods(Class> clazz, MethodCallback mc) throws IllegalArgumentException {@b@doWithMethods(clazz, mc, null);@b@}@b@@b@/**@b@ * Perform the given callback operation on all matching methods of the given@b@ * class and superclasses (or given interface and super-interfaces).@b@ *
The same named method occurring on subclass and superclass will appear@b@ * twice, unless excluded by the specified {@link MethodFilter}.@b@ * @param clazz class to start looking at@b@ * @param mc the callback to invoke for each method@b@ * @param mf the filter that determines the methods to apply the callback to@b@ */@b@public static void doWithMethods(Class> clazz, MethodCallback mc, MethodFilter mf)@b@throws IllegalArgumentException {@b@@b@// Keep backing up the inheritance hierarchy.@b@Method[] methods = clazz.getDeclaredMethods();@b@for (Method method : methods) {@b@if (mf != null && !mf.matches(method)) {@b@continue;@b@}@b@try {@b@mc.doWith(method);@b@}@b@catch (IllegalAccessException ex) {@b@throw new IllegalStateException("Shouldn't be illegal to access method '" + method.getName()@b@+ "': " + ex);@b@}@b@}@b@if (clazz.getSuperclass() != null) {@b@doWithMethods(clazz.getSuperclass(), mc, mf);@b@}@b@else if (clazz.isInterface()) {@b@for (Class> superIfc : clazz.getInterfaces()) {@b@doWithMethods(superIfc, mc, mf);@b@}@b@}@b@}@b@@b@/**@b@ * Get all declared methods on the leaf class and all superclasses. Leaf@b@ * class methods are included first.@b@ */@b@public static Method[] getAllDeclaredMethods(Class> leafClass) throws IllegalArgumentException {@b@final List methods = new ArrayList(32);@b@doWithMethods(leafClass, new MethodCallback() {@b@public void doWith(Method method) {@b@methods.add(method);@b@}@b@});@b@return methods.toArray(new Method[methods.size()]);@b@}@b@@b@/**@b@ * Get the unique set of declared methods on the leaf class and all superclasses. Leaf@b@ * class methods are included first and while traversing the superclass hierarchy any methods found@b@ * with signatures matching a method already included are filtered out.@b@ */@b@public static Method[] getUniqueDeclaredMethods(Class> leafClass) throws IllegalArgumentException {@b@final List methods = new ArrayList(32);@b@doWithMethods(leafClass, new MethodCallback() {@b@public void doWith(Method method) {@b@boolean knownSignature = false;@b@Method methodBeingOverriddenWithCovariantReturnType = null;@b@@b@for (Method existingMethod : methods) {@b@if (method.getName().equals(existingMethod.getName()) &&@b@Arrays.equals(method.getParameterTypes(), existingMethod.getParameterTypes())) {@b@// is this a covariant return type situation?@b@if (existingMethod.getReturnType() != method.getReturnType() &&@b@existingMethod.getReturnType().isAssignableFrom(method.getReturnType())) {@b@methodBeingOverriddenWithCovariantReturnType = existingMethod;@b@} else {@b@knownSignature = true;@b@}@b@break;@b@}@b@}@b@if (methodBeingOverriddenWithCovariantReturnType != null) {@b@methods.remove(methodBeingOverriddenWithCovariantReturnType);@b@}@b@if (!knownSignature && !isCglibRenamedMethod(method)) {@b@methods.add(method);@b@}@b@}@b@});@b@return methods.toArray(new Method[methods.size()]);@b@}@b@@b@/**@b@ * Invoke the given callback on all fields in the target class, going up the@b@ * class hierarchy to get all declared fields.@b@ * @param clazz the target class to analyze@b@ * @param fc the callback to invoke for each field@b@ */@b@public static void doWithFields(Class> clazz, FieldCallback fc) throws IllegalArgumentException {@b@doWithFields(clazz, fc, null);@b@}@b@@b@/**@b@ * Invoke the given callback on all fields in the target class, going up the@b@ * class hierarchy to get all declared fields.@b@ * @param clazz the target class to analyze@b@ * @param fc the callback to invoke for each field@b@ * @param ff the filter that determines the fields to apply the callback to@b@ */@b@public static void doWithFields(Class> clazz, FieldCallback fc, FieldFilter ff)@b@throws IllegalArgumentException {@b@@b@// Keep backing up the inheritance hierarchy.@b@Class> targetClass = clazz;@b@do {@b@Field[] fields = targetClass.getDeclaredFields();@b@for (Field field : fields) {@b@// Skip static and final fields.@b@if (ff != null && !ff.matches(field)) {@b@continue;@b@}@b@try {@b@fc.doWith(field);@b@}@b@catch (IllegalAccessException ex) {@b@throw new IllegalStateException(@b@"Shouldn't be illegal to access field '" + field.getName() + "': " + ex);@b@}@b@}@b@targetClass = targetClass.getSuperclass();@b@}@b@while (targetClass != null && targetClass != Object.class);@b@}@b@@b@/**@b@ * Given the source object and the destination, which must be the same class@b@ * or a subclass, copy all fields, including inherited fields. Designed to@b@ * work on objects with public no-arg constructors.@b@ * @throws IllegalArgumentException if the arguments are incompatible@b@ */@b@public static void shallowCopyFieldState(final Object src, final Object dest) throws IllegalArgumentException {@b@if (src == null) {@b@throw new IllegalArgumentException("Source for field copy cannot be null");@b@}@b@if (dest == null) {@b@throw new IllegalArgumentException("Destination for field copy cannot be null");@b@}@b@if (!src.getClass().isAssignableFrom(dest.getClass())) {@b@throw new IllegalArgumentException("Destination class [" + dest.getClass().getName()@b@+ "] must be same or subclass as source class [" + src.getClass().getName() + "]");@b@}@b@doWithFields(src.getClass(), new FieldCallback() {@b@public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {@b@makeAccessible(field);@b@Object srcValue = field.get(src);@b@field.set(dest, srcValue);@b@}@b@}, COPYABLE_FIELDS);@b@}@b@@b@@b@/**@b@ * Action to take on each method.@b@ */@b@public interface MethodCallback {@b@@b@/**@b@ * Perform an operation using the given method.@b@ * @param method the method to operate on@b@ */@b@void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;@b@}@b@@b@@b@/**@b@ * Callback optionally used to filter methods to be operated on by a method callback.@b@ */@b@public interface MethodFilter {@b@@b@/**@b@ * Determine whether the given method matches.@b@ * @param method the method to check@b@ */@b@boolean matches(Method method);@b@}@b@@b@@b@/**@b@ * Callback interface invoked on each field in the hierarchy.@b@ */@b@public interface FieldCallback {@b@@b@/**@b@ * Perform an operation using the given field.@b@ * @param field the field to operate on@b@ */@b@void doWith(Field field) throws IllegalArgumentException, IllegalAccessException;@b@}@b@@b@@b@/**@b@ * Callback optionally used to filter fields to be operated on by a field callback.@b@ */@b@public interface FieldFilter {@b@@b@/**@b@ * Determine whether the given field matches.@b@ * @param field the field to check@b@ */@b@boolean matches(Field field);@b@}@b@@b@@b@/**@b@ * Pre-built FieldFilter that matches all non-static, non-final fields.@b@ */@b@public static FieldFilter COPYABLE_FIELDS = new FieldFilter() {@b@@b@public boolean matches(Field field) {@b@return !(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers()));@b@}@b@};@b@@b@@b@/**@b@ * Pre-built MethodFilter that matches all non-bridge methods.@b@ */@b@public static MethodFilter NON_BRIDGED_METHODS = new MethodFilter() {@b@@b@public boolean matches(Method method) {@b@return !method.isBridge();@b@}@b@};@b@@b@@b@/**@b@ * Pre-built MethodFilter that matches all non-bridge methods@b@ * which are not declared on java.lang.Object
.@b@ */@b@public static MethodFilter USER_DECLARED_METHODS = new MethodFilter() {@b@@b@public boolean matches(Method method) {@b@return (!method.isBridge() && method.getDeclaringClass() != Object.class);@b@}@b@};@b@@b@}