前面我们讲了MapStruct的一些基本的、最常用的一些东西,包括同名属性映射、不同名称属性映射;同时我们也知道了它会自动生成我们定义的转换接口的实现类,实现类的本质还是xx2.set(xx1.get),相当于是一个代码生成器。
本文主要讲一些其他的东西,包括高阶用法探索、异常问题避免等。
1、多转一
1)我们在实际的业务中少不了将多个对象转换成一个的场景。 MapStruct 当然也支持多转一的操作。
下面放一个代码片段,我们可以看到其对应的信息不仅仅来自一个类, 那么, 我们也可以通过配置来实现多到一的转换。
- @Mapper
- public interface AddressMapper {
- AddressMapper INSTANCE = Mappers.getMapper(AddressMapper.class);
- @Mapping(source = "person.description", target = "description")
- @Mapping(source = "address.houseNo", target = "houseNumber")
- DeliveryAddress personAndAddressToDeliveryAddressDto(Person person, Address address);
- }
2)在多对一转换时, 遵循以下几个原则
- 当多个对象中, 有其中一个为 null, 则会直接返回 null
- 如一对一转换一样, 属性通过名字来自动匹配。 因此, 名称和类型相同的不需要进行特殊处理
- 当多个原对象中,有相同名字的属性时,需要通过 @Mapping 注解来具体的指定, 以免出现歧义(不指定会报错)。 如上面的 description
2、类型转换
在映射@Mapping时可以指定转换方式,例:
- @Mapping(target = "birthday", expression = "java(cn.hutool.core.date.DateUtil.format(vo.getBirthday(), \"yyyy-MM-dd HH:mm:ss\"))")
- })
更多类型转换可以查看源码如下,具体每个怎么使用暂时不讲解,后续有时间再写吧,有需要的朋友也可以自己研究下。
- @Repeatable(Mappings.class)
- @Retention(RetentionPolicy.CLASS)
- @Target({ElementType.METHOD})
- public @interface Mapping {
- String target();
- String source() default "";
- String dateFormat() default "";
- String numberFormat() default "";
- String constant() default "";
- String expression() default "";
- String defaultExpression() default "";
- boolean ignore() default false;
- Class extends Annotation>[] qualifiedBy() default {};
- String[] qualifiedByName() default {};
- Class> resultType() default void.class;
- String[] dependsOn() default {};
- String defaultValue() default "";
- NullValueCheckStrategy nullValueCheckStrategy() default NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
- NullValuePropertyMappingStrategy nullValuePropertyMappingStrategy() default NullValuePropertyMappingStrategy.SET_TO_NULL;
- }
3、Spring注入
我们知道只有在接口加上这个@Mapper注解, MapStruct 才会去实现该接口 。 @Mapper 里有个 componentModel 属性,主要是指定实现类的类型,一般用到两个 。
- default:默认,可以通过 Mappers.getMapper(Class) 方式获取实例对象 ;
- spring:在接口的实现类上自动添加注解 @Component,可通过 @Autowired 方式注入
4、异常问题避免/个性逻辑调整
我们知道转换的实现类是MapStruct帮我们在编译时自动生成的,实现类文件放在编译目录里面,没有在源代码里面。这会导致一个问题:如果你的java bean有修改字段类型/名称、或去掉一个字段,如果不重新生成覆盖,代码不会报错,你可能也发现不了,但是实际调用执行的时候会报错。
对于这个问题我和同事也讨论了相关优化措施:我们可以把MapStruct当成代码生成器,编译生成的转换器实现类我们把它从编译目录拷贝到源码目录下,这样的话可以预防这个问题,同时我们也不用编写这无意义的代码,只是动动小手迁移一下。另外在源码目录下我们可以做其他的定制逻辑处理调整,不用担心重新编译会覆盖掉我们添加的部分调整代码。
5、相关文章
相关文章列表点击这里,后续深度使用之后,也会继续更新更多关于MapStruct的文章。如果觉得有用,欢迎分享。