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")
    
  • 基本类型(及其包装类)的相同集合可以直接转换

    List<String>List<Integer>

    @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")
    
复杂集合的转换
  • 复杂List、Set的转换

    如需实现List<A>List<B>,可以先表示AB的方法toB(),再表示List<A>List<B>的方法toBList(),不需要显式调用toB()方法,mapstruct会在toBList()方法中自动循环调用toB()方法。

    @Getter
    @Setter
    @ToString
    public class A {
        private String aValue;
    }
    
    @Getter
    @Setter
    @ToString
    public class B {
        private String bValue;
    }
    
    @Mapper
    public interface Converter {
    	Converter INSTANCE = Mappers.getMapper(Converter.class);
        
        @Mapping(target = "bValue", source = "aValue")
        B toB(A a);
        
        // 不需要写任何注解,会自动调用toB(A a)方法
        List<B> toBList(List<A> aList);
    }
    
    

    生成代码示例:

    public List<B> toBList(List<A> aList) {
        if ( aList == null ) {
            return null;
        }
    
        List<B> list = new ArrayList<B>( aList.size() );
        for ( A a : aList ) {
            list.add( toBaseEntity( a ) );
        }
    
        return list;
    }
    
  • 复杂Map的转换

    如需要实现Map<A, C>转换为Map<B, D>,类似与List的转换,需要先分别实现A转换为BtoB()C转为DtoD()方法,然后再实现Map<A, C>转换为Map<B, D>toMap()方法

    @Getter
    @Setter
    @ToString
    public class A {
        private String aValue;
    }
    
    @Getter
    @Setter
    @ToString
    public class B {
        private String bValue;
    }
    
    @Getter
    @Setter
    @ToString
    public class C {
        private String cValue;
    }
    
    @Getter
    @Setter
    @ToString
    public class D {
        private String dValue;
    }
    
    
    @Mapper
    public interface Converter {
    	Converter INSTANCE = Mappers.getMapper(Converter.class);
        
        @Mapping(target = "bValue", source = "aValue")
        B toB(A a);
        
        @Mapping(target = "dValue", source = "cValue")
        D toD(C c);
        
        // 不需要写任何注解,会自动调用toB(A a)方法和D toD(C c)方法
        Map<B, D> toMap(Map<A, C> map);
    }
    

    生成代码示例:

    
    public Map<B, D> toMap(Map<A, C> map) {
        if ( map == null ) {
            return null;
        }
    
        Map<B, D> map = new HashMap<A, C>( Math.max( (int) ( baseVoMap.size() / .75f ) + 1, 16 ) );
    
        for ( java.util.Map.Entry<B, D> entry : map.entrySet() ) {
            B key = toB( entry.getKey() );
            D value = toD( entry.getValue() );
            map.put( key, value );
        }
    
        return map;
    }
    
枚举值的转换
两个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;
    }
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于MapStruct类型转换,您可以按照以下步骤进行操作: 1. 首先,在您的项目中添加MapStruct依赖。您可以在Maven或Gradle构建工具中添加相应的依赖项。 2. 创建源类型(source type)和目标类型(target type),这些类型可以是POJO(普通Java对象)。 3. 在源类型和目标类型之间创建一个Mapper接口。该接口应该使用`@Mapper`注解进行标记,并且可以定义多个转换方法。 4. 在转换方法中,使用`@Mapping`注解指定源类型和目标类型之间的映射关系。您可以使用属性名称、表达式或自定义转换器来定义映射规则。 5. 在您的代码中使用`Mapper`接口生成的实现类,通过调用转换方法进行类型转换。 下面是一个简单的示例: ```java // 源类型 public class Source { private String name; private int age; // getter和setter方法省略 } // 目标类型 public class Target { private String fullName; private int yearsOld; // getter和setter方法省略 } // Mapper接口 @Mapper public interface SourceTargetMapper { @Mapping(source = "name", target = "fullName") @Mapping(source = "age", target = "yearsOld") Target sourceToTarget(Source source); } // 使用转换器 public class Main { public static void main(String[] args) { Source source = new Source(); source.setName("John"); source.setAge(25); SourceTargetMapper mapper = Mappers.getMapper(SourceTargetMapper.class); Target target = mapper.sourceToTarget(source); System.out.println(target.getFullName()); // 输出: John System.out.println(target.getYearsOld()); // 输出: 25 } } ``` 通过以上步骤,您可以使用MapStruct进行源类型和目标类型之间的转换。请注意,MapStruct还支持更复杂的转换场景,例如集合映射和嵌套映射。您可以在MapStruct的官方文档中了解更多详细信息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值