基于反射进行对象属性的拷贝_JAVA_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > JAVA > 基于反射进行对象属性的拷贝

基于反射进行对象属性的拷贝

 2017/11/4 12:21:41  huan1993  程序员俱乐部  我要评论(0)
  • 摘要:在实际的工作中,有时可能存在2个javabean属性之间的拷贝,而如果使用bean之间setter方法进行设置,那么将会存在大量的冗余的代码,因此可以考虑使用反射来进行属性的拷贝操作。大致思路如下:1、从class文件中,获取到所有的public类型的方法2、获取到所有的getter方法和setter方法,getter方法的获取需要考虑到boolean类型这个比较特殊的类型的获取。3、进行属性的拷贝的时候,需要考虑到源对象中的属性值为null,是否应该拷贝到目标对象中4
  • 标签:反射

??? 在实际的工作中,有时可能存在2个java bean属性之间的拷贝,而如果使用bean 之间setter方法进行设置,那么将会存在大量的冗余的代码,因此可以考虑使用反射来进行属性的拷贝操作。

大致思路如下:

1、从class文件中,获取到所有的public类型的方法

2、获取到所有的getter方法和setter方法,getter方法的获取需要考虑到boolean类型这个比较特殊的类型的获取。

3、进行属性的拷贝的时候,需要考虑到源对象中的属性值为null,是否应该拷贝到目标对象中

4、一个class文件中的getter和setter方法一般都是不可变的,因此需要进行缓存起来,避免每次都进行获取。

一、编写BeanUtils工具类,实现拷贝

/**
 * bean 之间的属性的复制.
 * 
 * @描述
 * @作者 huan
 * @时间 2017年11月4日 - 上午11:25:26
 */
public final class BeanUtils {

	private static final ConcurrentHashMap<Class<?>, List<Method>> CACHE_CLASS_GET_METHOD = new ConcurrentHashMap<>();
	private static final ConcurrentHashMap<Class<?>, List<Method>> CACHE_CLASS_SET_METHOD = new ConcurrentHashMap<>();

	private BeanUtils() {
	}

	/**
	 * 将src java bean的属性拷贝到 tar java bean的属性中,默认不拷贝src对象中的空对象的值.
	 *
	 * @param src
	 *            源对象
	 * @param tar
	 *            目标对象
	 */
	public static void copyProperties(Object src, Object tar) {
		copyProperties(src, tar, true);
	}

	/**
	 * 将src java bean的属性拷贝到 tar java bean的属性中
	 *
	 * @param src
	 *            源对象
	 * @param tar
	 *            目标对象
	 * @param skipEmpty
	 *            如果src中属性的值时null,是否跳过这个拷贝, true:跳过 false:不跳过
	 */
	public static void copyProperties(Object src, Object tar, boolean skipEmpty) {
		List<Method> getterMethods = getGetMethod(src.getClass());
		List<Method> setterMethods = getSetMethod(tar.getClass());
		try {
			for (Method getMethod : getterMethods) {
				Object value = getMethod.invoke(src);
				if (skipEmpty && value == null) {
					continue;
				}
				Method method = setterMethods.stream().filter(m -> Objects.equals(m.getName(), getInvokedSetterMethodName(getMethod.getName()))).findFirst().orElse(null);
				if (null != method) {
					method.invoke(tar, value);
				}
			}
		} catch (IllegalAccessException | InvocationTargetException e) {
			throw new RuntimeException("bean复制属性过程中产生异常", e);
		}
	}

	/**
	 * 根据getter的方法名拿到setter的方法名
	 *
	 * @param getterMethodName
	 *            getter的方法名
	 * @return setter的方法名
	 */
	public static String getInvokedSetterMethodName(String getterMethodName) {
		if (getterMethodName.startsWith("get")) {
			return "set" + getterMethodName.substring(3);
		} else {
			return "set" + getterMethodName.substring(2);
		}
	}

	/**
	 * 获取clazz中的所有public getter 方法
	 *
	 * @param clazz
	 *            需要获取getter方法的类
	 * @return public getter方法
	 */
	public static List<Method> getGetMethod(Class<?> clazz) {
		Class<?> lockClazz = clazz;
		if (!CACHE_CLASS_GET_METHOD.containsKey(clazz)) {
			synchronized (lockClazz) {
				if (!CACHE_CLASS_GET_METHOD.containsKey(clazz)) {
					CACHE_CLASS_GET_METHOD.put(clazz, Arrays.stream(getMethods(clazz)).filter(BeanUtils::isGetterMethod).filter(m -> !Objects.equals(m.getName(), "getClass")).collect(Collectors.toList()));
				}
			}
		}
		return CACHE_CLASS_GET_METHOD.get(clazz);
	}

	/**
	 * 获取clazz中的所有public setter 方法
	 *
	 * @param clazz
	 *            需要获取setter方法的类
	 * @return public setter方法
	 */
	public static List<Method> getSetMethod(Class<?> clazz) {
		Class<?> lockClazz = clazz;
		if (!CACHE_CLASS_SET_METHOD.containsKey(clazz)) {
			synchronized (lockClazz) {
				if (!CACHE_CLASS_SET_METHOD.containsKey(clazz)) {
					CACHE_CLASS_SET_METHOD.put(clazz, Arrays.stream(getMethods(clazz)).filter(BeanUtils::isSetterMethod).collect(Collectors.toList()));
				}
			}
		}
		return CACHE_CLASS_SET_METHOD.get(clazz);
	}

	/**
	 * 获取一个类中中的所有的方法
	 *
	 * @param clazz
	 * @return
	 */
	public static Method[] getMethods(Class<?> clazz) {
		return clazz.getMethods();
	}

	/**
	 * 判断一个方式是否是getter方法
	 *
	 * @param method
	 *            需要判断的方法
	 * @return true:是getter方法 false:不是getter方法
	 */
	public static boolean isGetterMethod(Method method) {
		if (method.getName().startsWith("get") && method.getParameterCount() == 0 && method.getReturnType() != Void.class) {
			return true;
		} else if (method.getName().startsWith("is") && method.getParameterCount() == 0 && (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class))) {
			return true;
		}
		return false;
	}

	/**
	 * 判断是否是setter方法
	 *
	 * @param method
	 *            需要判断的方法
	 * @return true是setter方法 false不是setter方法
	 */
	public static boolean isSetterMethod(Method method) {
		boolean isSetter = false;
		if (method.getName().startsWith("set") && method.getParameterCount() == 1 && method.getReturnType() != Void.class) {
			isSetter = true;
		}
		return isSetter;
	}
}

?二、测试

?? 1、编写一个实体类 SysResource

/**
 * 资源实体类
 * 
 * @描述
 * @作者 huan
 * @时间 2017年11月4日 - 上午11:26:46
 */
@Data
public class SysResource {
	private String id;
	private String pid;
	private String name;
	private String url;
	private Integer type;
	private Date createTime;
}

?? 2、编写测试代码

?

?

  • 大小: 84.8 KB
  • 查看图片附件
发表评论
用户名: 匿名