在Java中常见的对象拷贝方式是使用cglib,Cglib的性能是目前公认最好的,用于解决Bean拷贝的性能问题
下面是以cglib封装的工具类实现对象和集合的拷贝
一、引入依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
<scope>compile</scope>
</dependency>
二、创建CglibUtil工具类
其中包含对象和集合的拷贝,还封装了Bean转Map的方法
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import net.sf.cglib.beans.BeanCopier;
import net.sf.cglib.beans.BeanMap;
import net.sf.cglib.core.Converter;
import java.util.Collection;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* @author YangBoss
* @title: CglibUtil
* @projectName frontop-ao
* @description: CglibUtil工具类
* @date 2022/6/2 10:18
*/
public class CglibUtil {
/**
* 拷贝Bean对象属性到目标类型<br>
* 此方法通过指定目标类型自动创建之,然后拷贝属性
*
* @param <T> 目标对象类型
* @param source 源bean对象
* @param targetClass 目标bean类,自动实例化此对象
* @return 目标对象
*/
public static <T> T copy(Object source, Class<T> targetClass) {
return copy(source, targetClass, null);
}
/**
* 拷贝Bean对象属性<br>
* 此方法通过指定目标类型自动创建之,然后拷贝属性
*
* @param <T> 目标对象类型
* @param source 源bean对象
* @param targetClass 目标bean类,自动实例化此对象
* @param converter 转换器,无需可传{@code null}
* @return 目标对象
*/
public static <T> T copy(Object source, Class<T> targetClass, Converter converter) {
final T target = ReflectUtil.newInstanceIfPossible(targetClass);
copy(source, target, converter);
return target;
}
/**
* 拷贝Bean对象属性
*
* @param source 源bean对象
* @param target 目标bean对象
*/
public static void copy(Object source, Object target) {
copy(source, target, null);
}
/**
* 拷贝Bean对象属性
*
* @param source 源bean对象
* @param target 目标beBeanCopierCachean对象
* @param converter 转换器,无需可传{@code null}
*/
public static void copy(Object source, Object target, Converter converter) {
Assert.notNull(source, "Source bean must be not null.");
Assert.notNull(target, "Target bean must be not null.");
final Class<?> sourceClass = source.getClass();
final Class<?> targetClass = target.getClass();
boolean conIsNull = converter == null ? false : true;
final BeanCopier beanCopier = BeanCopier.create(sourceClass, targetClass, conIsNull);
beanCopier.copy(source, target, converter);
}
/**
* 拷贝List Bean对象属性
*
* @param <S> 源bean类型
* @param <T> 目标bean类型
* @param source 源bean对象list
* @param target 目标bean对象
* @return 目标bean对象list
*/
public static <S, T> List<T> copyList(Collection<S> source, Supplier<T> target) {
return copyList(source, target, null, null);
}
/**
* 拷贝List Bean对象属性
*
* @param source 源bean对象list
* @param target 目标bean对象
* @param converter 转换器,无需可传{@code null}
* @param <S> 源bean类型
* @param <T> 目标bean类型
* @return 目标bean对象list
* @since 5.4.1
*/
public static <S, T> List<T> copyList(Collection<S> source, Supplier<T> target, Converter converter) {
return copyList(source, target, converter, null);
}
/**
* 拷贝List Bean对象属性
*
* @param source 源bean对象list
* @param target 目标bean对象
* @param callback 回调对象
* @param <S> 源bean类型
* @param <T> 目标bean类型
* @return 目标bean对象list
* @since 5.4.1
*/
public static <S, T> List<T> copyList(Collection<S> source, Supplier<T> target, BiConsumer<S, T> callback) {
return copyList(source, target, null, callback);
}
/**
* 拷贝List Bean对象属性
*
* @param source 源bean对象list
* @param target 目标bean对象
* @param converter 转换器,无需可传{@code null}
* @param callback 回调对象
* @param <S> 源bean类型
* @param <T> 目标bean类型
* @return 目标bean对象list
*/
public static <S, T> List<T> copyList(Collection<S> source, Supplier<T> target, Converter converter, BiConsumer<S, T> callback) {
return source.stream().map(s -> {
T t = target.get();
copy(s, t, converter);
if (callback != null) {
callback.accept(s, t);
}
return t;
}).collect(Collectors.toList());
}
/**
* 将Bean转换为Map
*
* @param bean Bean对象
* @return {@link BeanMap}
* @since 5.4.1
*/
public static BeanMap toMap(Object bean) {
return BeanMap.create(bean);
}
}
三、测试拷贝对象和集合
拷贝对象测试,再将拷贝的对象和源对象放入集合中对拷贝集合测试
public static void main(String[] args) {
/**
* 拷贝对象
*/
//创建对象
TUser tUser = new TUser();
tUser.setName("李四");
//拷贝对象
TUser tUser2 = CglibUtil.copy(tUser,TUser.class);
//打印结果
System.out.println(tUser2.getName());
/**
* 拷贝集合
*/
//创建集合
List<TUser> list1 = new ArrayList<>();
list1.add(tUser);
list1.add(tUser2);
//拷贝集合
List<TUser> list2 = CglibUtil.copyList(list1,TUser::new);
//打印结果
System.out.println(JSONObject.toJSONString(list2));
}
结果打印
四、注意点
CglibUtil.copy拷贝对象的时候,目标对象被lombok注解@Accessors(chain = true)修饰报空指针
在拷贝对象上不可用注解 @Accessors ,反射获取不到对应的setter,因为这个链式生成的代码带了返回值,此注解会将set方法返回值改变