這裏使用的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;
}
}