java 对象复制字段_利用Java反射机制实现对象相同字段的复制

一。如何实现不同类型对象之间的复制问题?

1、为什么会有这个问题?

近来在进行一个项目开发的时候,为了隐藏后端数据库表结构、同时也为了配合给前端一个更友好的API接口文档(swagger API文档),我采用POJO来对应数据表结构,使用VO来给传递前端要展示的数据,同时使用DTO来进行请求参数的封装。以上是一个具体的场景,可以发现这样子一个现象:POJO、VO、DTO对象是同一个数据的不同视图,所以会有很多相同的字段,由于不同的地方使用不同的对象,无可避免的会存在对象之间的值迁移问题,迁移的一个特征就是需要迁移的值字段相同。字段相同,于是才有了不同对象之间进行值迁移复制的问题。

2、现有的解决方法

一个一个的get出来后又set进去。这个方法无可避免会增加很多的编码复杂度,还是一些很没有营养的代码,看多了还会烦,所以作为一个有点小追求的程序员都没有办法忍受这种摧残。

使用别人已经存在的工具。在spring包里面有一个可以复制对象属性的工具方法,可以进行对象值的复制,下一段我们详细去分析它的这个工具方法。

自己动手丰衣足食。自己造工具来用,之所以自己造工具不是因为喜欢造工具,而是现有的工具没办法解决自己的需求,不得已而为之。

二、他山之石可以攻玉,详谈spring的对象复制工具

1、看看spring的对象复制工具到底咋样?

类名:org.springframework.beans.BeanUtils

这个类里面所有的属性复制的方法都调用了同一个方法,我们就直接分析这个原始的方法就行了。

/**

* Copy the property values of the given source bean into the given target bean.

*

Note: The source and target classes do not have to match or even be derived

* from each other, as long as the properties match. Any bean properties that the

* source bean exposes but the target bean does not will silently be ignored.

* @param source the source bean:也就是说要从这个对象里面复制值出去

* @param target the target bean:出去就是复制到这里面来

* @param editable the class (or interface) to restrict property setting to:这个类对象是target的父类或其实现的接口,用于控制属性复制的范围

* @param ignoreProperties array of property names to ignore:需要忽略的字段

* @throws BeansException if the copying failed

* @see BeanWrapper

*/

private static void copyProperties(Object source, Object target, Class> editable, String... ignoreProperties)

throws BeansException {

//这里在校验要复制的对象是不可以为null的,这两个方法可是会报错的!!

Assert.notNull(source, "Source must not be null");

Assert.notNull(target, "Target must not be null");

//这里和下面的代码就有意思了

Class> actualEditable = target.getClass();//获取目标对象的动态类型

//下面判断的意图在于控制属性复制的范围

if (editable != null) {

//必须是target对象的父类或者其实现的接口类型,相当于instanceof运算符

if (!editable.isInstance(target)) {

throw new IllegalArgumentException("Target class [" + target.getClass().getName() +

"] not assignable to Editable class [" + editable.getName() + "]");

}

actualEditable = editable;

}

//不得不说,下面这段代码乖巧的像绵羊,待我们来分析分析它是如何如何乖巧的

PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);//获取属性描述,描述是什么?描述就是对属性的方法信息的封装,好乖。

List ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

//重头戏开始了!开始进行复制了

for (PropertyDescriptor targetPd : targetPds) {

//先判断有没有写方法,没有写方法我也就没有必要读属性出来了,这个懒偷的真好!

Method writeMethod = targetPd.getWriteMethod();

//首先,没有写方法的字段我不写,乖巧撒?就是说你不让我改我就不改,让我忽略我就忽略!

if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {

PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());

//如果没办法从原对象里面读出属性也没有必要继续了

if (sourcePd != null) {

Method readMethod = sourcePd.getReadMethod();

//这里就更乖巧了!写方法不让我写我也不写!!!

if (readMethod != null &&

ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {

try {

//这里就算了,来都来了,就乖乖地进行值复制吧,别搞东搞西的了

if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {

readMethod.setAccessible(true);

}

Object value = readMethod.invoke(source);

if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {

writeMethod.setAccessible(true);

}

writeMethod.invoke(target, value);

}

catch (Throwable ex) {

throw new FatalBeanException(

"Could not copy property '" + targetPd.getName() + "' from source to target", ex);

}

}

}

}

}

}

2、对复制工具的一些看法和总结

总结上一段代码的分析,我们发现spring自带的工具有以下特点:

它名副其实的是在复制属性,而不是字段!!

它可以通过一个目标对象的父类或者其实现的接口来控制需要复制属性的范围

很贴心的可以忽略原对象的某些字段,可以通过2的方法忽略某些目标对象的字段

但是,这远远不够!!!我需要如下的功能:

复制对象的字段,而不是属性,也就是说我需要一个更暴力的复制工具。

我需要忽略原对象的某些字段,同时也能够忽略目标对象的某些字段。

我的项目还需要忽略原对象为null的字段和目标对象不为null的字段

带着这三个需求,开始我的工具制造。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 类确定运行时间_java回调函数实例:实现一个测试函数运行时间的工具类

下面使用java回调函数来实现一个测试函数运行时间的工具类:如果我们要测试一个类的方法的执行时间,通常我们会这样做:public class TestObject {/*** 一个用来被测试的方法,进行了一个比较耗时的循环*/public static void testMet…

java socket调用接口_Java中socket接口调用

最近一个项目中接口通讯这一块主要是调用银联系统的socket接口,我方是客户端,即发送请求接收返回报文的一方。在贴代码之前,还是要了解一下关于socket的基础知识。Socket的基本概念1.建立连接当需要建立网络连接时,必须…

protobuf java 编译_Maven项目中,编译proto文件成Java类

新建Maven项目新建一个 Maven 项目:pom定义了最小的maven2元素,即:groupId,artifactId,version。 groupId:项目或者组织的唯一标志,并且配置时生成的路径也是由此生成,如org.codehaus.mojo生成的相对路径为&#xff1a…

java 结构体数组初始化_C数组结构体联合体快速初始化

背景C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序。C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组某些元素或结构体某些成员进行选择性初始化,只需指明它们所对应的数组…

java override 访问权限_java基础之——访问修饰符(private/default/protected/public)

1. 访问修饰符介绍java中的访问修饰符包含了四种:private、default(没有对应的保留字)、protected和public。它们的含义如下:private:如果一个元素声明为private,那么只有同一个类下的元素才可以访问它。default:如果一…

python中scrapy可以爬取多少数据_python中scrapy框架爬取携程景点数据

———————————————————————————————[版权申明:本文系作者原创,转载请注明出处]文章出处:https://blog.csdn.net/sdksdk0/article/details/82381198作者:朱培 ID:sdksdk0——————…

python灰色关联度分析代码_灰色关联分析法步骤 - osc_uwnmtz9n的个人空间 - OSCHINA - 中文开源技术交流社区...

https://wenku.baidu.com/view/dc356290af1ffc4fff47ac0d.html?rec_flagdefault&sxts1538121950212利用灰色关联分析的步骤是:1.根据分析目的确定分析指标体系,收集分析数据。设n个数据序列形成如下矩阵:其中m为指标的个数&a…

aio 系统原理 Java_Java新一代网络编程模型AIO原理及Linux系统AIO介绍

从JDK 7版本开始,Java新加入的文件和网络io特性称为nio2(new io 2, 因为jdk1.4中已经有过一个nio了),包含了众多性能和功能上的改进,其中最重要的部分,就是对异步io的支持,称为Java AIO(asynchronous IO)。因为AIO的实…

centos mysql 5.5 art_Linux CentOS6.5下编译安装MySQL 5.5.51''''

一、编译安装MySQL前的准备工作安装编译源码所需的工具和库yum install gcc gcc-c ncurses-devel perl安装cmake,从http://www.cmake.org下载源码并编译安装wget http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gztar -xzvf cmake-2.8.10.2.tar.gzcd cmake-2.…

java修改默认字符编码_设置默认的Java字符编码?

如何以编程方式正确设置JVM(1.5.x)使用​​的默认字符编码?我已经读过-Dfile.encoding 以前是以往的方式去为旧的JVM …我没有那么奢侈的原因,我不会进入。我努力了:System.setProperty("file.encoding", "UTF-8");并且属…

java api 第一个类是_JAVA常用API:String 类的常用方法

字符串是一个对象,有很多方法可以使用1. length();返回字符串的长度String str "abcd";int len str.length();2. isEmpty(); 仅当当length()为0时返回true,否则返回falseboolean b str.isEmpty();3. getBytes();返回字符串中每个字符的ASCII码(使用平台…

关于java内容_关于java一些概念性的内容

PO:persistant object持久对象最形象的理解就是一个PO就是数据库中的一条记录。好处是可以把一条记录作为一个对象处理,可以方便的转为其它对象。--------------------------------------------------------------------------------BO:busin…

java订单类_基于Java创建一个订单类代码实例

这篇文章主要介绍了基于Java创建一个订单类代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下需求描述定义一个类,描述订单信息订单id订单所属用户(用户对象)订单所包含的商品(不定数量个商品对…

java请假审批怎么实现_java实现请假时间判断

笔记:需求分析:每周上班6天夏季早上8:30-12:00下午14:00-17:30冬季早上8:30-12:00下午14:30-18:00请假最低为半天按照上午8:00-12:00,下午14:00-18:00计算,包括了夏季和冬季时间,规律分布如下public String getDouble(HttpServletRequest request) throws ParseException {//参…

mariadb mysql 5.6_MySQL / MariaDB 5.5 升级到 MySQL 5.6

RHEL 及 CentOS 7 默认的资库系统是 MariaDB 5.5 (等同 MySQL 5.5), 虽然现时 MySQL 最新版是 5.7, 但一般上升级都建议一级一级上, 而 MySQL 5.6 比 5.5 也提高了效能及提供更多功能, 以下是在 RHEL 及 CentOS 从原来的 MySQL 5.5 或 MariaDB 5.5, 升级到 MySQL 5.6 的步骤。1…

iText报表Java_(例)Java生成PDF报表 iText

// 导入IO库类import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.util.ArrayList;// 导入 PO&#x…

mysql update修改数据_MySQL UPDATE:修改数据(更新数据)

在 MySQL 中,可以使用 UPDATE 语句来修改、更新一个或多个表的数据。UPDATE 语句的基本语法使用 UPDATE 语句修改单个表,语法格式为:UPDATE SET 字段 1值 1 [,字段 2值 2… ] [WHERE 子句 ][ORDER BY 子句] [LIMIT 子句]语法说明如下&#xf…

java堆内存 数据结构_JAVA内存区域

首先解释下内存溢出和内存泄露之间的区别,为后面的学习做些铺垫:1、内存溢出和内存泄露的区别和联系内存溢出 out of memory:是指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型…

java jsp的指令_[javaEE] jsp的指令

jsp的指令:jsp的指令(directive)是为jsp引擎而设计的,他们并不直接产生任何可见输出,而是告诉引擎如何处理jsp页面中的其他部分页面头部的page指令pageEncoding"utf-8"%>配置错误页面:web.xml500/500.jsp404/404.jsp…

JAVA不能满屏_java – 全屏幕视频,不拉伸视频

像这样,你可以自己设置视频的属性。使用SurfaceView(给你更多的视图控制),将其设置为fill_parent以匹配整个屏幕android:orientation"vertical"android:layout_width"match_parent"android:layout_height"fill_parent">…