MapStruct使用指南(二)——MapStruct数据类型转换

MapStruct数据类型转换

基本类型的转换

​ mapstruct会自动完成基本类型的一些隐式转换(包括:booleanbytecharintlongfloatdoubleString及其包装类等)

  • 相同基本类型可以直接转换

    @Mapping(target = "intValue", source = "intValue")    
    
  • 基本类型都可以转String类型,如int/Integer转String

    实际上使用的是string.valueOf()方法,支持所有基本类型转String。

    @Mapping(target = "stringValue", source = "intValue") 
    @Mapping(target = "stringValue", source = "booleanValue") 
    
  • 所有的数字类型及其包装类都可以直接转换,如int/Integer、long/Long之间转换。

    实际上会进行强制转换,长字节类型转短字节类型会发生截断,注意数据溢出,精度丢失等问题。

    @Mapping(target = "byteValue", source = "intValue")  
    
    // 生成代码示例,257强制转byte后溢出,实际为1
    target.setByteValue((byte) intValue);
    
  • 基本类型与其包装类型可以直接转换,且会自动生成判空代码

    @Mapping(target = "intValue", source = "integerValue")  
    
    // 生成代码示例,自动生成判空代码
    if (source.getIntegerValue() != null) {
        target.setIntValue( source.getIntegerValue() );
    }
    
    
  • StringBuilderString可以直接转换

  • 大数类型与基本类型及其包装类、String可以直接转换

时间类型转换

  • 隐式转换规则

    • java.time.Instantjava.util.Date直接转换
    • java.sql.Datejava.util.Date直接转换
    • java.sql.Time java.util.Date直接转换
    • java.sql.Timestamp java.util.Date直接转换
  • java.util.DateString,使用系统默认时区

    @Mapper
    public interface TimeMapper {
        TimeMapper INSTANCE = Mappers.getMapper(TimeMapper.class);
    
        @Mapping(target = "date", source = "date", dateFormat = "yyyy-MM-dd HH:MM:ss")
        TimeVo toTimeVo(TimeEntity timeEntity);
    }
    
    public class TimeEntity {
        private Date date;
    }
    
    public class TimeVo {
        private String date;
    }
    
  • java.util.Date可以与String转换,使用系统默认时区

    @Mapper
    public interface TimeMapper {
        TimeMapper INSTANCE = Mappers.getMapper(TimeMapper.class);
    
        @Mapping(target = "date", source = "instant", dateFormat = "yyyy-MM-dd HH:MM:ss")
        TimeVo toTimeVo(TimeEntity timeEntity);
    }
    
    public class TimeEntity {
    	private Instant instant;
    }
    
    public class TimeVo {
        private String date;
    }
    

集合类型的转换

  • 相同类型的集合可以直接转换

    @Mapping(target = "list", source = "list")
    
  • 基本类型(及其包装类)的相同集合可以直接转换

    ListList

    @Mapping(target = "integerList", source = "stringList")
    

    生成代码示例,自动生成一个stringListToIntegerList方法。

    target.setList( stringListToIntegerList( source.getList() ) );
    
    protected List<Integer> stringListToIntegerList(List<String> list) {
        if ( list == null ) {
            return null;
        }
    
        List<Integer> list1 = new ArrayList<Integer>( list.size() );
        for ( String string : list ) {
            list1.add( Integer.parseInt( string ) );
        }
    
        return list1;
    }
    
  • 同类型的ListSet可以直接转换

    @Mapping(target = "set", source = "list")
    

复杂集合的转换

枚举值的转换

两个Enum之间的转换

两个枚举值之间可以使用@ValueMapping进行转换,举例:对DML语句的进行分类,定义两个枚举,两个对象分别拥有这两个枚举属性

public enum DMLEnum {
    SELECT("SELECT * FROM test"),
    INSERT("INSERT INTO test VALUES(...)"),
    INSERT_OR_UPDATE("INSERT INTO test VALUES(...) ON DUPLICATE KEY UPDATE..."),
    UPDATE("UPDATE test SET ... WHERE ..."),
    DELETE("DELETE FROM test WHERE ...");

    private final String sql;

    DMLEnum(String sql) {
        this.sql = sql;
    }
}

public enum OperationEnum {
    CREATE,
    UPDATE,
    READ,
    DELETE
}

public class BaseVo {
    private OperationEnum operationEnum;
}

public class BaseEntity {
    private DMLEnum dmlEnum;
}

映射如下:

Entity
VO
SELECT
INSERT
INSERT_OR_UPDATE
UPDATE
DELETE
CREATE
UPDATE
READ
DELETE

Mapper:

@Mapper
public interface DMLMapper {

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

    @ValueMapping(target = "CREATE", source = "INSERT")
    @ValueMapping(target = "CREATE", source = "INSERT_OR_UPDATE")
    @ValueMapping(target = "READ", source = "SELECT")
    @ValueMapping(target = "UPDATE", source = "UPDATE")
    @ValueMapping(target = "DELETE", source = "DELETE")
    OperationEnum toOperationEnum(DMLEnum dmlEnum);
    
    @Mapping(target = "operationEnum", source = "dmlEnum")
    BaseVo toBaseVo(BaseEntity baseEntity);
}

测试:

public class DMLMapperTest {
    @Test
    public void test_toOperationEnum() {
        System.out.println(DMLMapper.INSTANCE.toOperationEnum(DMLEnum.INSERT_OR_UPDATE));
        System.out.println(DMLMapper.INSTANCE.toOperationEnum(DMLEnum.INSERT));
    }
    
    @Test
    public void test_toBaseVo() {
        BaseEntity baseEntity = new BaseEntity();
        baseEntity.setDmlEnum(DMLEnum.UPDATE);
        BaseV baseVo = DMLMapper.INSTANCE.toBaseVo(baseEntity);
        System.out.println(baseVo.getOperationEnum());
    }
}
/***************************************output******************************
*	CREATE
*	CREATE
****************************************************************************
*	UPDATE
****************************************************************************
枚举与字符串之间的转换

枚举的字面值(name()方法返回值)和字符串可以互相转换

枚举值->字符串

直接将枚举值映射为字符串值,以上面枚举DMLEnum为例,映射为字符串String

@Mapper
public interface DMLMapper {
    DMLMapper INSTANCE = Mappers.getMapper(DMLMapper.class);
    
    @Mapping(target = "dml", source = "dmlEnum")
    BaseVo toBaseVo(BaseEntity baseEntity);
}

public class BaseVo {
    private String dml;
}

public class BaseEntity {
    private DMLEnum dmlEnum;
}

测试

public class DMLMapperTest {
    @Test
    public void test_toBaseVo() {
        BaseEntity baseEntity = new BaseEntity();
        baseEntity.setDmlEnum(DMLEnum.UPDATE);
        BaseVo baseVo = DMLMapper.INSTANCE.toBaseVo(baseEntity);
        System.out.println(baseVo.getDml());
    }
}
/***************************************output******************************
*	UPDATE
****************************************************************************

字符串->枚举

@Mapper
public interface DMLMapper {
    DMLMapper INSTANCE = Mappers.getMapper(DMLMapper.class);
    
    @Mapping(target = "dmlEnum", source = "dml")
    BaseEntity toBaseEntity(BaseVo baseVo);
}

public class BaseVo {
    private String dml;
}

public class BaseEntity {
    private DMLEnum dmlEnum;
}

测试

public class DMLMapperTest {
    @Test
    public void test_toBaseEntity() {
        BaseVo baseVo = new BaseVo();
        baseVo.setDml("UPDATE");
        BaseEntity baseEntity = DMLMapper.INSTANCE.toBaseEntity(baseVo);
        System.out.println(baseEntity.getDmlEnum());
    }
}

/***************************************output******************************
*	UPDATE
****************************************************************************
字符串转枚举再转字符串

字符->找到对应枚举->得到枚举的字符串属性

dml: String -> dmlEnum: DMLEnum->sql: String

@Mapper
public interface DMLMapper {

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

    @Mapping(target = "sql", expression = "java(org.numb.mapstruct.entity.DMLEnum.fromName(baseVo.getDml()).getSql())")
    BaseEntity toBaseEntity(BaseVo baseVo);
}

public class BaseVo {
    private String dml;
}

public class BaseEntity {
    private String sql;
}

测试

public class DMLMapperTest {
    @Test
    public void test_toBaseEntity() {
        BaseVo baseVo = new BaseVo();
        baseVo.setDml("UPDATE");
        BaseEntity baseEntity = DMLMapper.INSTANCE.toBaseEntity(baseVo);
        System.out.println(baseEntity.getSql());
    }
}
/***************************************output******************************
*	UPDATE test SET ... WHERE ...
****************************************************************************

引用对象映射

mapstruct会自动识别并引用当前Mapper中的映射方法,如A对象包含B对象,C对象包含D对象。A对象映射为C对象,同时希望把B对象映射为D对象

C
A
D
B

可以在Mapper中同时定义A->C、B->D的映射对象,当A->C转换时,会自动调用C->D的映射。

如下,Car中包含Person对象,调用carToCarDto时会自动调用personToPersonDto

@Mapper
public interface CarMapper {

    CarDto carToCarDto(Car car);

    PersonDto personToPersonDto(Person person);
}

引用对象映射遵循一些规则:

  • 如果source和target类型相同(包括集合类),会调用set、constructor方法直接赋值

  • 如果source和target类型不同,会在当前Mapper中寻找有相同类型入参相同返回值类型的映射方法,如果存在则自动引用该方法。

  • 如果不存在上述映射方法,寻找是否有内置转换代码(built-in conversion)可以完成转换

  • 如果上述方法都不存在,mapstruct尝试自动生成转换方法

  • 如果不能完成转换,则报错。

自定义映射方法

如果Mapstruct有些场景不能完成,可以自定义转化方法

public interface CarMapper{
  	@Mapping(target = "personDto", source = "person")
    CarDto toCarDto(Car car);
   
    // 自定义方法实现
    static PersonDto toPersonDto(Person person) {
        PersonDto personDto = new PersonDto();
        // do something
        return personDto;
    }
}

也可以使用@Mapping的表达式属性expression显式指定某一个参数。注意expression不会自动导入,所以表达式中要使用其他类的方法,要带全类名(包名.类名.函数名)或者使用@Mapperimports显式导入所需要的类。

@Mapper(imports = {com.xxx.xxx.class})
public interface CarMapper{
  	@Mapping(target = "personDto", expression = "toPersonDto(person)")
    CarDto toCarDto(Car car);
   
    // 自定义方法实现
    static PersonDto toPersonDto(Person person) {
        PersonDto personDto = new PersonDto();
        // do something
        return personDto;
    }
}

你可能感兴趣的:(开发语言,java,spring,mapstrcut,DDD,领域驱动设计)