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

目录

  • 前言
  • 1. 基本知识
  • 2. 同属性Demo
  • 3. 不同属性Demo
  • 4. 实战场景

前言

基本知识推荐阅读:

  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. 实战场景

实战中的运用如下:

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/464572.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PHP魔术方法详解

php魔术方法是一些特殊的方法&#xff0c;由特定的环境来进行触发。 这些魔术方法让开发者能够更好地控制对象的行为&#xff0c;特别是在处理不常见的操作或者需要自动化处理某些任务时非常有用。 1、_construct()构造函数&#xff1a; <?php highlight_file(__FILE__);…

小白DB补全计划Day1-LeetCode:SQL基本操作select

前言&#xff1a;找工作&#xff08;主人&#xff09;的任务罢了 链接&#xff1a;1757. 可回收且低脂的产品 - 力扣&#xff08;LeetCode&#xff09; 584. 寻找用户推荐人 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 对DB篇的SQL章不太知道怎么写…

2023年蓝桥杯省赛——幸运数字

目录 题目链接&#xff1a;0幸运数字 - 蓝桥云课 (lanqiao.cn) 解法 思路 高级思路 总结 题目链接&#xff1a;0幸运数字 - 蓝桥云课 (lanqiao.cn) 解法 首先是我写了差不多一个小时的解法&#xff0c;裂开了&#xff0c;为什么我如此废物 思路 寻找第2023个在二进制、八…

每日一题——LeetCode2789.合并后数组中的最大元素

方法一 倒序遍历&#xff1a; 将数组倒序过来看&#xff0c;就是从最后一个数开始&#xff0c;如果它前面一个数小于等于它就可以把前面一个数吃掉同时加上前一个数的值形成一个新的数&#xff0c;如果碰到一个更大的数就吃不动了&#xff0c;那么就换那个更大的数去继续吃前面…

API接口:获取歌曲、小姐姐图片以及视频

文章目录 前言一、成果展示二、接口演示 1、歌曲2、图片和视频三、创造难点四、总结 前言 上次利用QQ音乐官网做了一个根据qq号获取暗恋人喜欢的歌单以及收藏歌曲&#xff0c;但是感觉功能还是太单薄了&#xff0c;于是我再次利用网上提供的免费API接口补充了一些功能。 一、成…

数据库精通之路:国产GBASE数据库学习网站全攻略

介绍&#xff1a;GBASE是一个包含多种产品的数据库系列&#xff0c;由南大通用数据技术有限公司推出&#xff0c;以其高性能和高可用性在国内数据库市场享有较高的品牌知名度。以下是GBASE系列的主要产品特点&#xff1a; GBase 8a&#xff1a;这是一个面向大数据分析的高性能数…

Unload-labs-pass-03

这里是设置了黑名单不能传.asp.aspx.php.jsp文件 $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(UPLOAD_PATH)) {$deny_ext array(.asp,.aspx,.php,.jsp);$file_name trim($_FILES[upload_file][name]);$file_name deldot($file_name);//删…

vue2+vant2+Laravel7 实现多图上传到七牛云

后端接口 1、路由&#xff0c;在 routes/api.php 中 Route::resource(photos, PhotoController)->only(store);2、创建对应控制器 <?php namespace App\Http\Controllers; use Illuminate\Http\Request;class PhotoController extends Controller {/**** 上传图片* p…

LangChain: 调研报告

概述 LangChain是一个用于开发由语言模型驱动的应用程序的框架。它允许创建能够连接到上下文源&#xff08;如提示指令、少量示例、内容基础等&#xff09;的应用程序&#xff0c;并且能够进行推理&#xff08;基于提供的上下文如何回答问题、采取何种行动等&#xff09;。提供…

最佳实践:Postman 怎么调试 WebSocket

WebSocket 是一个支持双向通信的网络协议&#xff0c;它在实时性和效率方面具有很大的优势。Postman 是一个流行的 API 开发工具&#xff0c;它提供了许多功能来测试和调试 RESTful API 接口&#xff0c;最新的版本也支持 WebSocket 接口的调试。想要学习更多关于 Postman 的知…

力扣24. 两两交换链表中的节点

新建虚拟头节点&#xff0c;用3个指针记录前3个节点&#xff0c;然后再相互赋值指向&#xff0c;再移动当前节点&#xff0c;当前节点所在的位置&#xff0c;只能交换该节点的后两个节点&#xff08;所以必须建立虚拟头节点&#xff0c;才能操作第1&#xff0c;2个节点&#xf…

机器学习——压缩网络作业

文章目录 任务描述介绍知识蒸馏网络设计 Baseline实践 任务描述 网络压缩&#xff1a;使用小模型模拟大模型的预测/准确性。在这个任务中&#xff0c;需要训练一个非常小的模型来完成HW3&#xff0c;即在food-11数据集上进行分类。 介绍 有许多种网络/模型压缩的类型&#xff0…

【静夜思】为什么我们会如此喜欢夜晚呢

作为一名大学生&#xff0c;熬夜对我来说已是常态。每天都是近乎一点钟才有困意&#xff0c;觉得应该上床睡觉了&#xff0c;即使明天早八&#xff0c;即使明天有很多课。我也观察过身边的朋友&#xff0c;他们中大多数也和我一样&#xff0c;基本都是在12点过后才入睡。当今的…

AIGC笔记--关节点6D位姿按比例融合

1--核心代码 6D位姿一般指平移向量和旋转向量&#xff0c;Maya软件中关节点的6D位姿指的是相对平移向量和欧拉旋转向量&#xff1b; 为了按比例融合两个Pose&#xff0c;首先需要将欧拉旋转向量转换为旋转矩阵&#xff0c;在将旋转矩阵转换为四元数&#xff0c;利用球面线性插值…

指针 六 ---总结

文章目录 前言1.指针和指针变量2.const修饰2.1.const int* p 修饰的是指针指向的内容&#xff0c;保证指针指向的内容不能通过指针来改变。但是指针变量本⾝的内容可变。2.2 int const *p2.3 int *const p2.4 const int* const p 3. 指针数组&#xff08;array of pointers&…

彻底学会系列:一、机器学习之梯度下降(1)

1 梯度下降概念 1.1 概念 梯度下降是一种优化算法&#xff0c;用于最小化一个函数的值&#xff0c;特别是用于训练机器学习模型中的参数&#xff0c;其基本思想是通过不断迭代调整参数的值&#xff0c;使得函数值沿着梯度的反方向逐渐减小&#xff0c;直至达到局部或全局最小…

如何在webapp中手动部署

前言&#xff1a;这个有不知道怎么下载Tomcat的可以看我这篇博客的前面&#xff0c;有相关链接&#xff0c;下载好后我那边也有如何运行成功的 在idea中配置tomcat服务器&#xff0c;部署一个项目-CSDN博客 接下来进入这篇博客的正题&#xff01;怎么手动部署 先找到我们下载…

java.lang.NoSuchMethodException异常解决

标题 java.lang.NoSuchMethodException异常的正确解决方法摘要&#x1f680; 异常介绍&#x1f9d0; 异常原因分析&#x1f6e0; 解决方法核对方法名称和参数使用正确的方法签名调整方法访问权限 &#x1f4dd; 解决步骤详解&#x1f5a5; 代码案例演示❓ QA部分Q: 如何区分jav…

Linux环境开发工具之yum

前言 前面我们已经对基本的指令和权限进行了介绍&#xff0c;本期开始我们将介绍常用的开发工具。例如&#xff1a;软件包管理器yum。 本期内容介绍 Linux上安装软件的方式 什么是yum yum的相关操作 yum的本地配置和yum源 一、Linux上安装软件的方式 在介绍Linux上如何安装一…

uboot的移植——移植uboot官方的uboot到x210开发板(2)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 参考内容 1、uboot的移植——移植uboot官方的uboot到x210开发板&#xff08;1&#xff09; 2、uboot启动流程——C阶段的start_armboot函数-CSDN博客 3、以官方uboot移植uboot(SD卡驱动移植)-CSDN博…