Orika是一种java Bean映射框架,可以实现从一个对象递归拷贝数据至另一个对象。
对象的拷贝在开发中的应用场景非常多,比如我们需要一个新的类只继承原有类的部分属性;亦或者需要一个新的类增加更多的属性(可以用继承实现);亦或者只取两个类中有交集的属性:
简单封装Orika
由于每次使用都需要new一个MapperFactory的基础类
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
所以我们可以对它进行一个简单的封装:
首先在pom.xml中导入maven依赖,我这里直接找了maven仓库的最新版本
<dependency>
<groupId>ma.glasnost.orika</groupId>
<artifactId>orika-core</artifactId>
<version>1.5.4</version>
</dependency>
</dependencies>
下面是简单封装的MapperUtils工具类,将MapperFactory的初始化方法写在静态代码块中,这样重复调用也只用初始化一次。并且提供了getMapperFactory(),让Orika不局限于工具类中的方法。这里只写了一个类coyp的方法,实际上Orika是很强大的
import ma.glasnost.orika.MapperFacade;
import ma.glasnost.orika.MapperFactory;
import ma.glasnost.orika.impl.DefaultMapperFactory;
public class MapperUtils {
private static final MapperFacade mapperFacade;
private static final MapperFactory mapperFactory;
static {
mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFacade = mapperFactory.getMapperFacade();
}
/**
* 将对象sourceObject的值拷贝到对象targetObject中
*/
public static void copyObject(Object sourceObject, Object targetObject) {
mapperFacade.map(sourceObject, targetObject);
}
// 可以封装更多的常用方法
/**
* 提供getMapperFactory方便调用其他方法
*/
public static MapperFactory getMapperFactory() {
return mapperFactory;
}
}
调用方法也非常简单,假设已有源对象sourceClass,需要复制一个TargetClass对象,TargetClass可以已有的对象,不一定要new出来。
TargetClass targetClass = new TargetClass();
MapperUtils.copyObject(sourceClass,targetClass);
//MapperUtils.getMapperFactory().getMapperFacade().map(sourceClass,targetClass);
实例测试
这边创建两个测试用的实例类:
SourceClass作为复制源对象;TargetClass作为复制目标对象
public class SourceClass {
private String aaa;
private int bbb;
private String ccc;
private String eee;
....省略get set方法
}
public class TargetClass{
private String aaa;
private String bbb;
private int ccc;
private String ddd;
....省略get set方法
}
写一个main方法进行测试
例子中包含了几种特殊情况:①属性名相同,数据类型不同;②源类有,目标类没有的属性;源类没有,目标类有的属性 ③目标类属性已有值
①情况一: 源类中(int类型)bbb=1,ccc=“c”
public static void main(String[] args) {
SourceClass sourceClass=new SourceClass();
sourceClass.setAaa("a");
sourceClass.setBbb(1);
sourceClass.setCcc("c");
TargetClass targetClass=new TargetClass();
MapperUtils.copyObject(sourceClass,targetClass);
System.out.println(targetClass);
}
运行结果是直接报错了:
这个报错很好理解,就是在复制ccc的时候,由于sourceClass 中ccc是String类型的"c",而TargetClass是int类型,所以String的"c"肯定无法转换成int。
②情况二: 源类中(int类型)bbb=1,ccc=“3”
public static void main(String[] args) {
SourceClass sourceClass=new SourceClass();
sourceClass.setAaa("a");
sourceClass.setBbb(1);
sourceClass.setCcc("3");
sourceClass.setEee("e");
TargetClass targetClass=new TargetClass();
MapperUtils.copyObject(sourceClass,targetClass);
System.out.println(targetClass);
}
可以看到控制台正常输出了targetClass:
TargetClass{aaa=a, bbb=1, ccc=3, ddd=null}
通过debugger看到,sourceClass中int类型的bbb=1成功转换成了targetClass中的String类型的“1”;String类型的ccc=“3”成功转换成了int类型的3;而eee由于targetClass没有,所以也不存在任何属性与其原有值对应;而targetClass中ddd由于sourceClass没有对应的属性,所以为null。
③情况三 当目标类已有值,设置targetClass中的ccc=2,ddd=“d”
public static void main(String[] args) {
SourceClass sourceClass=new SourceClass();
sourceClass.setAaa("a");
sourceClass.setBbb(1);
sourceClass.setCcc("3");
sourceClass.setEee("e");
TargetClass targetClass=new TargetClass();
targetClass.setCcc(2);
targetClass.setDdd("d");
MapperUtils.copyObject(sourceClass,targetClass);
System.out.println(targetClass);
}
通过debugger可以看到ccc值被覆盖,ddd的值依旧保留
结论
从测试结果来看,这个方法能实现的复制:只复制两个类中属性名相同的字段,且当字段名相同类型不同的时要求值能正常转换;相同属性名的值会被源类的值覆盖,目标类的原有属性假如在源类中没有相同属性则会保留原有值。