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@ * <p>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 <code>name</code>. 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 <code>null</code> 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 <code>name</code> 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 <code>null</code> if type is specified)@b@ * @param type the type of the field (may be <code>null</code> if name is specified)@b@ * @return the corresponding Field object, or <code>null</code> 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 <code>value</code>.@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@ * <p>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 <code>null</code>@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@ * <p>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 <code>Object</code>.@b@ * <p>Returns <code>null</code> 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 <code>null</code> 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 <code>Object</code>.@b@ * <p>Returns <code>null</code> 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 <code>null</code> to indicate any signature)@b@ * @return the Method object, or <code>null</code> 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 <code>null</code> when invoking a static {@link Method}.@b@ * <p>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 <code>null</code> when invoking a@b@ * static {@link Method}.@b@ * <p>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 <code>null</code>)@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 <code>null</code>)@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@ * <p>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@ * <p>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@ * <em>target exception</em> of an {@link InvocationTargetException}. Should@b@ * only be called if no checked exception is expected to be thrown by the@b@ * target method.@b@ * <p>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@ * <em>target exception</em> of an {@link InvocationTargetException}. Should@b@ * only be called if no checked exception is expected to be thrown by the@b@ * target method.@b@ * <p>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 <code>true</code> if the exception can be thrown as-is;@b@ * <code>false</code> 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 <code>setAccessible(true)</code> 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 <code>setAccessible(true)</code> 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 <code>setAccessible(true)</code> 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@ * <p>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@ * <p>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<Method> methods = new ArrayList<Method>(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<Method> methods = new ArrayList<Method>(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 <code>java.lang.Object</code>.@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@}