JAVA对象相互转换的多种实现方式
方式一:MapStruct
是一个代码生成器,它基于约定优于配置的方法,极大地简化了 Java bean 类型之间的映射实现。
生成的映射代码使用普通的方法调用,因此速度快、类型安全且易于理解。
官方文档
https://mapstruct.org/documentation/installation/
更多使用示例
https://github.com/kevinLuan/mapstruct-examples
mapper-struct使用比较灵活,性能非常出色。由于它的实现是通过在开发中生成源代码的方式实现,所以对于动态对象数据拷贝并不适合。
使用示例:
// 编写User实体类和DTO实体类
@Data
public class User {
private int id;
private String nickname;
private boolean sex;
private Date registerTime;
private int status;
}
@Data
public class UserDTO {
private int id;
private String nickname;
private boolean sex;
private Date registerTime;
}
import org.mapstruct.CollectionMappingStrategy;
import org.mapstruct.Mapper;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.factory.Mappers;
//编写转换Mapper接口
@Mapper(collectionMappingStrategy = CollectionMappingStrategy.ADDER_PREFERRED,
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS)
public interface UserMapper {
UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);
UserDTO map(User user);
User map(UserDTO userDTO);
}
//maven工程编译项目: mvn compile
//编译插件自动生成UserMapper实现类:UserMapperImpl
import javax.annotation.Generated;
@Generated(
value = "org.mapstruct.ap.MappingProcessor",
date = "2022-04-03T15:59:10+0800",
comments = "version: 1.4.2.Final, compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)"
)
public class TestUserMapperImpl implements UserMapper {
//...
}
//介绍几个常用的注解:
@Mapping 描述转换源对象中的属性名称到目标属性名称的映射,如下
User -> UserDTO 转换示例
@Mapping(source = "users", target = "userList")
UserDTO convert(User user);
//反向转换 UserDTO -> User
@Mapping(source = "userList", target = "users")
User convert(UserDTO userDTO);
//反向转换还可以使用如下注解来完成相同的效果,当转换映射参数比较复杂的情况下,可以使用该注解简化配置
@InheritInverseConfiguration //指示方法应继承响应反向的配置
User convert(UserDTO userDTO);
//使用java表达式,来生成数据,如下示例演示,通过执行表达式中的代码动态生成数据填充到目标属性中
@Mapping(target = "uniqueId", expression = "java(CommonConverter.generateUniqueId())")
User convert(UserDTO userDTO);
//演示实现装饰器自定义映射实现
@Mapper(imports = CommonConverter.class)
//通过定义装饰器模式实现
@DecoratedWith(value = AbstractCarMapperDecorated.class)
public interface CarMapper {
CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
CarDto map(Car car);
//使用java表达式,来生成数据
@Mapping(target = "uniqueId", expression = "java(CommonConverter.generateUniqueId())")
Car map(CarDto car);
}
/**
* 实现装饰器自定义映射实现
*/
public abstract class AbstractCarMapperDecorated implements CarMapper {
private CarMapper delegate;
public AbstractCarMapperDecorated(CarMapper delegate) {
this.delegate = delegate;
}
public CarDto map(Car car) {
CarDto dto = delegate.map(car);
dto.setTitle("title:" + dto.getTitle());
return dto;
}
}
方式二:BeanCopier
BeanCopier 底层依赖cglib通过生成字节码来实现对象拷贝,性能同样非常出色。
由于使用到字节码生成方式技术,所以在动态生成字节码实现类时性能消耗比较大,不过可以通过提前预生成实现类并添加到cache中。
final static BeanCopier beanCopier = BeanCopier.create(Goods.class, GoodsDto.class, false);
//深拷贝数据
beanCopier.copy(goods, goodsDto, null);
public class Goods{
//...
}
public class GoodsDto{
//...
}
方式三:Spring BeanUtils
Spring BeanUtils实现原理是基于反射实现的数据拷贝处理,性能上相比通过字节码生成实现要慢很多。
org.springframework.beans.BeanUtils.copyProperties(source, target);
方式四:apache BeanUtils
org.apache.commons.beanutils.BeanUtils.copyProperties(do, entity);
该方法同样使用反射调用实现数据拷贝处理,性能相比Spring BeanUtils还要差一些,适合使用场景较为简单,调用频率比高的场景。
方式五:IDE idea插件:GenerateAllSetter
安装插件:using IDE plugin system
Preferences(Settings) > Plugins > Browse repositories... > find"GenerateAllSetter" > Install Plugin源码地址: https://github.com/gejun123456/intellij-generateAllSetMethod
// 编写User实体类和DTO实体类
@Data
public class User {
private int id;
private String nickname;
private boolean sex;
private Date registerTime;
private int status;
}
@Data
public class UserDTO {
private int id;
private String nickname;
private boolean sex;
private Date registerTime;
}
//然后编写转换方法
public UserDTO convertUserDTO(User user){
//TODO 将光标移到方法中空白处,使用快捷键:alt + enter(回车键) 当前使用的mac系统
//弹出:Generate setter getter converter
}
//生成后的代码如下:
public UserDTO convertUserDTO(User user){
UserDTO userDTO = new UserDTO();
userDTO.setId(user.getId());
userDTO.setNickname(user.getNickname());
userDTO.setSex(user.isSex());
userDTO.setRegisterTime(user.getRegisterTime());
return userDTO;
}