推荐这款类型转换神器!Mapstruct新出的Spring插件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了推荐这款类型转换神器!Mapstruct新出的Spring插件相关的知识,希望对你有一定的参考价值。

参考技术A

Mapstruct可以代替 BeanUtil 来进行 DTO VO PO 之间的转换。它使用的是Java编译期的 annotation processor 机制,说白了它就是一个代码生成器,代替你手工进行类型转换期间的取值赋值操作。

我很多项目都使用了它,代码清爽得很,增加了大量摸鱼时间,用过的都说好。

就这么几行就把一个 PO 的集合转换成了对应 VO 的集合。

换成你手写试试,起码得五分之一炷香的功夫。

但是这样写还是不太爽,每次都要挂对应的Mapper类。

Spring framework 提供了一个 Converter 接口:

它的作用是将 S 转换为 T ,这和 Mapstruct 的作用不谋而合。

Converter 会通过 ConverterRegistry 这个注册接口注册到 ConversionService ,然后你就可以通过 ConversionService 的 convert 方法来进行转换:

根据上面的机制官方推出了 MapStruct Spring Extensions 插件, 它实现了一种机制,所有的 Mapstruct 映射接口( Mapper )只要实现了 Converter ,都会自动注册到 ConversionService ,我们只需要通过 ConversionService 就能完成任何转换操作。

调用时:

MapStruct Spring Extensions 会自动生成一个适配类处理 Mapper 注册:

默认情况下,生成的适配类将位于包 org.mapstruct.extensions.spring.converter 中,名称固定为 ConversionServiceAdapter 。如果你希望修改包路径或者名称,你可以这样:

如果你的 Spring IoC 容器中有多个 ConversionService ,你可以通过 @SpringMapperConfig 注解的 conversionServiceBeanName 参数指定。

Spring 内部提供了很多好用的 Converter 实现,有的并不直接开放,如果你想用 Mapstruct 的机制使用它们,可以通过 @SpringMapperConfig 注解的 externalConversions 注册它们。

会在适配器中自动生成相应的转换:

mapstruct-spring-annotations 使开发人员能够通过 ConversionService 使用定义的 Mapstruct 映射器,而不必单独导入每个 Mapper ,从而允许 Mapper 之间的松散耦合。,它本身不会影响 Mapstruct 的机制。

类型转换神器Mapstruct新出的Spring插件真好用

胖哥在几年前安利过Mapstruct这个神器,它可以代替BeanUtil来进行DTOVOPO之间的转换。它使用的是Java编译期的  annotation processor 机制,说白了它就是一个代码生成器,代替你手工进行类型转换期间的取值赋值操作。

胖哥很多项目都使用了它,代码清爽得很,增加了大量摸鱼时间,用过的都说好。

@Mapper(componentModel = "spring")
public interface AreaMapping 

    List<AreaInfoListVO> toVos(List<Area> areas);

就这么几行就把一个PO的集合转换成了对应VO的集合。

// spring bean 
@Autowired
AreaMapping areaMapping
    
// 转换源 areas    
List<Area> areas = ……;
// 转换目标 vos 
List<AreaInfoListVO> vos = areaMapping.toVos(areas)

换成你手写试试,起码得五分之一炷香的功夫。

但是这样写还是不太爽,每次都要挂对应的Mapper类。

Converter

Spring framework提供了一个Converter<S,T>接口:

@FunctionalInterface
public interface Converter<S, T> 
    @Nullable
    T convert(S source);

    default <U> Converter<S, U> andThen(Converter<? super T, ? extends U> after) 
        Assert.notNull(after, "After Converter must not be null");
        return (s) -> 
            T initialResult = this.convert(s);
            return initialResult != null ? after.convert(initialResult) : null;
        ;
    

它的作用是将S转换为T,这和Mapstruct的作用不谋而合。

Converter会通过ConverterRegistry这个注册接口注册到ConversionService,然后你就可以通过ConversionServiceconvert方法来进行转换:

<T> T convert(@Nullable Object source, Class<T> targetType);

MapStruct Spring Extensions

根据上面的机制官方推出了MapStruct Spring Extensions插件, 它实现了一种机制,所有的Mapstruct映射接口(Mapper)只要实现了Converter,都会自动注册到ConversionService,我们只需要通过ConversionService就能完成任何转换操作。

/**
 * @author felord.cn
 * @since 1.0.0
 */
@Mapper(componentModel = "spring")
public interface CarMapper extends Converter<Car, CarDto> 

    @Mapping(target = "seats", source = "seatConfiguration")
    CarDto convert(Car car);

调用时:

@Autowired
private ConversionService conversionService;

Car car = ……;
CarDto carDto = conversionService.convert(car,CarDto.class);

MapStruct Spring Extensions 会自动生成一个适配类处理Mapper注册:

package org.mapstruct.extensions.spring.converter;

import cn.felord.mapstruct.entity.Car;
import cn.felord.mapstruct.entity.CarDto;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
/**
 * @author felord.cn
 * @since 1.0.0
 */
@Component
public class ConversionServiceAdapter 
    private final ConversionService conversionService;

    public ConversionServiceAdapter(@Lazy final ConversionService conversionService) 
        this.conversionService = conversionService;
    

    public CarDto mapCarToCarDto(final Car source) 
        return (CarDto)this.conversionService.convert(source, CarDto.class);
    

自定义

自定义适配类的包路径和名称

默认情况下,生成的适配类将位于包org.mapstruct.extensions.spring.converter中,名称固定为ConversionServiceAdapter。如果你希望修改包路径或者名称,你可以这样:

package cn.felord.mapstruct.config;

import org.mapstruct.MapperConfig;
import org.mapstruct.extensions.spring.SpringMapperConfig;

/**
 * @author felord.cn
 * @since 1.0.0
 */
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(conversionServiceAdapterPackage = "cn.felord.mapstruct.config",
        conversionServiceAdapterClassName = "MapStructConversionServiceAdapter")
public class MapperSpringConfig 

不指定conversionServiceAdapterPackage元素,生成的 Adapter 类将与注解的 Config 驻留在同一个包中,所以上面的路径是可以省略的。

指定ConversionService

如果你的Spring IoC容器中有多个ConversionService,你可以通过@SpringMapperConfig注解的conversionServiceBeanName 参数指定。

package cn.felord.mapstruct.config;

import org.mapstruct.MapperConfig;
import org.mapstruct.extensions.spring.SpringMapperConfig;

/**
 * @author felord.cn
 * @since 1.0.0
 */
@MapperConfig(componentModel = "spring")
@SpringMapperConfig(conversionServiceAdapterPackage = "cn.felord.mapstruct.config",
        conversionServiceAdapterClassName = "MapStructConversionServiceAdapter",
                   conversionServiceBeanName = "myConversionService")
public class MapperSpringConfig 

集成Spring的内置转换

Spring内部提供了很多好用的Converter<S,T>实现,有的并不直接开放,如果你想用Mapstruct的机制使用它们,可以通过@SpringMapperConfig注解的 externalConversions注册它们。

@MapperConfig(componentModel = "spring")
@SpringMapperConfig(
   externalConversions = @ExternalConversion(sourceType = String.class, targetType = Locale.class))
public interface MapstructConfig 

会在适配器中自动生成相应的转换:

@Component
public class ConversionServiceAdapter 
  private final ConversionService conversionService;

  public ConversionServiceAdapter(@Lazy final ConversionService conversionService) 
    this.conversionService = conversionService;
  

  public Locale mapStringToLocale(final String source) 
    return conversionService.convert(source, Locale.class);
  

总结

mapstruct-spring-annotations 使开发人员能够通过ConversionService使用定义的 Mapstruct 映射器,而不必单独导入每个 Mapper,从而允许 Mapper 之间的松散耦合。,它本身不会影响Mapstruct的机制。相关的DEMO可以通过公众号回复 mapstructspring 获取。

往期推荐

IntelliJ IDEA 卡成球了?


知网哭穷赔不起1200亿,网友:收钱时咋不嫌多


用了Stream后,代码反而越写越丑?


有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

以上是关于推荐这款类型转换神器!Mapstruct新出的Spring插件的主要内容,如果未能解决你的问题,请参考以下文章

除了 BeanUtils ,这款 PO VO DTO 转换神器香!

iOS最新观影神器,需要的速度下

别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?

别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?

别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?

别再用 BeanUtils 了,这款 PO VO DTO 转换神器不香么?