mapstruct 框架的原理
这里不在讲它的基础用法了,也相信大家都会了基本用法,它就是通过Java的动态编译实现的,我们也可以通过mapping注解指定转换规则。下面通过原理说一些需要注意的地方。
两个类:
@Data
class A{
private String name;
private String age;
}
@Data
class B{
private String name;
private String age;
private String address;
}
// B对象集合转换成A对象集合
List<A> bListToAList(List<B> bList);
如上代码,是将B集合转换成A集合,实际编译完成的代码如下,这里可能疑惑,我们没有声明单个对象的转换,它怎么编译后有此对象呢,这就是因为编译时对代码进行的增强,通过反射增加了单个对象的转换。但也不是每次都会自动生成,它会先遍历整个对象的方法,通过形参和返回值确定是否已经存在了所需要的单个对象转换方法。如果存在了就直接使用了。
public A bToA(B b) {
if (b== null) {
return null;
} else {
A a = new A();
a.setName(b.getName());
a.setAge(b.getAge());
return a;
}
}
public List<A> bListToAList(List<B> bList) {
if (bList== null) {
return null;
} else {
List<A> list = new ArrayList(bList.size());
Iterator var3 = bList.iterator();
while(var3.hasNext()) {
B b = (B)var3.next();
list.add(this.bToA(b));
}
return list;
}
}
如果我们自定义了属性对应关系
// B对象转换成A对象
@Mappings({
@Mapping(source = "name", target = "name"),
@Mapping(source = "address", target = "age")
})
A bToA(B b);
// B对象集合转换成A对象集合
List<A> bListToAList(List<B> bList);
则编译后的代码如下:我们发现,它使用了我们自定义好的转换规则
public A bToA(B b) {
if (b== null) {
return null;
} else {
A a = new A();
a.setName(b.getName());
a.setAge(b.getAddress());
return a;
}
}
public List<A> bListToAList(List<B> bList) {
if (bList== null) {
return null;
} else {
List<A> list = new ArrayList(bList.size());
Iterator var3 = bList.iterator();
while(var3.hasNext()) {
B b = (B)var3.next();
list.add(this.bToA(b));
}
return list;
}
}
如果我们写了两个方法,这两个方法名不一样,但是形参和返回值一样会出现什么问题呢?
// B对象转换成A对象
@Mappings({
@Mapping(source = "name", target = "name"),
@Mapping(source = "address", target = "age")
})
A bToA(B b);
A bToANew(B b);
// B对象集合转换成A对象集合
List<A> bListToAList(List<B> bList);
这时候编译的时候会报错,提示 Ambiguous mapping methods found for mapping collection element,为映射集合元素找到了不明确的映射方法。这是因为上面我们讲到的原理,是通过形参和返回值去确定方法的,这时候类中有两个一样的形参和返回值方法,所以就会报错。如何解决呢,可以使用 @Named 和 @IterableMapping(qualifiedByName =‘’)注解进行标记:
// B对象转换成A对象
@Mappings({
@Mapping(source = "name", target = "name"),
@Mapping(source = "address", target = "age")
})
@Named('bToA')
A bToA(B b);
@Named('bToANew')
A bToANew(B b);
// B对象集合转换成A对象集合
@IterableMapping(qualifiedByName ='bToANew')
List<A> bListToAList(List<B> bList);
此时编译好的代码如下:
public A bToA(B b) {
if (b== null) {
return null;
} else {
A a = new A();
a.setName(b.getName());
a.setAge(b.getAddress());
return a;
}
}
public A bToANew(B b) {
if (b== null) {
return null;
} else {
A a = new A();
a.setName(b.getName());
a.setAge(b.getAge());
return a;
}
}
public List<A> bListToAList(List<B> bList) {
if (bList== null) {
return null;
} else {
List<A> list = new ArrayList(bList.size());
Iterator var3 = bList.iterator();
while(var3.hasNext()) {
B b = (B)var3.next();
list.add(this.bToANew(b));
}
return list;
}
}