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;
  }    
posted @ 2022-05-16 17:53  Franson  阅读(3309)  评论(0编辑  收藏  举报