@Mapping(…)
…
public abstract CarDto carToCarDto(Car car);
public PersonDto personToPersonDto(Person person) {
//hand-written mapping logic
}
}
▐ 多个source参数的映射方法
MapStruct也支持带有多个source参数的映射方法。这个在将多个bean合并成一个bean的时候非常有用。
例子如下:
@Mapper
public interface AddressMapper {
@Mapping(source = “person.description”, target = “description”)
@Mapping(source = “address.houseNo”, target = “houseNumber”)
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Address address);
}
上面显示的就是将俩个source参数映射成一个target对象。和单个参数一样,属性映射也是通过名称。
如果多个source参数中的属性具有相同的名称,必须通过@Mapping指定哪个source里面的属性映射到target属性中。如果存在多个相同的属性,并且没有指定,则会报错。
MapStruct也支持直接引用一个source参数映射到target对象中。例子如下
@Mapper
public interface AddressMapper {
@Mapping(source = “person.description”, target = “description”)
@Mapping(source = “hn”, target = “houseNumber”)
DeliveryAddressDto personAndAddressToDeliveryAddressDto(Person person, Integer hn);
}
上面的例子将hn直接映射到target的houseNumber属性上。
▐ 处理内嵌bean属性映射
例子如下:
@Mapper
public interface CustomerMapper {
@Mapping( target = “name”, source = “record.name” )
@Mapping( target = “.”, source = “record” )
@Mapping( target = “.”, source = “account” )
Customer customerDtoToCustomer(CustomerDto customerDto);
}
-
如果只是某一个内嵌属性的映射,可以类似
@Mapping( target = "name", source = "record.name" )
这样写 -
如果是映射多个内嵌属性到target上,可以用
.
代替,表示把对应属性bean匹配的内嵌属性映射到target上
▐ 更新Bean实例
有时我们并不一定创建一个新的Bean,可能需要更新某一个实例。这种类型的映射我们可以通过在参数上增加一个@MappingTarget注解。例子如下:
@Mapper
public interface CarMapper {
void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
}
这个例子会把CarDto中的属性值更新的Car对象实例上。上面的例子我们也可以将void改成Car类型返回值。
对于Collection或者Map类型,默认会将集合中所有的值清空,然后使用相关source集合中的值来填充,即CollectionMappingStrategy.ACCESSOR_ONLY策略。另外也提供了CollectionMappingStrategy.ADDER_PREFERRED 或者 CollectionMappingStrategy.TARGET_IMMUTABLE。这些策略可以在@Mapper(collectionMappingStrategy=CollectionMappingStrategy.TARGET_IMMUTABLE)来指定。
▐ 集合映射
基本的定义方式和普通的bean没什么区别,简单例子如下
@Mapper
public interface CarMapper {
Set integerSetToStringSet(Set integers);
List carsToCarDtos(List cars);
CarDto carToCarDto(Car car);
}
对应的生成方法如下
//GENERATED CODE
@Override
public Set integerSetToStringSet(Set integers) {
if ( integers == null ) {
return null;
}
Set set = new HashSet();
for ( Integer integer : integers ) {
set.add( String.valueOf( integer ) );
}
return set;
}
@Override
public List carsToCarDtos(List cars) {
if ( cars == null ) {
return null;
}
List list = new ArrayList();
for ( Car car : cars ) {
list.add( carToCarDto( car ) );
}
return list;
}
对于Map的映射,还提供了@MapMapping
注解,用于处理value的转换
具体的例子如下
public interface SourceTargetMapper {
@MapMapping(valueDateFormat = “dd.MM.yyyy”)
Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}
生成的代码如下
//GENERATED CODE
@Override
public Map<Long, Date> stringStringMapToLongDateMap(Map<String, String> source) {
if ( source == null ) {
return null;
}
Map<Long, Date> map = new HashMap<Long, Date>();
for ( Map.Entry<String, String> entry : source.entrySet() ) {
Long key = Long.parseLong( entry.getKey() );
Date value;
try {
value = new SimpleDateFormat( “dd.MM.yyyy” ).parse( entry.getValue() );
}
catch( ParseException e ) {
throw new RuntimeException( e );
}
map.put( key, value );
}
return map;
}
通过@Mapping#collectionMappingStrategy设置集合的映射策略:CollectionMappingStrategy.ACCESSOR_ONLY:默认、CollectionMappingStrategy.SETTER_PREFERRED、CollectionMappingStrategy.ADDER_PREFERRED、CollectionMappingStrategy.TARGET_IMMUTABLE。
策略具体的意义如果没有看懂,可以参考下这篇文章MapStruct文档(五)——集合映射
▐ 枚举映射处理
直接上例子,方便理解
@Mapper
public interface OrderMapper {
OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class );
@ValueMappings({
@ValueMapping(source = “EXTRA”, target = “SPECIAL”),
@ValueMapping(source = “STANDARD”, target = “DEFAULT”),
@ValueMapping(source = “NORMAL”, target = “DEFAULT”)
})
ExternalOrderType orderTypeToExternalOrderType(OrderType orderType);
}
生成的代码如下
// GENERATED CODE
public class OrderMapperImpl implements OrderMapper {
@Override
public ExternalOrderType orderTypeToExternalOrderType(OrderType orderType) {
if ( orderType == null ) {
return null;
}
ExternalOrderType externalOrderType_;
switch ( orderType ) {
case EXTRA: externalOrderType_ = ExternalOrderType.SPECIAL;
break;
case STANDARD: externalOrderType_ = ExternalOrderType.DEFAULT;
break;
case NORMAL: externalOrderType_ = ExternalOrderType.DEFAULT;
break;
case RETAIL: externalOrderType_ = ExternalOrderType.RETAIL;
break;
case B2B: externalOrderType_ = ExternalOrderType.B2B;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + orderType );
}
return externalOrderType_;
}
}
默认情况下,如果存在不匹配的情形,则直接抛出异常。这种默认行为是可以被修改的,主要有以下三种策略
-
MappingConstants.NULL : 处理null值,
-
MappingConstants.ANY_REMAINING : 处理所有未被定义或者名字匹配不上的
-
MappingConstants.ANY_UNMAPPED :处理任何违背匹配的情形
枚举到字符串的映射,不支持MappingConstants.ANY_REMAINING
@Mapper
public interface TestMapper {
@ValueMappings({
@ValueMapping(source = “able_status”, target = “PERFECT”),
@ValueMapping(source = MappingConstants.NULL, target = “PASS”),
@ValueMapping(source = “failed_status”, target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = “normal”),
})
String toEnum(DisableStatus disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public String toEnum(DisableStatus disableStatus) {
if ( disableStatus == null ) {
return “PASS”;
}
String string;
switch ( disableStatus ) {
case able_status: string = “PERFECT”;
break;
case failed_status: string = null;
break;
default: string = “normal”;
}
return string;
}
}
字符串到枚举的映射
@Mapper
public interface TestMapper {
@ValueMappings({
@ValueMapping(source = “PERFECT”, target = “able_status”),
@ValueMapping(source = “PASS”, target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.NULL, target = “failed_status”),
@ValueMapping(source = MappingConstants.ANY_UNMAPPED, target = “normal_status”),
})
DisableStatus toEnum(String disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public DisableStatus toEnum(String disableStatus) {
if ( disableStatus == null ) {
return DisableStatus.failed_status;
}
DisableStatus disableStatus1;
switch ( disableStatus ) {
case “PERFECT”: disableStatus1 = DisableStatus.able_status;
break;
case “PASS”: disableStatus1 = null;
break;
default: disableStatus1 = DisableStatus.normal_status;
}
return disableStatus1;
}
}
@Mapper
public interface TestMapper {
@ValueMappings({
@ValueMapping(source = “PERFECT”, target = “able_status”),
@ValueMapping(source = “PASS”, target = MappingConstants.NULL),
@ValueMapping(source = MappingConstants.NULL, target = “failed_status”),
@ValueMapping(source = MappingConstants.ANY_REMAINING, target = “normal_status”),
})
DisableStatus toEnum(String disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public DisableStatus toEnum(String disableStatus) {
if ( disableStatus == null ) {
return DisableStatus.failed_status;
}
DisableStatus disableStatus1;
switch ( disableStatus ) {
case “PERFECT”: disableStatus1 = DisableStatus.able_status;
break;
case “PASS”: disableStatus1 = null;
break;
case “able_status”: disableStatus1 = DisableStatus.able_status;
break;
case “disable_status”: disableStatus1 = DisableStatus.disable_status;
break;
case “normal_status”: disableStatus1 = DisableStatus.normal_status;
break;
case “failed_status”: disableStatus1 = DisableStatus.failed_status;
break;
case “ok_status”: disableStatus1 = DisableStatus.ok_status;
break;
case “fine_status”: disableStatus1 = DisableStatus.fine_status;
break;
default: disableStatus1 = DisableStatus.normal_status;
}
return disableStatus1;
}
}
- 自定义名称转换
可以通过删除或添加源枚举字符串的前后缀来映射目标枚举对象。
public enum LevelEnum {
able(1, “完美”),
disable(2, “合格”),
normal(3, “普通”),
failed(4, “不及格”),
ok(5, “还行”),
fine(6, “可以”);
private Integer code;
private String desc;
LevelEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
public enum DisableStatus {
able_status(1, “完美”),
disable_status(2, “合格”),
normal_status(3, “普通”),
failed_status(4, “不及格”),
ok_status(5, “还行”),
fine_status(6, “可以”);
private Integer code;
private String desc;
DisableStatus(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
}
@Mapper
public interface TestMapper {
@EnumMapping(nameTransformationStrategy = “stripSuffix”, configuration = “_status”)
LevelEnum toEnum(DisableStatus disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public LevelEnum toEnum(DisableStatus disableStatus) {
if ( disableStatus == null ) {
return null;
}
LevelEnum levelEnum;
switch ( disableStatus ) {
case able_status: levelEnum = LevelEnum.able;
break;
case disable_status: levelEnum = LevelEnum.disable;
break;
case normal_status: levelEnum = LevelEnum.normal;
break;
case failed_status: levelEnum = LevelEnum.failed;
break;
case ok_status: levelEnum = LevelEnum.ok;
break;
case fine_status: levelEnum = LevelEnum.fine;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + disableStatus );
}
return levelEnum;
}
}
@EnumMapping#nameTransformationStrategy支持的参数有:suffix(添加源后缀)、stripSuffix(删除源后缀)、prefix(添加源前缀)、stripPrefix(删除源前缀)。
检索映射器
最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
LevelEnum toEnum(DisableStatus disableStatus);
}
@Component
public class TestMapperImpl implements TestMapper {
@Override
public LevelEnum toEnum(DisableStatus disableStatus) {
if ( disableStatus == null ) {
return null;
}
LevelEnum levelEnum;
switch ( disableStatus ) {
case able_status: levelEnum = LevelEnum.able;
break;
case disable_status: levelEnum = LevelEnum.disable;
break;
case normal_status: levelEnum = LevelEnum.normal;
break;
case failed_status: levelEnum = LevelEnum.failed;
break;
case ok_status: levelEnum = LevelEnum.ok;
break;
case fine_status: levelEnum = LevelEnum.fine;
break;
default: throw new IllegalArgumentException( "Unexpected enum constant: " + disableStatus );
}
return levelEnum;
}
}
@EnumMapping#nameTransformationStrategy支持的参数有:suffix(添加源后缀)、stripSuffix(删除源后缀)、prefix(添加源前缀)、stripPrefix(删除源前缀)。
检索映射器
最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
[外链图片转存中…(img-fLONrAQ4-1714528015163)]