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();
        }
    }
}


相关文章
|
消息中间件 存储 监控
云消息队列 RocketMQ 版(原ONS)体验
云消息队列 RocketMQ 版(原ONS)是阿里云基于 Apache RocketMQ 构建的低延迟、高并发、高可用、高可靠的分布式“消息、事件、流”统一处理平台。它在阿里集团内部业务、阿里云以及开源社区中得到广泛应用。最新的版本进一步优化了高可靠低延迟的特性,并提供了多场景容灾解决方案,使其成为金融级业务消息的首选方案。由于专业及能力问题,本次我只能从产品功能体验方面进行简单的一些分析。
1904 64
|
JSON Java API
玩转Spring Boot之RestTemplate的使用
在java代码里想要进行restful web client服务,一般使用Apache的HttpClient。不过此种方法使用起来太过繁琐。Spring Boot提供了一种简单便捷的内置模板类来进行操作,这就是RestTemplate。
6178 0
|
2月前
|
人工智能 定位技术 API
智能体(Agent):AI不再只是聊天,而是能替你干活
智能体(Agent):AI不再只是聊天,而是能替你干活
933 99
|
10月前
|
机器学习/深度学习 人工智能 算法
DeepSeek:掀翻互联网底层的“东方神秘力量” ——当AI大模型成为网络世界的“基建狂魔”
DeepSeek正重构网络底层逻辑,从“哑管道”到“认知神经”,赋予网络思考能力。它通过意图驱动和认知架构,优化带宽资源,提升效率。技术上,MOE+MLA架构与FP8精度训练大幅降低成本,性能超越传统模型。产业链方面,通信巨头转型为“AI驯兽师”,推出智能预测、定制化网络等服务。然而,AI基建也面临安全挑战,如僵尸网络攻击和隐私问题。展望6G,AGI将成新“网络原住民”,带来更智能的服务。这场变革不仅提升了连接效率,还创造了更多价值。
|
安全 API 开发者
如何遵守孔夫子旧书网的使用规则?
使用孔夫子旧书网需先注册并认证,获得API权限后,须遵守API调用协议,包括正确使用公共参数及业务参数。平台强调版权保护、用户隐私权及免责声明,同时要求用户遵守法律法规,确保信息安全合规。遇技术问题可寻求官方支持。
|
敏捷开发 存储 数据管理
自动化测试框架设计:从理论到实践
【7月更文挑战第13天】本文将深入探讨自动化测试框架的设计原理与实现方法。通过分析自动化测试的必要性和框架设计的基本原则,结合具体案例,展示如何从零开始构建一个高效、可维护的自动化测试系统。文章不仅涵盖框架的结构设计,还包括最佳实践和常见问题的解决策略,为读者提供一套完整的解决方案和实操指南。
|
缓存 算法 安全
【Java对象拷贝机制】使用CGlib实现Bean拷贝(BeanCopier)
【Java对象拷贝机制】使用CGlib实现Bean拷贝(BeanCopier)
769 0
【Java对象拷贝机制】使用CGlib实现Bean拷贝(BeanCopier)
|
存储 算法 定位技术
ElasticSearch 之 数据类型
ElasticSearch 之 数据类型
881 0
实战:第四章:java后端日志埋点实现
实战:第四章:java后端日志埋点实现
1460 0
实战:第四章:java后端日志埋点实现