在开发过程中总会遇到Java对象相互转换,出了最原始及最高效的get/set一块,Java平台中,也出现了很多对象转换工具.
今天本是父亲节,也是地球百年罕见的一次日食现象,晨到点就抱着相机出门,结果专业度不够,拍了俩月亮回来; 朋友圈也是晒疯了,各种各样的太阳,对都是你们的太阳; 此时的我回到家中,左思右想,这个周末又要颓废了吗,别介,好记性不如烂笔头,写会文章吧;(TM….一堆废话)
好吧,咱进入今天的正题,Java对象转换工具哪家强? 首先,java平台中提供了很多的转换工具,旨在提供工作效率,我给大家列举一下
此处排名不分先后,专业评测
什么是MapStruct
MapStruct is a code generator that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach. The generated mapping code uses plain method invocations and thus is fast, type-safe and easy to understand.
啥意思?官方说它是个代码生成器,生成约定的Java bean对象转换.重点是纯方法调用
纯方法调用
容我先买个关子,5毛,不能再多了.
还记得最初的BeanUtils
吗,对于同属性copy,当年用的贼嗨,慢慢的工作经验和程序的并发出现,发现效率并没有那么高;
还有非同属性copy,中途换了N多,比如居于配置文件的Dozer
,写着复杂的xml配置.这些框架的背后无不使用了Java的反射或者代理;
此时,要说今天的主角之前,我觉得咱又必须要先说一下,大名鼎鼎的lombok
,很多人都耳目共染,有了它,我们再也不用写get/set了,好嗨呀!!!
那么MapStruct
又能让我们少写什么呢,对,这位同学很聪慧,不需要我们写对象转换时的get/set啦.
MapStruct亮点是啥
Multi-layered applications often require to map between different object models (e.g. entities and DTOs). Writing such mapping code is a tedious and error-prone task. MapStruct aims at simplifying this work by automating it as much as possible.
In contrast to other mapping frameworks MapStruct generates bean mappings at compile-time which ensures a high performance, allows for fast developer feedback and thorough error checking.
翻译就算了,直接说重点,Java bean 属性转换,这样的代码写多了,看着冗余
,还不好找(密密麻麻),MapStruct
在编译的时候,帮你生成对应的映射关系,提供开发效率.
如何使用
导入对应依赖
1.3.1.Final
的mapstruct-jdk8
已经指向mapstruct
,所以导入mapstruct-jdk8
已经成为过去式
<dependencies>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.3.1.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.1.Final</version>
</dependency>
</dependencies>
- mapstruct 含有对应的注解,比如
@Mapper
- mapstruct-processor 包含Java处理机制,代码生成的关键
编写Java Bean
@Data
public class User implements Serializable {
private String loginName;
private String password;
}
@Data
public class UserDto implements Serializable {
private String username;
private String password;
}
编写Mapper
@Mapper(componentModel = "spring")
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
@Mapping(source = "loginName", target = "username")
UserDto userToUserDto(User user);
}
@Mapper(componentModel = "spring")
使用spring方式注入UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
不使用spring注入时,可以使用实例模式,默认@Mapping(source = "loginName", target = "username")
约定映射关系,多个使用@Mappings
测试
@Slf4j
public class DomainTest extends ApplicationTest {
@Autowired
private UserMapper userMapper;
@Test
public void test(){
User user = new User();
user.setLoginName("12321");
user.setPassword("123456");
// 实例模式
log.info("result:{}",UserMapper.INSTANCE.userToUserDto(user));
}
@Test
public void test2(){
User user = new User();
user.setLoginName("12321");
user.setPassword("123456");
// spring 注入模式
log.info("result:{}",userMapper.userToUserDto(user));
}
}
原理
上文讲述了如何使用MapStruct
,现在我们来讲述下原理,讲述原理前,我们要知道一个大杀器
Annotation Processor
Annotation Processor
注解处理器是javac内置的一个用于编译时扫描和处理注解(Annotation)的工具.
简单的说,在源代码编译阶段,通过注解处理器,我们可以获取源文件内注解(Annotation)相关内容.
编译时注解处理器AnnotationProcessor的使用
查看lombok
和MapStruct
源码,我们都发现有这样一个文件
META-INF/services/javax.annotation.processing.Processor
内容大概是这样的,它在告诉javac对应的注解处理是哪些
# Copyright MapStruct Authors.
#
# Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
org.mapstruct.ap.MappingProcessor
通过MappingProcessor
一系列的处理后,MapStruct
为你生成了对应的mapper的实现类,我们来看看生成的代码怎样的
@Component
public class UserMapperImpl implements UserMapper {
public UserMapperImpl() {
}
public UserDto userToUserDto(User user) {
if (user == null) {
return null;
} else {
UserDto userDto = new UserDto();
userDto.setUsername(user.getLoginName());
userDto.setPassword(user.getPassword());
return userDto;
}
}
}
此时,是不是觉得哪些代理、反射都弱爆了,对此你有什么样的看法呢,欢迎留言,我们一起探讨