BeanCopier的使用

简介: BeanCopier的使用
选择Cglib的BeanCopier进行Bean拷贝的理由是,
其性能要比Spring的BeanUtils,Apache的BeanUtils和PropertyUtils要好很多,
尤其是数据量比较大的情况下。
package cn.dearth.common.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import static org.junit.jupiter.api.Assertions.*;
class BeanCopyUtilsTest {
    /**
     * 测试说明: 类型不同BeanCopier不会拷贝
     */
    @Test
    void copy() {
        User user = new User();
        user.setId(1);
        user.setName("dearth");
        BeanCopier copier = BeanCopier.create(User.class, UserVo.class, false);
        UserVo userVo = new UserVo();
        copier.copy(user, userVo, null);
        Assertions.assertNull(userVo.getId());
    }
    /**
     * 测试说明: 提供转换器可以实现不同类型的拷贝
     */
    @Test
    void copyUseConverter() {
        User user = new User();
        user.setId(1);
        user.setName("dearth");
        user.setCreateTime(new Timestamp(10043143243L));
        user.setBalance(BigDecimal.valueOf(4000L));
        BeanCopier copier = BeanCopier.create(User.class, UserVo.class, true);
        UserVo vo = new UserVo();
        copier.copy(user, vo, new UserConverter());
        Assertions.assertNotNull(vo.getCreateTime());
        Assertions.assertNotNull(vo.getBalance());
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static
    class User {
        private String name;
        private int id;
        private Timestamp createTime;
        private BigDecimal balance;
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static
    class UserVo {
        private String name;
        private Integer id;
        private String createTime;
        private String balance;
    }
    static class UserConverter implements Converter {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        @Override
        public Object convert(Object o, Class aClass, Object o1) {
            if (o instanceof Integer) {
                return (Integer) o;
            } else if (o instanceof Timestamp) {
                Timestamp data = (Timestamp) o;
                return sdf.format(data);
            } else if (o instanceof BigDecimal) {
                BigDecimal bg = (BigDecimal) o;
                return bg.toPlainString();
            } else {
                 return null;
            }
        }
    }
}
总结
  1. BeanCopier只拷贝名称和类型都相同的属性。
  2. 当目标类的setter数目比getter少时,创建BeanCopier会失败而导致拷贝不成功。
  3. 自定义Converter转换器可以转换不同类型的属性

工具类

package cn.dearth.common.utils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.SimpleCache;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class BeanCopyUtils {
    /**
     * 单对象基于对象创建拷贝
     *
     * @param source 数据来源实体
     * @param desc   转换后的对象
     * @return desc
     */
    public static <T, V> V copy(T source, V desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        BeanCopier beanCopier = BeanCopierCache.INSTANCE.get(source.getClass(), desc.getClass(), null);
        beanCopier.copy(source, desc, null);
        return desc;
    }
    /**
     * 单对象基于class创建拷贝
     *
     * @param source 数据来源实体
     * @param desc   描述对象 转换后的对象
     * @return desc
     */
    public static <T, V> V copy(T source, Class<V> desc) {
        if (ObjectUtil.isNull(source)) {
            return null;
        }
        if (ObjectUtil.isNull(desc)) {
            return null;
        }
        final V target = ReflectUtil.newInstanceIfPossible(desc);
        return copy(source, target);
    }
    /**
     * 列表对象基于class创建拷贝
     *
     * @param sourceList 数据来源实体列表
     * @param desc       描述对象 转换后的对象
     * @return desc
     */
    public static <T, V> List<V> copyList(List<T> sourceList, Class<V> desc) {
        if (ObjectUtil.isNull(sourceList)) {
            return null;
        }
        if (CollUtil.isEmpty(sourceList)) {
            return CollUtil.newArrayList();
        }
        return sourceList.stream()
                .map(source -> {
                    V target = ReflectUtil.newInstanceIfPossible(desc);
                    copy(source, target);
                    return target;
                }).collect(Collectors.toList());
    }
    public enum BeanCopierCache {
        INSTANCE;
        private final SimpleCache<String, BeanCopier> cache = new SimpleCache<>();
        public BeanCopier get(Class<?> sourceClass, Class<?> targetClass, Converter converter) {
            final String key = genKey(sourceClass, targetClass, converter);
            return cache.get(key, () -> BeanCopier.create(sourceClass, targetClass, converter != null));
        }
        private String genKey(Class<?> sourceClass, Class<?> targetClass, Converter converter) {
            StringBuilder key = StrUtil.builder()
                    .append(sourceClass.getName())
                    .append('#')
                    .append(targetClass.getName());
            Optional.ofNullable(converter)
                    .ifPresent(c -> key.append(c.getClass().getName()));
            return key.toString();
        }
    }
}


相关文章
|
数据库
MybatisPlus中设置自动填充时间@TableField注解的使用
MybatisPlus中设置自动填充时间@TableField注解的使用
855 0
|
前端开发 网络协议 Dubbo
超详细Netty入门,看这篇就够了!
本文主要讲述Netty框架的一些特性以及重要组件,希望看完之后能对Netty框架有一个比较直观的感受,希望能帮助读者快速入门Netty,减少一些弯路。
81361 30
超详细Netty入门,看这篇就够了!
|
缓存 Linux 开发工具
CentOS 7- 配置阿里镜像源
阿里镜像官方地址http://mirrors.aliyun.com/ 1、点击官方提供的相应系统的帮助 :2、查看不同版本的系统操作: 下载源1、安装wget yum install -y wget2、下载CentOS 7的repo文件wget -O /etc/yum.
200505 0
|
6月前
|
并行计算 算法 安全
【C++ 迭代器 】C++ 迭代器标签的使用场景
【C++ 迭代器 】C++ 迭代器标签的使用场景
85 0
|
6月前
|
机器学习/深度学习 JavaScript 前端开发
「译文」如何在 YAML 中输入多行字符串?
「译文」如何在 YAML 中输入多行字符串?
|
JavaScript Windows
Windows安装ElasticSearch
Windows安装ElasticSearch
1775 2
|
存储 缓存 运维
Linux限制磁盘与内存配额【超详细】
Linux限制磁盘与内存配额方法
431 0
|
SQL druid Java
实现SpringBoot项目的多数据源配置的两种方式(dynamic-datasource-spring-boot-starter和自定义注解的方式)
最近项目需要配置多数据源,本项目采用的技术是SpringBoot+mybatis-plus+Druid。为了图个方便直接想直接集成dynamic-datasource-spring-boot-starter进行多数据源配置。
4352 0
实现SpringBoot项目的多数据源配置的两种方式(dynamic-datasource-spring-boot-starter和自定义注解的方式)
|
Java Spring 容器
Aviator和Spring Expression
Aviator和Spring Expression
|
应用服务中间件 nginx
Nginx服务器的反向代理proxy_pass配置方法讲解
 Nginx服务器的反向代理proxy_pass配置方法讲解 这篇文章主要介绍了Nginx服务器的反向代理proxy_pass配置方法讲解,包括经常被提到的url的/问题的相关说明,需要的朋友可以参考下 就普...
5074 0