mapstruct 之 類型轉換

參考鏈接:mapstruct的基本使用

背景介紹

是不是有時候發現明明source和target不是同一個類型,但是卻轉換成功了,這是因爲mapstruct有一套自己的類型轉換機制

類型轉換的流程

  1. 首先嚐試自動進行類型轉換
  2. 若是無法支持的類型轉換,則是嘗試調用已經存在的類型轉換方法
  3. 不存在可用的方法則是嘗試自己創建一個類型轉換方法

類型轉換分類

自動轉換

以下的類型之間是mapstruct自動進行類型轉換的。

  • 基本類型及其他們對應的包裝類型。
    此時mapstruct會自動進行拆裝箱。不需要人爲的處理
  • 基本類型的包裝類型和string類型之間
@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Item1 {
    Long itemId;
    String title;
}

@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Item2 {
    Long itemId;
    String title;
}

@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class Sku2 {
    Long skuId;
    String skuCode;
    String skuPrice;
    List<String> nameList;
    Item1 item;
}

@Data
@NoArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@AllArgsConstructor
public class SkuDTO2 {
    Long skuId;
    String skuCode;
    Long skuPrice;
    List<String> nameList;
    Item2 item;
}

@Mapper
public interface ItemConvert {

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

    SkuDTO2 domain2Dto(Sku2 sku2);
}

// 以下爲mapstruct自動生成
public class ItemConvertImpl implements ItemConvert {

    @Override
    public SkuDTO2 domain2Dto(Sku2 sku2) {
        if ( sku2 == null ) {
            return null;
        }

        SkuDTO2 skuDTO2 = new SkuDTO2();

        skuDTO2.setSkuId( sku2.getSkuId() );
        skuDTO2.setSkuCode( sku2.getSkuCode() );
        if ( sku2.getSkuPrice() != null ) {
            skuDTO2.setSkuPrice( Long.parseLong( sku2.getSkuPrice() ) );
        }
        List<String> list = sku2.getNameList();
        if ( list != null ) {
            skuDTO2.setNameList( new ArrayList<String>( list ) );
        }
        skuDTO2.setItem( item1ToItem2( sku2.getItem() ) );

        return skuDTO2;
    }
    
   protected Item2 item1ToItem2(Item1 item1) {
    if ( item1 == null ) {
        return null;
    }

    Item2 item2 = new Item2();

    item2.setItemId( item1.getItemId() );
    item2.setTitle( item1.getTitle() );

    return item2;
}
自定義轉換類型
  • 使用表達式進行定義類型轉換,expression="java(。。。)"
    注意:使用表達式的時候,類必須是全路徑的使用,或者@Mapper(imports={類名.class}
@Mapper(imports={DemandSourceEnum.class})
public interface CarDealMapper {
 
 CarDealMapper INSTANCE = Mappers.getMapper(CarDealMapper.class);
 
    @Mappings({
            @Mapping(target = "demandSource", expression = "java(DemandSourceEnum.getMeaning(carDealDO.getDemandSource()))"),
    SaleDemandVO doToVo(CarDealDO carDealDO);
}
  • 自定義方法進行類型轉換
@Mapper
public interface ItemConvert {

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

    SkuDTO2 domain2Dto(Sku2 sku2);

    default Item2 item1ToItem2(Item1 item1) {
        if (item1 == null) {
            return null;
        }

        Item2 item2 = new Item2();

        item2.setItemId(11111L);
        item2.setTitle(item1.getTitle());

        return item2;
    }
}

// mapstruct 的實現類
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-07-30T18:38:11+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
)
public class ItemConvertImpl implements ItemConvert {

    @Override
    public SkuDTO2 domain2Dto(Sku2 sku2) {
        if ( sku2 == null ) {
            return null;
        }

        SkuDTO2 skuDTO2 = new SkuDTO2();

        skuDTO2.setSkuId( sku2.getSkuId() );
        skuDTO2.setSkuCode( sku2.getSkuCode() );
        if ( sku2.getSkuPrice() != null ) {
            skuDTO2.setSkuPrice( Long.parseLong( sku2.getSkuPrice() ) );
        }
        List<String> list = sku2.getNameList();
        if ( list != null ) {
            skuDTO2.setNameList( new ArrayList<String>( list ) );
        }
        // mapstruct直接調用的是在接口中自定義的實現
        skuDTO2.setItem( item1ToItem2( sku2.getItem() ) );

        return skuDTO2;
    }
}
  • 使用策略的方式進行類型轉換
    若是類型在很多Mapper中都需要使用,比較使用下例
public class BooleanStrategy {

    public String booleanToString(Boolean value) {

        if (value == null) {
            return "--";
        }

        return value ? "是" : "否";
    }

    public Integer booleanToInteger(Boolean value) {
        if (value == null) {
            return null;
        }

        return value ? 1 : 0;
    }

    public Boolean IntegerToBoolean(Integer value) {
        if (value == null) {
            return null;
        }

        return value == 0 ? false : true;
    }

    public String dateFormate(Date date) {

        if (date == null) {
            return "--";
        }

        return DateFormatUtils.format(date, "yyyy-MM-dd HH:mm:ss");
    }
}


@Mapper(uses = BooleanStrategy.class)
public interface CarDealMapper {
 CarDealMapper INSTANCE = Mappers.getMapper(CarDealMapper.class);
 
 CarDealDO dtoToDo(PlateCityMessageDTO plateCityMessageDTO);
}

方法中target和source 類型滿足 BooleanStrategy方法的,會自動進行調用這個方法的類型轉換進行處理

  • 自定義常量的方法

若是我們需要給一些屬性定義一個固定的值,這個時候可以使用 constant

    @Mapping(target = "whetherPass", constant = "true")
    CentralizedNewCarShipDTO doToDubboDto(CarDealDO carDealDO);
  • 特殊類型的轉換
  @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss", expression = "java(new Date())")
    CarDTO doToDTO(CarDO carDO);

另外還有numberFormat定義數字的格式轉換

  • 自定義初始值 defaultValue
    當source值爲空的時候則會使用defaultValue定義的值。而constant則是無論source是否爲空,都會使用constant定義的值,注意區分兩者
   /**
     * 單個參數的直接使用
     *
     * @param carDO source do
     * @return target dto
     */
    @Mapping(target = "userName", constant = "yby")
    @Mapping(target = "modelColor", source = "modelColor", defaultValue = "標緻")
    @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss", expression = "java(new Date())")
    CarDTO doToDTO(CarDO carDO);

額外的請參考 org.mapstruct.Mapping

Collection轉換

原理是遍歷source collection然後轉換類型,put到target collection中 如果是可以自動轉換的則自動轉換,同date type conversion;若是無法自動轉換的,則會查看是否有可以調用的類型

@Mapper(imports = Date.class)
public interface CarMapper {

    CarMapper INSTANCE = Mappers.getMapper(CarMapper.class);
    
     /**
     * 基本類型collection的轉換
     *
     * @param integers
     * @return
     */
    Set<String> integerSetToStringSet(Set<Integer> integers);

    /**
     * 調用存在已有方法的轉換
     *
     * @param cars
     * @return
     */
    List<CarDTO> carsToCarDtos(List<CarDO> cars);

    /**
     * 單個參數的直接使用
     *
     * @param carDO source do
     * @return target dto
     */
    @Mapping(target = "userName", constant = "yby")
    @Mapping(target = "modelColor", source = "modelColor", defaultValue = "標緻")
    @Mapping(target = "createTime", dateFormat = "yyyy-MM-dd HH:mm:ss", expression = "java(new Date())")
    CarDTO doToDTO(CarDO carDO);
    
    /**
     * DTO轉爲VO
     *
     * @param warehouseValidDTOList
     * @return
     */
    List<WarehouseValidPageVO> dtoToVo(List<WarehouseValidDTO> warehouseValidDTOList);
}

// mapstruct實現

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-07-30T19:27:05+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
)
public class CarMapperImpl implements CarMapper {
 
    @Override
    public Set<String> integerSetToStringSet(Set<Integer> integers) {
        if ( integers == null ) {
            return null;
        }

        Set<String> set = new HashSet<String>( Math.max( (int) ( integers.size() / .75f ) + 1, 16 ) );
        for ( Integer integer : integers ) {
            set.add( String.valueOf( integer ) );
        }

        return set;
    }

    @Override
    public List<CarDTO> carsToCarDtos(List<CarDO> cars) {
        if ( cars == null ) {
            return null;
        }

        List<CarDTO> list = new ArrayList<CarDTO>( cars.size() );
        for ( CarDO carDO : cars ) {
            list.add( doToDTO( carDO ) );
        }

        return list;
    }

    @Override
    public CarDTO doToDTO(CarDO carDO) {
        if ( carDO == null ) {
            return null;
        }

        CarDTO carDTO = new CarDTO();

        if ( carDO.getModelColor() != null ) {
            carDTO.setModelColor( carDO.getModelColor() );
        }
        else {
            carDTO.setModelColor( "標緻" );
        }
        if ( carDO.getNewCarGuidePrice() != null ) {
            carDTO.setNewCarGuidePrice( BigDecimal.valueOf( carDO.getNewCarGuidePrice() ) );
        }
        carDTO.setBrandCode( carDO.getBrandCode() );
        carDTO.setBrandName( carDO.getBrandName() );
        carDTO.setSeriesCode( carDO.getSeriesCode() );
        carDTO.setSeriesName( carDO.getSeriesName() );
        carDTO.setModelCode( carDO.getModelCode() );
        carDTO.setModelName( carDO.getModelName() );
        carDTO.setModelColorCode( carDO.getModelColorCode() );

        carDTO.setUserName( "yby" );
        carDTO.setCreateTime( new Date() );

        return carDTO;
    }
@Override
    public List<WarehouseValidPageVO> dtoToVo(List<WarehouseValidDTO> warehouseValidDTOList) {
        if ( warehouseValidDTOList == null ) {
            return null;
        }

        List<WarehouseValidPageVO> list = new ArrayList<WarehouseValidPageVO>( warehouseValidDTOList.size() );
        for ( WarehouseValidDTO warehouseValidDTO : warehouseValidDTOList ) {
            list.add( warehouseValidDTOToWarehouseValidPageVO( warehouseValidDTO ) );
        }

        return list;
    }

    protected WarehouseValidPageVO warehouseValidDTOToWarehouseValidPageVO(WarehouseValidDTO warehouseValidDTO) {
        if ( warehouseValidDTO == null ) {
            return null;
        }

        WarehouseValidPageVO warehouseValidPageVO = new WarehouseValidPageVO();

        warehouseValidPageVO.setId( warehouseValidDTO.getId() );
        warehouseValidPageVO.setWarehouseNo( warehouseValidDTO.getWarehouseNo() );
        warehouseValidPageVO.setWarehouseName( warehouseValidDTO.getWarehouseName() );
        warehouseValidPageVO.setPlateValid( warehouseValidDTO.getPlateValid() );

        return warehouseValidPageVO;
    }
}
map
public interface SourceTargetMapper {

    @MapMapping(valueDateFormat = "dd.MM.yyyy")
    Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source);
}

// mapstruct自己實現
@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2019-07-30T19:35:22+0800",
    comments = "version: 1.3.0.Final, compiler: javac, environment: Java 1.8.0_101 (Oracle Corporation)"
)
public class SourceTargetMapperImpl implements SourceTargetMapper {

    @Override
    public Map<String, String> longDateMapToStringStringMap(Map<Long, Date> source) {
        if ( source == null ) {
            return null;
        }

        Map<String, String> map = new HashMap<String, String>( Math.max( (int) ( source.size() / .75f ) + 1, 16 ) );

        for ( java.util.Map.Entry<Long, Date> entry : source.entrySet() ) {
            String key = new DecimalFormat( "" ).format( entry.getKey() );
            String value = new SimpleDateFormat( "dd.MM.yyyy" ).format( entry.getValue() );
            map.put( key, value );
        }

        return map;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章