详细分析Java中的BeanCopier属性复制(附Demo)

本文详细介绍了BeanCopier库在Java中如何进行对象属性复制,包括其优点、适用场景、示例演示以及在实际项目中的运用,如处理浅拷贝、深拷贝和不同类型对象的复制需求。
摘要由CSDN通过智能技术生成

前言

基本知识推荐阅读:

  1. 浅拷贝和深拷贝的深度理解
  2. java框架 零基础从入门到精通的学习路线 附开源项目面经等(超全)
  3. 【Java项目】实战CRUD的功能整理(持续更新)

1. 基本知识

BeanCopier是一个Java库,用于在Java Bean之间进行属性复制,它可以自动将一个Java Bean对象的属性值复制到另一个Java Bean对象中,而无需手动编写属性复制的代码

作用优点缺点
简化属性复制: BeanCopier能够自动将一个Java Bean对象的属性值复制到另一个Java Bean对象中,省去了手动编写属性复制代码的繁琐工作

提高效率: 由于BeanCopier利用了反射机制,因此能够实现高效的属性复制,避免了手动编写大量的getter和setter方法的耗时工作

灵活性: BeanCopier可以根据需求灵活地配置属性复制的行为,例如可以选择性地复制某些属性,或者自定义属性复制的规则
简单易用: BeanCopier提供了简单易用的API,使得属性复制变得非常简单

高效性能: 利用了反射机制,能够实现高效的属性复制,提高了程序的执行效率

灵活性: 可以根据需求灵活配置属性复制的行为,使得其适用于各种不同的场景
不支持复杂属性: BeanCopier虽然能够处理简单的属性复制,但是对于复杂的属性,例如嵌套对象或集合对象,可能需要额外的处理

不支持类型转换: BeanCopier在属性复制时不支持类型转换,如果源对象和目标对象的属性类型不一致,可能需要额外的类型转换处理

不支持属性名称不同的情况: 如果源对象和目标对象的属性名称不一致,BeanCopier无法自动匹配属性,需要手动指定属性映射关系

2. 同属性Demo

package com.example.test;

import org.springframework.cglib.beans.BeanCopier;

public class test {
    static class SourceBean {
        private String name;
        private int age;

        // getters and setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public int getAge() { return age; }
        public void setAge(int age) { this.age = age; }
    }

    static class TargetBean {
        private String name;
        private int age;

        // getters and setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public int getAge() { return age; }
        public void setAge(int age) { this.age = age; }
    }

    public static void main(String[] args) {
        // 创建BeanCopier对象
        BeanCopier copier = BeanCopier.create(SourceBean.class, TargetBean.class, false);

        // 创建源对象
        SourceBean source = new SourceBean();
        source.setName("码农研究僧");
        source.setAge(18);

        // 创建目标对象
        TargetBean target = new TargetBean();

        // 属性复制
        copier.copy(source, target, null);

        // 打印目标对象属性值
        System.out.println("Name: " + target.getName()); // 输出:Name: John
        System.out.println("Age: " + target.getAge());   // 输出:Age: 30
    }
}

截图如下:

在这里插入图片描述

3. 不同属性Demo

这是不同属性,但不需要转换的Demo

package com.example.test;


import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

// 定义一个源对象类
class CheckOrder implements Serializable {
    private String orderId;

    public CheckOrder() {
    }

    public CheckOrder(String orderId) {
        this.orderId = orderId;
    }

    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }
}

// 定义一个目标对象类,继承自源对象类
class CheckOrderVO extends CheckOrder implements Serializable {
    private String orderName;

    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String orderName) {
        this.orderName = orderName;
    }
}

// 模拟BeanUtil工具类
class BeanUtil {
    private static final Map<BeanCopierKey, BeanCopier> BEAN_COPIER_MAP = new HashMap<>();

    public static <T> T copy(Object source, Class<T> clazz) {
        return source == null ? null : copy(source, source.getClass(), clazz);
    }

    public static <T> T copy(Object source, Class sourceClazz, Class<T> targetClazz) {
        if (source == null) {
            return null;
        } else {
            BeanCopier copier = BeanCopier.create(sourceClazz, targetClazz, false);
            T to = newInstance(targetClazz);
            copier.copy(source, to, null);
            return to;
        }
    }

    public static <T> T newInstance(Class<T> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

// 模拟BeanCopier类
class BeanCopier {
    public static BeanCopier create(Class source, Class target, boolean useConverter) {
        return create(source, target, useConverter, false);
    }

    public static BeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) {
        return new BeanCopier();
    }

    public void copy(Object source, Object target, Object converter) {
        if (source == null || target == null) {
            throw new IllegalArgumentException("Source and target objects cannot be null.");
        }

        Field[] sourceFields = source.getClass().getDeclaredFields();
        Field[] targetFields = target.getClass().getDeclaredFields();

        Map<String, Field> targetFieldMap = new HashMap<>();
        for (Field sourceField : sourceFields) {
            sourceField.setAccessible(true);
            targetFieldMap.put(sourceField.getName(), sourceField);
        }

        for (Field sourceField : sourceFields) {
            sourceField.setAccessible(true);
            Field targetField = targetFieldMap.get(sourceField.getName());
            if (targetField != null && sourceField.getType().equals(targetField.getType())) {
                try {
                    Object value = sourceField.get(source);
                    targetField.set(target, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println("Copying from " + source + " to " + target);
    }


}

class BeanCopierKey {
    private Class<?> source;
    private Class<?> target;
    private boolean useConverter;
    private boolean nonNull;

    public BeanCopierKey(Class<?> source, Class<?> target, boolean useConverter, boolean nonNull) {
        this.source = source;
        this.target = target;
        this.useConverter = useConverter;
        this.nonNull = nonNull;
    }

    public Class<?> getSource() {
        return source;
    }

    public Class<?> getTarget() {
        return target;
    }

    public boolean isUseConverter() {
        return useConverter;
    }

    public boolean isNonNull() {
        return nonNull;
    }
}

public class Demo {
    public static void main(String[] args) {
        // 创建一个源对象
        CheckOrder checkOrder = new CheckOrder("12345");

        // 使用BeanUtil进行对象拷贝
        CheckOrderVO checkOrderVOCopy = BeanUtil.copy(checkOrder, CheckOrderVO.class);

        // 手动设置目标对象的属性
        checkOrderVOCopy.setOrderName("码农研究僧");

        // 输出拷贝后的目标对象的属性值
        System.out.println("Copied order ID: " + checkOrderVOCopy.getOrderId());
        // 因为目标对象类继承自源对象类,所以也可以访问源对象的属性
        System.out.println("Copied order name: " + checkOrderVOCopy.getOrderName());
    }
}

截图如下:

在这里插入图片描述

如果需要用到转换,可以看如下函数:

class BeanCopier {
    public static BeanCopier create(Class source, Class target, boolean useConverter) {
        return create(source, target, useConverter, false);
    }
    public static BeanCopier create(Class source, Class target, boolean useConverter, boolean nonNull) {
        return new BeanCopier();
    }
    public void copy(Object source, Object target, Object converter) {
        if (source == null || target == null) {
            throw new IllegalArgumentException("Source and target objects cannot be null.");
        }
        Field[] sourceFields = source.getClass().getDeclaredFields();
        Field[] targetFields = target.getClass().getDeclaredFields();

        Map<String, Field> targetFieldMap = new HashMap<>();
        for (Field targetField : targetFields) {
            targetField.setAccessible(true);
            targetFieldMap.put(targetField.getName(), targetField);
        }
		
		// 修改变动位置
        Converter customConverter = (Converter) converter;

        for (Field sourceField : sourceFields) {
            sourceField.setAccessible(true);
            Field targetField = targetFieldMap.get(sourceField.getName());
            if (targetField != null && sourceField.getType().equals(targetField.getType())) {
                try {
                    Object value = sourceField.get(source);
                    
                    // 修改变动位置
                    if (customConverter != null) {
                        value = customConverter.convert(value, targetField.getType(), null);
                    }
                    
                    targetField.set(target, value);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("Copying from " + source + " to " + target);
    }
}

4. 实战场景

实战中的运用如下:

数据库的字段等都建立好了,并且其实体类如下:

在这里插入图片描述

使用过程中,可能还需要添加额外的字段,但又不影响到数据库,只想显示在前端而已,可以通过如下

在这里插入图片描述

最后结合工具类来复刻整个数据库拥有的属性,并添加新的字段值,并返回给前端操作

在这里插入图片描述

  • 41
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农研究僧

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值