基於Cglib的高效copy工具類

這裏使用的cglib是spring core包的。

import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.support.DefaultConversionService;

import java.util.*;

/**
 * <p>使用Cglib高效的複製對象,不使用Spring的BeanCopy,支持類型互相轉換。
 * 如果轉換失敗會拋出{@link ConversionFailedException}異常。
 * 這裏的{@link org.springframework.cglib.beans.BeanCopier}
 * 是spring-core包裏集成的,不需要單獨引入Cglib依賴包。
 * <br/>注意:對象使用了Lombok註解時,不要有{@link Accessors}註解,否則無法複製。
 * </p>
 * <code>
 *
 * </code>
 * @author chengjz
 * @version 1.0
 * @date 2020-04-01 14:46
 */
@Slf4j
public class FastCopy {
	private static final DefaultConversionService conversionService = new DefaultConversionService();
	public static final DefaultConverter converter = new DefaultConverter();

	public static Map<String, BeanCopier> CACHE_MAP = new HashMap<>();

	public static void addBothWayBeanCopy(Class<?> clz1, Class<?> clz2) {
		addBothWayBeanCopy(clz1, clz2, true);
	}

	public static void addBothWayBeanCopy(Class<?> clz1, Class<?> clz2, boolean useConverter) {
		CACHE_MAP.put(buildCacheKey(clz1, clz2), BeanCopier.create(clz1, clz2, useConverter));
		CACHE_MAP.put(buildCacheKey(clz2, clz1), BeanCopier.create(clz2, clz1, useConverter));
	}

	/**
	 * 複製單個對象
	 * @param form 源對象
	 * @param to 複製的對象
	 * @param <T>  複製對象類型
	 * @return 複製對象實例
	 */
	public static <T> T copy(Object form, Class<T> to) {
		return copy(form, to, converter);
	}

	/**
	 * 複製單個對象,自定義類型轉換器,除非有必要,否則請使用{@link #copy(Object, Class)}方法
	 * @param form 源對象
	 * @param to 複製的對象
	 * @param converter 類型轉換器
	 * @param <T>  複製對象類型
	 * @return 複製對象實例
	 */
	public static <T> T copy(Object form, Class<T> to, Converter converter) {
		T targetSource = null;
		try {
			targetSource = to.newInstance();
		} catch (Exception e) {
			log.error("創建對象發生異常: ", e);
		}
		return copy(form, to, targetSource, converter);
	}


	/**
	 * 複製對象列表
	 * @param formList 源對象列表
	 * @param to 複製的對象
	 * @param <T>  複製對象類型
	 * @return 複製對象實例列表
	 */
	public static <F, T> List<T> listCopy(List<F> formList, Class<T> to) {
		List<T> toList = new ArrayList<>(formList.size());
		formList.forEach(v -> {
			toList.add(copy(v, to));
		});
		return toList;
	}


	public static<T> T copy(Object form, Class<?> to, T targetSource, Converter converter) {
		if (form == null) {
			return targetSource;
		}
		final Class<?> formClass = form.getClass();
		String cacheKey = buildCacheKey(formClass, to);
		if (!CACHE_MAP.containsKey(cacheKey)) {
			addBothWayBeanCopy(formClass, to);
		}
		CACHE_MAP.get(cacheKey).copy(form, targetSource, converter);
		return targetSource;
	}

	private static String buildCacheKey(Class<?> clz1, Class<?> clz2) {
		return clz1.getName() + "_" + clz2.getName();
	}

	public static class DefaultConverter implements Converter {
		@Override
		public Object convert(Object source, Class target, Object context) {
			if (source == null) {
				return null;
			}
			if (isJavaClass(target) || source instanceof Collection<?> || source instanceof Map<?,?>) {
				return conversionService.convert(source, target);
			}
			return copy(source, target);
		}
	}

	public static boolean isJavaClass(Class<?> clz) {
		return clz != null && clz.getClassLoader() == null;
	}

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章