属性映射工具——MapStruct

一、简介

一个属性映射工具。

项目中各种实体之间会有很多转换,比如 vo、entity、dto、domain等。转换时需要写大量的get、set方法,冗长也工作量很大。再加上转换时可能还会有一定的业务逻辑处理,这会导致映射过程十分繁琐。

本篇博客介绍的工具MapStruct,就可以很好地解决这一问题。

二、实践

实际应用场景主要分为以下几种情况:

1、属性名相同

无需处理,自动映射,类似BeanUtils。

2、属性名不同

需手动指定。

3、属性值需额外的逻辑处理

使用表达式引入逻辑处理。

代码示例

引入jar包

 		 <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.3.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.3.1.Final</version>
        </dependency>

代码示例

//两个实体PersonVo->PersonDto
@Data
public class PersonVo {
    private Integer id;
    private String personName;
    private Integer type;
}

@Data
public class PersonDto {
    private Integer id;
    private String name;
    private Integer status;
}

//映射接口
@Mapper
public interface IConvert {

    IConvert INSTANCE= Mappers.getMapper(IConvert.class);

    @Mappings({
            @Mapping(target = "name",source = "personName"),
            @Mapping(target = "status",expression = "java(ParseUtil.parseType(personVo.getType()))")
    })
    PersonDto convert(PersonVo personVo);

}

//expression表达式中的util方法
public class ParseUtil {

    public static Integer parseType(Integer type){
        switch (type){
            case 1:
                return 2;
            case 2:
                return 3;
            default:
                return 0;
        }
    }
}

//test调用
public class Test {
    IConvert iConvert;

    public static void main(String[] args) {
        Test test=new Test();
        PersonVo personVo=new PersonVo();
        personVo.setId(1);
        personVo.setPersonName("zhangsan");
        personVo.setType(2);
        PersonDto personDto = test.iConvert.INSTANCE.convert(personVo);
        System.out.println(personDto);
    }
}

打开编译后的文件,会发现mapstruct生成了IConvert的实现类IConvertImpl。

public class IConvertImpl implements IConvert {
    public IConvertImpl() {
    }

    public PersonDto convert(PersonVo personVo) {
        if (personVo == null) {
            return null;
        } else {
            PersonDto personDto = new PersonDto();
            personDto.setName(personVo.getPersonName());
            personDto.setId(personVo.getId());
            personDto.setStatus(ParseUtil.parseType(personVo.getType()));
            return personDto;
        }
    }
}

常用注解:
@Mapper——接口注解
@Mapping——属性映射
@Mappings——可以配置多个属性

三、原理

MapStruct是在编译期间完成映射的,并没有通过反射机制动态映射。因此,安全性更高、速度更快。
MappingProcessor是MapStruct的入口,主要方法init() process()

@SupportedAnnotationTypes({"org.mapstruct.Mapper"})
@SupportedOptions({"mapstruct.suppressGeneratorTimestamp", "mapstruct.suppressGeneratorVersionInfoComment", "mapstruct.unmappedTargetPolicy", "mapstruct.defaultComponentModel"})
public class MappingProcessor extends AbstractProcessor {

    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        this.options = this.createOptions();
        this.annotationProcessorContext = new AnnotationProcessorContext(processingEnv.getElementUtils(), processingEnv.getTypeUtils());
    }
    
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
        if (!roundEnvironment.processingOver()) {
            RoundContext roundContext = new RoundContext(this.annotationProcessorContext);
            Set<TypeElement> deferredMappers = this.getAndResetDeferredMappers();
            this.processMapperElements(deferredMappers, roundContext);
            Set<TypeElement> mappers = this.getMappers(annotations, roundEnvironment);
            this.processMapperElements(mappers, roundContext);
        }

        return false;
    }
}

四、评价

优点:
BeanUtils.copyProperties()使用反射,在一定程度上会影响性能。而MapStruct是在编译时完成映射,更安全快速。另外,使用注解来映射属性,更清晰直观。

缺点:
注解中的参数值容易出错,尤其是expression,出错后编译报错。配合MapStruct插件效果会更好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值