深入理解Java对象复制
一、图示
二、MapStruct
pom文件
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils --> <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>1.2.0.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-jdk8</artifactId> <version>1.2.0.Final</version> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.2.0.Final</version> </dependency> <!-- dozer使用时需要配置xml 文件,不推荐使用性能和 BeanUtils 差不多,使用过程可以参考 https://www.jianshu.com/p/bf8f0e8aee23--> <!-- https://mvnrepository.com/artifact/net.sf.dozer/dozer --> <!--<dependency> <groupId>net.sf.dozer</groupId> <artifactId>dozer</artifactId> <version>5.5.1</version> </dependency>-->
下载插件
插件的作用是为了在本地测试的时候,生成 接口的 impl 文件(生成的文件存在与target包里面)
如果是生产环境的话,和Lombok操作一样,需要在pom文件添加 mapStruct 插件依赖
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> <showWarnings>true</showWarnings> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </path> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>1.2.0.Final</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
代码
import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * Created by yangLongFei on 2021/5/11 10:44 * Version: $ */ @Data @AllArgsConstructor @NoArgsConstructor @TableName public class Student { private Integer id; private String name; private String age; private String phone; private String address; }
import lombok.Data; import java.io.Serializable; /** * Created by yangLongFei on 2021/5/11 10:51 * Version: $ */ @Data public class StudentDTO implements Serializable { private static final long serialVersionUID = 735190899850778343L; private Integer id; private String name; private String age; private String phone; private String address; }
import lombok.Data; import java.io.Serializable; /** * Created by yangLongFei on 2021/5/11 16:59 * Version: $ */ @Data public class StudentVO implements Serializable { private static final long serialVersionUID = 2059190505074790405L; private Integer pk; private String userName; private String userAge; private String userPhone; private String userAddress; }
接口
import com.sys.yang.dto.StudentDTO; import com.sys.yang.entity.Student; import com.sys.yang.vo.StudentVO; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.factory.Mappers; @Mapper public interface ConverterStudent { ConverterStudent INSTANCE = Mappers.getMapper(ConverterStudent.class); @Mappings({ @Mapping(source = "name", target = "name"), @Mapping(source = "age", target = "age") }) StudentDTO entityToDTO(Student student); @Mappings({ @Mapping(source = "id", target = "pk"), @Mapping(source = "name", target = "userName"), @Mapping(source = "age", target = "userAge"), @Mapping(source = "phone", target = "userPhone"), @Mapping(source = "address", target = "userAddress") }) StudentVO dtoToVo(StudentDTO studentDTO); }
测试类
import com.sys.yang.dto.StudentDTO; import com.sys.yang.entity.Student; import com.sys.yang.vo.StudentVO; import org.junit.Test; import org.springframework.beans.BeanUtils; import java.lang.reflect.Method; /** * 对象转换,映射 * 方式1:效率最高 get set 方法 * 方式2:Common包 BeanUtils.copyProperties 反射的方式进行 * 方式3:mapstruct 推荐使用,操作不复杂,效率和 get set 方式相差不大 * * <p> * Created by yangLongFei on 2021/5/11 10:43 * Version: $ */ public class AToB { /** * set get 的时候使用 * 生成 对象的set方法 */ public static void main(String[] args) { Class<StudentDTO> clazz = StudentDTO.class; Method[] fields = clazz.getDeclaredMethods(); for (Method field: fields) { String name = field.getName(); if(!name.startsWith("is") && !name.startsWith("get")){ System.out.println("entity." + name + "()"); } } } /** * 测试方法 */ @Test public void test1() { Student student = new Student(1,"zhagnsan","18","110112113114","diqiu"); System.out.println(student.toString()); StudentDTO studentDTO1 = new StudentDTO(); BeanUtils.copyProperties(student,studentDTO1); System.out.println("BeanUtils: "+ studentDTO1.toString()); StudentDTO studentDTO2 = ConverterStudent.INSTANCE.entityToDTO(student); System.out.println("mapstruct: entityToDTO " + studentDTO2.toString()); StudentVO studentVO = ConverterStudent.INSTANCE.dtoToVo(studentDTO2); System.out.println("mapStruct: dtoToVo "+ studentVO); } }
生成的接口文件
三、framework cglib
要转换的对象的,字段名称 要和 原对象的字段名称一致,否则赋值会失败,可以手动 convert 方法,但是,实现后所有的转换内容都会走 convert 方法
代码
import lombok.Data; import java.io.Serializable; /** * Created by yangLongFei on 2021/5/11 16:59 * Version: $ */ @Data public class StudentVO implements Serializable { private static final long serialVersionUID = 2059190505074790405L; private Integer pk; private String userName; private String userAge; private String userPhone; private String userAddress; // framework cglib 使用到的内容 private String id; private String name; private Integer age; private String phone; private String address; }
convert 实现类
import org.springframework.cglib.core.Converter; /** * Created by yangLongFei on 2021/5/11 19:53 * Version: $ */ public class ConvertStudentDtoToVo implements Converter { /** * ⭐️⭐️⭐️⭐️⭐️ 要转换的属性名称,相同的情况下,才会走该方法 * @param o 原对象属性值,value * @param aClass 目标对象属性 类型,class java.lang.String * @param o1 目标对象属性set方法,setAddress * @return */ @Override public Object convert(Object o, Class aClass, Object o1) { if (o.getClass().equals(aClass)) { return o; } else { if (o instanceof Integer) { return String.valueOf(o); } if (String.valueOf(o1).contains("Age")) { return Integer.valueOf(o.toString()); } return o; } } }
测试方法
@Test public void test2() { Student student = new Student(1,"zhagnsan","18","110112113114","diqiu"); // false 表示不使用 转换器, BeanCopier entityToDto = BeanCopier.create(Student.class, StudentDTO.class, false); StudentDTO studentDTO3 = new StudentDTO(); // null 表示,不指定转换器,要使用转换器的化,需要实现 Converter 接口 // 属性名称之间不能指定映射关系,当属性名称不同的时候赋值操作会失败 entityToDto.copy(student, studentDTO3, null); System.out.println("cglib :entityToDTO " + studentDTO3.toString()); BeanCopier dtoTOVo = BeanCopier.create(StudentDTO.class, StudentVO.class, false); StudentVO studentVO1 = new StudentVO(); dtoTOVo.copy(studentDTO3, studentVO1, null); System.out.println("cglib: dtoToVo " + studentVO1.toString()); // 一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性 BeanCopier dtoTOVo2 = BeanCopier.create(StudentDTO.class, StudentVO.class, true); StudentVO studentVO2 = new StudentVO(); dtoTOVo2.copy(studentDTO3, studentVO2, new ConvertStudentDtoToVo()); System.out.println("cglib : convert "+studentVO2.toString()); }
四、问题
beanUtils 不会进行 属性 类型的转换,如果字段名称相同,类型不同,不会对该字段进行赋值操作,( 测试方法中使用的 是 org.springframework.beans.BeanUtils )
cglib 在不定义Converter 的情况下也会出现 类型转换错误的异常,可以手动自定义转换器 convert ,一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性。
springframwork 有实现 cglib 的BeanCopier 不需要再引用 org.easymock 依赖
到此这篇关于深入理解Java对象复制的文章就介绍到这了,更多相关Java对象复制内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
- 这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了R语言删除指定变量或对象的操作方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 某些时候,例如为了搭建一个测试环境,或者克隆一个网站,需要复制一个已存在的mysql数据库。使用以下方法,可以非常简单地实现。假设已经存在的数据库名字叫db1,想要复制一份,命名为newdb。步骤如下:1. 首先创建新的数据库newd...2015-10-21
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
如何在Spring WebFlux的任何地方获取Request对象
这篇文章主要介绍了如何在Spring WebFlux的任何地方获取Request对象,帮助大家更好的理解和使用springboot框架,感兴趣的朋友可以了解下...2021-01-26- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了JavaScript预解析,对象的的相关资料,小编觉得这篇文章写的还不错,需要的朋友可以参考下,希望能够给你带来帮助...2021-11-10
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31牛叉的Jquery――Jquery与DOM对象的互相转换及DOM的三种操作
只有jQuery对象才能调用jQuery类库的各种函数,同样有些dom对象的属性和方法在jQuery上也是无法调用的,不过基本上jQuery类库提供的函数包含了所有的dom操作。这就需要我们知道如何将jQuery对象和DOM的相互转换的方法。1...2015-10-30- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03