前言
对象属性转换 方式有很多
例如 各种beanUtils或者dozer 但是mapstruct 是类似lombok一样 在编译器直接生成性能最高的 直接调用set的方式
在编译器能够提示大多数的映射异常
示例
依赖和搭配lombok使用配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <lombok.version>1.18.20</lombok.version> <mapstruct.version>1.5.0.Beta1</mapstruct.version> <lombok-mapstruct-binding.version>0.1.0</lombok-mapstruct-binding.version> 。。。 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.mapstruct</groupId> <artifactId>mapstruct</artifactId> <version>${mapstruct.version}</version> </dependency>
。。。 <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${encoding}</encoding> <compilerArgs>--enable-preview</compilerArgs> <annotationProcessorPaths> <path> <groupId>org.mapstruct</groupId> <artifactId>mapstruct-processor</artifactId> <version>${mapstruct.version}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok-mapstruct-binding</artifactId> <version>${lombok-mapstruct-binding.version}</version> </path> </annotationProcessorPaths> </configuration> </plugin>
|
相关代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package com.ming.mapstuct;
import com.ming.core.utils.JSONSingleton; import com.ming.core.utils.TimeUtils; import org.mapstruct.Named; import org.springframework.stereotype.Component;
import java.net.URI; import java.time.LocalDate; import java.time.LocalDateTime;
@Component @Named(GlobalTypeConvertMapping.GLOBAL_TYPE_CONVERT_MAPPING) public class GlobalTypeConvertMapping { public static final String GLOBAL_TYPE_CONVERT_MAPPING = "GlobalTypeConvertMapping"; public static final String CONVERT_JSON_TO_STRING = "jsonToString"; public static final String CONVERT_OBJECT_TO_STRING = "objectToString"; public static final String CONVERT_URI_TO_URL_STRING = "uriToUrlString"; public static final String CONVERT_TIME_MILLIS_TO_LOCAL_DATE = "timeMillisToLocalDate"; public static final String CONVERT_LOCAL_DATE_TO_TIME_MILLIS = "localDateToTimeMillis";
@Named(CONVERT_JSON_TO_STRING) public String jsonToString(Object object) { return JSONSingleton.writeString(object); }
@Named(CONVERT_OBJECT_TO_STRING) public String objectToString(Object object) { return object.toString(); }
@Named(CONVERT_URI_TO_URL_STRING) public String uriToUrlString(URI uri) { return uri.getPath(); }
@Named(CONVERT_TIME_MILLIS_TO_LOCAL_DATE) public LocalDate timeMillisToLocalDate(long timeMillis) { return TimeUtils.toLocalDate(timeMillis); }
@Named(CONVERT_LOCAL_DATE_TO_TIME_MILLIS) public Long localDateTimeToMillis(LocalDateTime localDateTime) { return 20000L; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| package com.ming.mapstuct;
import lombok.Data; import org.mapstruct.*;
import java.time.LocalDateTime; import java.time.ZoneOffset;
@Mapper(componentModel = MappingConstants.ComponentModel.DEFAULT, uses = GlobalTypeConvertMapping.class) public interface TestMapper {
@Mappings({ @Mapping(source = "createTime", target = "createTimeStr") }) Demo12 convertDemo12(Demo11 demo11);
@Mappings({ @Mapping(target = "timeMillis", expression = ("java(System.currentTimeMillis())")), @Mapping(target = "flag", constant = "false"), }) Demo22 convertDemo21(Demo21 demo21);
@Mapping(source = "dateTime", target = "dateTimeMillis") Demo32 implicitConvertDemo31(Demo31 demo31);
default Long implicitLocalDateTimeToMillis(LocalDateTime localDateTime) { return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli(); }
@Mapping(source = "dateTime", target = "dateTimeMillis", qualifiedByName = "displayLocalDateTimeToMillis") Demo32 displayConvertDemo31(Demo31 demo31);
@Named("displayLocalDateTimeToMillis") default Long displayLocalDateTimeToMillis(LocalDateTime localDateTime) { return 10000L; }
@Mapping(source = "dateTime", target = "dateTimeMillis", qualifiedByName = GlobalTypeConvertMapping.CONVERT_LOCAL_DATE_TO_TIME_MILLIS) Demo32 superExtendsConvertDemo31(Demo31 demo31); }
@Data class Demo11 { private String name; private Integer age; private LocalDateTime createTime; }
@Data class Demo12 { private String name; private String age; private String createTimeStr; }
@Data class Demo21 { private String name; }
@Data class Demo22 { private String name; private Long timeMillis; private Boolean flag; }
@Data class Demo31 { private LocalDateTime dateTime; }
@Data class Demo32 { private Long dateTimeMillis; }
|
- mapper编译后生成的mapperImpl classes
此代码为mapper编译后生成的 用idea反编译出来看的
可以清晰的看到 按照mapping定义的方式 编译成对应的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
|
package com.ming.mapstuct;
import java.time.format.DateTimeFormatter;
public class TestMapperImpl implements TestMapper { private final GlobalTypeConvertMapping globalTypeConvertMapping = new GlobalTypeConvertMapping();
public TestMapperImpl() { }
public Demo12 convertDemo12(Demo11 demo11) { if (demo11 == null) { return null; } else { Demo12 demo12 = new Demo12(); if (demo11.getCreateTime() != null) { demo12.setCreateTimeStr(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(demo11.getCreateTime())); }
demo12.setName(demo11.getName()); if (demo11.getAge() != null) { demo12.setAge(String.valueOf(demo11.getAge())); }
return demo12; } }
public Demo22 convertDemo21(Demo21 demo21) { if (demo21 == null) { return null; } else { Demo22 demo22 = new Demo22(); demo22.setName(demo21.getName()); demo22.setTimeMillis(System.currentTimeMillis()); demo22.setFlag(false); return demo22; } }
public Demo32 implicitConvertDemo31(Demo31 demo31) { if (demo31 == null) { return null; } else { Demo32 demo32 = new Demo32(); demo32.setDateTimeMillis(this.implicitLocalDateTimeToMillis(demo31.getDateTime())); return demo32; } }
public Demo32 displayConvertDemo31(Demo31 demo31) { if (demo31 == null) { return null; } else { Demo32 demo32 = new Demo32(); demo32.setDateTimeMillis(this.displayLocalDateTimeToMillis(demo31.getDateTime())); return demo32; } }
public Demo32 superExtendsConvertDemo31(Demo31 demo31) { if (demo31 == null) { return null; } else { Demo32 demo32 = new Demo32(); demo32.setDateTimeMillis(this.globalTypeConvertMapping.localDateTimeToMillis(demo31.getDateTime())); return demo32; } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.ming.mapstuct;
import org.mapstruct.factory.Mappers;
import java.time.LocalDateTime;
public class Test {
private TestMapper getMapper() { return Mappers.getMapper(TestMapper.class); }
@org.junit.jupiter.api.Test public void test1() { Demo11 demo11 = new Demo11(); demo11.setName("ming"); demo11.setAge(200); demo11.setCreateTime(LocalDateTime.now()); System.out.println("demo11:" + demo11); System.out.println("demo12:" + getMapper().convertDemo12(demo11)); }
@org.junit.jupiter.api.Test public void test2() { Demo21 demo21 = new Demo21(); demo21.setName("ming"); System.out.println("demo21:" + demo21); System.out.println("demo22:" + getMapper().convertDemo21(demo21)); }
@org.junit.jupiter.api.Test public void test3() { Demo31 demo31 = new Demo31(); demo31.setDateTime(LocalDateTime.now()); System.out.println("demo31:" + demo31); System.out.println("隐式函数转换为时间戳-demo32:" + getMapper().implicitConvertDemo31(demo31)); System.out.println("显示函数转换固定值为10000-demo32:" + getMapper().displayConvertDemo31(demo31)); System.out.println("公共uses引用函数转换固定值为20000-demo32:" + getMapper().superExtendsConvertDemo31(demo31));
} }
|
1 2 3 4 5 6 7 8
| demo11:Demo11(name=ming, age=200, createTime=2022-02-11T17:57:09.729450200) demo12:Demo12(name=ming, age=200, createTimeStr=2022-02-11T17:57:09.7294502) demo21:Demo21(name=ming) demo22:Demo22(name=ming, timeMillis=1644573429759, flag=false) demo31:Demo31(dateTime=2022-02-11T17:57:09.762451900) 隐式函数转换为时间戳-demo32:Demo32(dateTimeMillis=1644573429762) 显示函数转换固定值为10000-demo32:Demo32(dateTimeMillis=10000) 公共uses引用函数转换固定值为20000-demo32:Demo32(dateTimeMillis=20000)
|
总结
其实使用cglib的BeanCopier 性能也不低 不过一些特殊情况就不好处理
mapstruct 定义比较清晰 而且编译期间可以提示大多数情况的错误
就是这玩意跟lombok一样 要影响编译
如果项目使用了静态增强的aop 配置起来会比较麻烦