mirror of
https://gitee.com/easii/mapstruct-plus.git
synced 2025-12-06 17:18:43 +08:00
- AutoMapper增加配置信息convertGenerate,配置是否生成转换的接口,可以控制不生成接口;
- 增加注解 ReverseAutoMapping,提升反向配置映射关系的功能 - AutoMapping target属性默认可以不填,不填则取当前字段
This commit is contained in:
parent
3301b668d9
commit
a22e35bb29
@ -9,6 +9,7 @@ Mapstruct Plus 是对 Mapstruct 框架的一个增强,只做增强,不做修
|
||||
## 链接
|
||||
|
||||
- [Document](https://mapstruct.plus)
|
||||
- [Mapstruct](https://mapstruct.org)
|
||||
- [Gitee](https://gitee.com/linpeilie/mapstruct-plus)
|
||||
- [Github](https://github.com/linpeilie/mapstruct-plus)
|
||||
- [彻底干掉 BeanUtils,最优雅的 Mapstruct 增强工具全新出炉](https://juejin.cn/post/7204307381688909882)
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mapstruct.version>1.5.1.Final</mapstruct.version>
|
||||
<mapstruct-plus.version>1.1.5</mapstruct-plus.version>
|
||||
<mapstruct-plus.version>1.1.6</mapstruct-plus.version>
|
||||
<lombok.version>1.18.22</lombok.version>
|
||||
</properties>
|
||||
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
<artifactId>spring-boot-3</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@ -55,8 +55,8 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>17</source>
|
||||
<target>17</target>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
||||
@ -9,4 +9,8 @@ public class StringToListStringConverter {
|
||||
return Arrays.asList(str.split(","));
|
||||
}
|
||||
|
||||
public static String listStringToString(List<String> list) {
|
||||
return String.join(",", list);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.StringToListStringConverter;
|
||||
import io.github.linpeilie.annotations.AutoMapMapper;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import io.github.linpeilie.annotations.AutoMappers;
|
||||
import io.github.linpeilie.annotations.AutoMapping;
|
||||
import io.github.linpeilie.annotations.ReverseAutoMapping;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMappers({
|
||||
@AutoMapper(target = OrderEntity.class, reverseConvertGenerate = false),
|
||||
// @AutoMapper(target = OrderVO.class)
|
||||
})
|
||||
public class Order {
|
||||
|
||||
private String orderId;
|
||||
|
||||
@AutoMapping(expression = "java(java.lang.String.join(\",\", source.getGoods()))")
|
||||
private List<String> goods;
|
||||
|
||||
@AutoMapping(numberFormat = "$0.00")
|
||||
private BigDecimal orderPrice;
|
||||
|
||||
@AutoMapping(numberFormat = "$0.00")
|
||||
private Integer goodsNum;
|
||||
|
||||
@AutoMapping(dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime orderTime;
|
||||
|
||||
@AutoMapping(dateFormat = "yyyy_MM_dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
@ReverseAutoMapping(target = "orderDate", dateFormat = "yyyy-MM-dd")
|
||||
private String date;
|
||||
|
||||
@AutoMapping(source = "user.username")
|
||||
private User user;
|
||||
|
||||
private Boolean payStatus;
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.ReverseAutoMapping;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Data;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@Data
|
||||
public class OrderEntity {
|
||||
|
||||
private String orderId;
|
||||
|
||||
private String goods;
|
||||
|
||||
private String orderPrice;
|
||||
|
||||
private String goodsNum;
|
||||
|
||||
private String orderTime;
|
||||
|
||||
private String createTime;
|
||||
|
||||
private LocalDate orderDate;
|
||||
|
||||
private String user;
|
||||
|
||||
private String payStatus;
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.StringToListStringConverter;
|
||||
import io.github.linpeilie.annotations.AutoMapMapper;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import io.github.linpeilie.annotations.AutoMapping;
|
||||
import io.github.linpeilie.annotations.AutoMappings;
|
||||
import io.github.linpeilie.annotations.ReverseAutoMapping;
|
||||
import java.time.LocalDate;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = Order.class, uses = StringToListStringConverter.class, convertGenerate = false)
|
||||
public class OrderVO {
|
||||
|
||||
private String orderId;
|
||||
|
||||
private String goods;
|
||||
|
||||
@ReverseAutoMapping(numberFormat = "$0.00")
|
||||
private String orderPrice;
|
||||
|
||||
@ReverseAutoMapping(ignore = true)
|
||||
private String goodsNum;
|
||||
|
||||
@ReverseAutoMapping(dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private String orderTime;
|
||||
|
||||
@ReverseAutoMapping(dateFormat = "yyyy_MM_dd HHmmss")
|
||||
private String createTime;
|
||||
|
||||
@ReverseAutoMapping(source = "date", dateFormat = "yyyy-MM-dd")
|
||||
private LocalDate orderDate;
|
||||
|
||||
@ReverseAutoMapping(source = "user.username")
|
||||
private String user;
|
||||
|
||||
@ReverseAutoMapping(defaultValue = "True")
|
||||
private String payStatus;
|
||||
|
||||
}
|
||||
@ -10,6 +10,7 @@ import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMappers({
|
||||
@AutoMapper(target = UserDto.class),
|
||||
@AutoMapper(target = UserDto.class),
|
||||
@AutoMapper(target = UserVO.class)
|
||||
})
|
||||
@ -24,15 +25,15 @@ public class User {
|
||||
private List<String> educationList;
|
||||
|
||||
@AutoMappings({
|
||||
@AutoMapping(targetClass = UserDto.class, target = "birthday", dateFormat = "yyyy-MM-dd HH:mm:ss"),
|
||||
@AutoMapping(targetClass = UserVO.class, target = "birthday", ignore = true)
|
||||
@AutoMapping(targetClass = UserDto.class, dateFormat = "yyyy-MM-dd HH:mm:ss"),
|
||||
@AutoMapping(targetClass = UserVO.class, ignore = true)
|
||||
})
|
||||
private Date birthday;
|
||||
|
||||
@AutoMapping(targetClass = UserDto.class, target = "assets", numberFormat = "$0.00")
|
||||
@AutoMapping(targetClass = UserDto.class, numberFormat = "$0.00")
|
||||
private double assets;
|
||||
|
||||
@AutoMapping(target = "money", numberFormat = "$0.00")
|
||||
@AutoMapping(numberFormat = "$0.00")
|
||||
private double money;
|
||||
|
||||
@AutoMappings({
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
package io.github.linpeilie;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import io.github.linpeilie.model.Goods;
|
||||
import io.github.linpeilie.model.GoodsDto;
|
||||
import io.github.linpeilie.model.GoodsVo;
|
||||
import io.github.linpeilie.model.MapModelA;
|
||||
import io.github.linpeilie.model.Order;
|
||||
import io.github.linpeilie.model.OrderVO;
|
||||
import io.github.linpeilie.model.Sku;
|
||||
import io.github.linpeilie.model.SysMenu;
|
||||
import io.github.linpeilie.model.SysMenuVo;
|
||||
import io.github.linpeilie.model.User;
|
||||
import io.github.linpeilie.model.UserDto;
|
||||
import io.github.linpeilie.model.UserVO;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
@ -42,10 +49,10 @@ public class QuickStartTest {
|
||||
mapModel1.put("mapModelB", mapModel2);
|
||||
|
||||
final MapModelA mapModelA = converter.convert(mapModel1, MapModelA.class);
|
||||
System.out.println(mapModelA); // MapModelA(str=1jkf1ijkj3f, i1=111, l2=11231, mapModelB=MapModelB(date=2023-02-23 01:03:23))
|
||||
System.out.println(
|
||||
mapModelA); // MapModelA(str=1jkf1ijkj3f, i1=111, l2=11231, mapModelB=MapModelB(date=2023-02-23 01:03:23))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void ueseTest() {
|
||||
UserDto userDto = new UserDto();
|
||||
@ -167,4 +174,32 @@ public class QuickStartTest {
|
||||
System.out.println(goodsVo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reverseMappingTest() {
|
||||
Order order = new Order();
|
||||
order.setOrderId("394bcab38052404ab404c791cb975596");
|
||||
order.setGoods(Arrays.asList("Apple", "Phone"));
|
||||
order.setOrderPrice(BigDecimal.valueOf(123.3421));
|
||||
order.setGoodsNum(32);
|
||||
order.setOrderTime(LocalDateTime.of(2023, 1, 3, 12, 23, 1));
|
||||
order.setCreateTime(DateUtil.parseDateTime("2023-01-03 11:06:01"));
|
||||
order.setDate("2022-03-01");
|
||||
User user = new User();
|
||||
user.setUsername("Jack");
|
||||
order.setUser(user);
|
||||
|
||||
OrderVO orderVO = converter.convert(order, OrderVO.class);
|
||||
System.out.println(orderVO);
|
||||
|
||||
Assert.equals(orderVO.getOrderId(), "394bcab38052404ab404c791cb975596");
|
||||
Assert.equals(orderVO.getGoods(), "Apple,Phone");
|
||||
Assert.equals(orderVO.getOrderPrice(), "$123.34");
|
||||
Assert.isNull(orderVO.getGoodsNum());
|
||||
Assert.equals(orderVO.getOrderTime(), "2023-01-03 12:23:01");
|
||||
Assert.equals(orderVO.getCreateTime(), "2023_01_03 110601");
|
||||
Assert.equals(orderVO.getOrderDate(), LocalDate.parse("2022-03-01", DateTimeFormatter.ofPattern("yyyy-MM-dd")));
|
||||
Assert.equals(orderVO.getUser(), "Jack");
|
||||
Assert.equals(orderVO.getPayStatus(), "True");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package io.github.linpeilie.processor;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.github.linpeilie.annotations.AutoMapMapper;
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
@ -8,6 +10,8 @@ import io.github.linpeilie.annotations.AutoMapping;
|
||||
import io.github.linpeilie.annotations.AutoMappings;
|
||||
import io.github.linpeilie.annotations.ComponentModelConfig;
|
||||
import io.github.linpeilie.annotations.MapperConfig;
|
||||
import io.github.linpeilie.annotations.ReverseAutoMapping;
|
||||
import io.github.linpeilie.annotations.ReverseAutoMappings;
|
||||
import io.github.linpeilie.processor.generator.AutoMapperGenerator;
|
||||
import io.github.linpeilie.processor.generator.DefaultAdapterMapperGenerator;
|
||||
import io.github.linpeilie.processor.generator.MapperConfigGenerator;
|
||||
@ -43,6 +47,7 @@ import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import static io.github.linpeilie.processor.Constants.AUTO_MAPPERS_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.AUTO_MAPPER_ANNOTATION;
|
||||
@ -69,6 +74,8 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
|
||||
private final List<AutoMapperMetadata> mapperList = new ArrayList<>();
|
||||
|
||||
private final Set<String> mapperSet = new HashSet<>();
|
||||
|
||||
public AutoMapperProcessor() {
|
||||
this.mapperGenerator = new AutoMapperGenerator();
|
||||
this.mapperConfigGenerator = new MapperConfigGenerator();
|
||||
@ -216,19 +223,17 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
private void generateMapper() {
|
||||
final Set<String> mapperSet = new HashSet<>();
|
||||
|
||||
// 去重
|
||||
mapperList.removeIf(mapper -> !mapperSet.add(mapper.mapperName()));
|
||||
|
||||
List<AutoMapperMetadata> reverseMapperMetadataList = new ArrayList<>();
|
||||
|
||||
mapperList.forEach(autoMapperMetadata -> {
|
||||
if (!autoMapperMetadata.isReverseConvertGenerate()) {
|
||||
return;
|
||||
}
|
||||
boolean defineReverseMapping = CollectionUtil.isNotEmpty(autoMapperMetadata.getFieldReverseMappingList());
|
||||
final AutoMapperMetadata reverseMapperMetadata = reverseMapper(autoMapperMetadata);
|
||||
if (!mapperSet.add(reverseMapperMetadata.mapperName())) {
|
||||
if (defineReverseMapping) {
|
||||
addMapper(reverseMapperMetadata);
|
||||
} else if (!mapperSet.add(reverseMapperMetadata.mapperName())) {
|
||||
return;
|
||||
}
|
||||
reverseMapperMetadataList.add(reverseMapperMetadata);
|
||||
@ -237,6 +242,9 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
mapperList.addAll(reverseMapperMetadataList);
|
||||
|
||||
mapperList.forEach(metadata -> {
|
||||
if (!metadata.isConvertGenerate()) {
|
||||
return;
|
||||
}
|
||||
this.writeAutoMapperClassFile(metadata);
|
||||
addAdapterMethod(metadata.getSourceClassName(), metadata.getTargetClassName(), metadata.mapperClass());
|
||||
});
|
||||
@ -248,14 +256,15 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
private AutoMapperMetadata reverseMapper(AutoMapperMetadata autoMapperMetadata) {
|
||||
AutoMapperMetadata reverseMapperMetadata = new AutoMapperMetadata();
|
||||
reverseMapperMetadata.setSourceClassName(autoMapperMetadata.getTargetClassName());
|
||||
reverseMapperMetadata.setTargetClassName(autoMapperMetadata.getSourceClassName());
|
||||
reverseMapperMetadata.setSuperClass(autoMapperMetadata.getSuperClass());
|
||||
reverseMapperMetadata.setSuperGenerics(
|
||||
new ClassName[] {reverseMapperMetadata.getSourceClassName(), reverseMapperMetadata.getTargetClassName()});
|
||||
AutoMapperMetadata reverseMapperMetadata = initAutoMapperMetadata(
|
||||
autoMapperMetadata.getTargetClassName(), autoMapperMetadata.getSourceClassName());
|
||||
reverseMapperMetadata.setConvertGenerate(autoMapperMetadata.isReverseConvertGenerate());
|
||||
reverseMapperMetadata.setUsesClassNameList(autoMapperMetadata.getUsesClassNameList());
|
||||
reverseMapperMetadata.setMapstructConfigClass(
|
||||
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getConfigClassName()));
|
||||
if (CollectionUtil.isNotEmpty(autoMapperMetadata.getFieldReverseMappingList())) {
|
||||
reverseMapperMetadata.setFieldMappingList(autoMapperMetadata.getFieldReverseMappingList());
|
||||
} else {
|
||||
// 需要继承的属性
|
||||
final List<AutoMappingMetadata> fieldMetadataList =
|
||||
autoMapperMetadata.getFieldMappingList().stream().map(fieldMapping -> {
|
||||
@ -265,6 +274,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
return autoMappingMetadata;
|
||||
}).collect(Collectors.toList());
|
||||
reverseMapperMetadata.setFieldMappingList(fieldMetadataList);
|
||||
}
|
||||
return reverseMapperMetadata;
|
||||
}
|
||||
|
||||
@ -293,12 +303,32 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
mapMethodMap.put(adapterMapMethodMetadata.getMethodName(), adapterMapMethodMetadata);
|
||||
}
|
||||
|
||||
private AutoMapperMetadata initAutoMapperMetadata(ClassName source, ClassName target) {
|
||||
AutoMapperMetadata metadata = new AutoMapperMetadata();
|
||||
|
||||
metadata.setSourceClassName(source);
|
||||
metadata.setTargetClassName(target);
|
||||
metadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseMapper"));
|
||||
metadata.setSuperGenerics(new ClassName[] {source, target});
|
||||
metadata.setMapstructConfigClass(
|
||||
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getConfigClassName()));
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private List<AutoMapperMetadata> buildAutoMapperMetadataByAutoMappers(final Element ele) {
|
||||
final AutoMappers autoMappers = ele.getAnnotation(AutoMappers.class);
|
||||
if (autoMappers == null) {
|
||||
return null;
|
||||
}
|
||||
Set<String> targetClassNames = new HashSet<>();
|
||||
return Arrays.stream(autoMappers.value())
|
||||
.filter(autoMapper -> {
|
||||
ClassName className = transToClassName(autoMapper::target);
|
||||
if (className == null) {
|
||||
return false;
|
||||
}
|
||||
return targetClassNames.add(className.reflectionName());
|
||||
})
|
||||
.map(autoMapper -> buildAutoMapperMetadata(autoMapper, ele))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@ -311,6 +341,31 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
return buildAutoMapperMetadata(autoMapperAnnotation, ele);
|
||||
}
|
||||
|
||||
private boolean hasReverseAutoMapping(Element ele) {
|
||||
TypeElement typeElement = (TypeElement) ele;
|
||||
if (!typeElement.getKind().isClass()) {
|
||||
return false;
|
||||
}
|
||||
return typeElement.getEnclosedElements()
|
||||
.stream().anyMatch(e -> {
|
||||
if (e.getKind() != ElementKind.FIELD) {
|
||||
return false;
|
||||
}
|
||||
return e.getAnnotation(ReverseAutoMapping.class) != null
|
||||
|| e.getAnnotation(ReverseAutoMappings.class) != null;
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isTargetFieldMapping(ClassName target, AutoMappingMetadata mappingMetadata) {
|
||||
if (MAPPING_DEFAULT_TARGET.reflectionName().contentEquals(mappingMetadata.getTargetClass().reflectionName())) {
|
||||
return true;
|
||||
}
|
||||
if (target.reflectionName().contentEquals(mappingMetadata.getTargetClass().reflectionName())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private AutoMapperMetadata buildAutoMapperMetadata(final AutoMapper autoMapper, final Element ele) {
|
||||
ClassName source = ClassName.get((TypeElement) ele);
|
||||
ClassName target = transToClassName(autoMapper::target);
|
||||
@ -319,31 +374,85 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
List<ClassName> uses = transToClassNameList(autoMapper::uses);
|
||||
List<AutoMappingMetadata> autoMappingMetadataList = buildFieldMappingMetadata((TypeElement) ele);
|
||||
autoMappingMetadataList.removeIf(mappingMetadata -> {
|
||||
if (MAPPING_DEFAULT_TARGET.reflectionName()
|
||||
.contentEquals(mappingMetadata.getTargetClass().reflectionName())) {
|
||||
return false;
|
||||
}
|
||||
if (target.reflectionName().contentEquals(mappingMetadata.getTargetClass().reflectionName())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
autoMappingMetadataList.removeIf(mappingMetadata -> !isTargetFieldMapping(target, mappingMetadata));
|
||||
|
||||
AutoMapperMetadata metadata = new AutoMapperMetadata();
|
||||
List<AutoMappingMetadata> reverseMappingMetadataList = buildFieldReverseMappingMetadata((TypeElement) ele);
|
||||
reverseMappingMetadataList.removeIf(mappingMetadata -> !isTargetFieldMapping(target, mappingMetadata));
|
||||
|
||||
AutoMapperMetadata metadata = initAutoMapperMetadata(source, target);
|
||||
|
||||
metadata.setSourceClassName(source);
|
||||
metadata.setTargetClassName(target);
|
||||
metadata.setUsesClassNameList(uses);
|
||||
metadata.setFieldMappingList(autoMappingMetadataList);
|
||||
metadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseMapper"));
|
||||
metadata.setSuperGenerics(new ClassName[] {source, target});
|
||||
metadata.setMapstructConfigClass(
|
||||
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getConfigClassName()));
|
||||
metadata.setFieldReverseMappingList(reverseMappingMetadataList);
|
||||
metadata.setConvertGenerate(autoMapper.convertGenerate());
|
||||
metadata.setReverseConvertGenerate(autoMapper.reverseConvertGenerate());
|
||||
|
||||
addMapper(metadata);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private List<AutoMappingMetadata> buildFieldReverseMappingMetadata(final TypeElement ele) {
|
||||
List<AutoMappingMetadata> list = new ArrayList<>();
|
||||
if (!ele.getKind().isClass()) {
|
||||
return list;
|
||||
}
|
||||
for (Element field : ele.getEnclosedElements()) {
|
||||
if (field.getKind() != ElementKind.FIELD) {
|
||||
continue;
|
||||
}
|
||||
ReverseAutoMapping reverseAutoMapping = field.getAnnotation(ReverseAutoMapping.class);
|
||||
if (reverseAutoMapping != null) {
|
||||
list.add(buildAutoMappingMetadata(reverseAutoMapping, field, ele));
|
||||
}
|
||||
ReverseAutoMappings reverseAutoMappings = field.getAnnotation(ReverseAutoMappings.class);
|
||||
if (reverseAutoMappings != null) {
|
||||
for (ReverseAutoMapping mapping : reverseAutoMappings.value()) {
|
||||
list.add(buildAutoMappingMetadata(mapping, field, ele));
|
||||
}
|
||||
}
|
||||
}
|
||||
list.removeIf(Objects::isNull);
|
||||
return list;
|
||||
}
|
||||
|
||||
private AutoMappingMetadata buildAutoMappingMetadata(ReverseAutoMapping reverseAutoMapping,
|
||||
Element ele,
|
||||
TypeElement type) {
|
||||
ClassName targetClass = transToClassName(reverseAutoMapping::targetClass);
|
||||
if (targetClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AutoMappingMetadata metadata = new AutoMappingMetadata();
|
||||
if (StrUtil.isNotEmpty(reverseAutoMapping.source())) {
|
||||
metadata.setSource(reverseAutoMapping.source());
|
||||
} else {
|
||||
metadata.setSource(ele.getSimpleName().toString());
|
||||
}
|
||||
if (StrUtil.isNotEmpty(reverseAutoMapping.target())) {
|
||||
metadata.setTarget(reverseAutoMapping.target());
|
||||
} else {
|
||||
metadata.setTarget(ele.getSimpleName().toString());
|
||||
}
|
||||
metadata.setTargetClass(targetClass);
|
||||
metadata.setDefaultValue(reverseAutoMapping.defaultValue());
|
||||
metadata.setIgnore(reverseAutoMapping.ignore());
|
||||
metadata.setExpression(reverseAutoMapping.expression());
|
||||
metadata.setDateFormat(reverseAutoMapping.dateFormat());
|
||||
metadata.setNumberFormat(reverseAutoMapping.numberFormat());
|
||||
return metadata;
|
||||
}
|
||||
|
||||
private void addMapper(AutoMapperMetadata metadata) {
|
||||
if (!mapperSet.add(metadata.mapperName())) {
|
||||
throw new DuplicateMapperException("An exception occurred to generate " + metadata.mapperName()
|
||||
+ ", check the mapping configuration for "
|
||||
+ metadata.getSourceClassName().reflectionName()
|
||||
+ " or " + metadata.getTargetClassName().reflectionName());
|
||||
}
|
||||
}
|
||||
|
||||
private List<AutoMappingMetadata> buildFieldMappingMetadata(final TypeElement autoMapperEle) {
|
||||
List<AutoMappingMetadata> list = new ArrayList<>();
|
||||
|
||||
@ -378,13 +487,17 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
AutoMappingMetadata metadata = new AutoMappingMetadata();
|
||||
if (autoMapping.source() != null && !autoMapping.source().isEmpty()) {
|
||||
if (StrUtil.isNotEmpty(autoMapping.source())) {
|
||||
metadata.setSource(autoMapping.source());
|
||||
} else {
|
||||
metadata.setSource(ele.getSimpleName().toString());
|
||||
}
|
||||
metadata.setTargetClass(targetClass);
|
||||
if (StrUtil.isNotEmpty(autoMapping.target())) {
|
||||
metadata.setTarget(autoMapping.target());
|
||||
} else {
|
||||
metadata.setTarget(ele.getSimpleName().toString());
|
||||
}
|
||||
metadata.setTargetClass(targetClass);
|
||||
metadata.setDefaultValue(autoMapping.defaultValue());
|
||||
metadata.setIgnore(autoMapping.ignore());
|
||||
metadata.setExpression(autoMapping.expression());
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
package io.github.linpeilie.processor;
|
||||
|
||||
public class DuplicateMapperException extends RuntimeException {
|
||||
|
||||
public DuplicateMapperException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -23,6 +23,7 @@ import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import static io.github.linpeilie.processor.Constants.*;
|
||||
|
||||
@ -76,13 +77,16 @@ public class AutoMapperGenerator {
|
||||
.addMember("target", CodeBlock.builder().add("$S", autoMappingMetadata.getTarget()).build())
|
||||
.addMember("ignore", CodeBlock.builder().add(String.valueOf(autoMappingMetadata.isIgnore())).build());
|
||||
if (StrUtil.isNotEmpty(autoMappingMetadata.getDateFormat())) {
|
||||
builder.addMember("dateFormat", CodeBlock.builder().add("$S", autoMappingMetadata.getDateFormat()).build());
|
||||
builder.addMember("dateFormat",
|
||||
CodeBlock.builder().add("$S", autoMappingMetadata.getDateFormat()).build());
|
||||
}
|
||||
if (StrUtil.isNotEmpty(autoMappingMetadata.getNumberFormat())) {
|
||||
builder.addMember("numberFormat", CodeBlock.builder().add("$S", autoMappingMetadata.getNumberFormat()).build());
|
||||
builder.addMember("numberFormat",
|
||||
CodeBlock.builder().add("$S", autoMappingMetadata.getNumberFormat()).build());
|
||||
}
|
||||
if (StrUtil.isNotEmpty(autoMappingMetadata.getDefaultValue())) {
|
||||
builder.addMember("defaultValue", CodeBlock.builder().add("$S", autoMappingMetadata.getDefaultValue()).build());
|
||||
builder.addMember("defaultValue",
|
||||
CodeBlock.builder().add("$S", autoMappingMetadata.getDefaultValue()).build());
|
||||
}
|
||||
if (StringUtils.isNoneEmpty(autoMappingMetadata.getExpression())) {
|
||||
builder.addMember("expression",
|
||||
|
||||
@ -1,24 +1,28 @@
|
||||
package io.github.linpeilie.processor.metadata;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.github.linpeilie.processor.AutoMapperProperties;
|
||||
import java.util.List;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
public class AutoMapperMetadata extends AbstractMapperMetadata {
|
||||
|
||||
|
||||
|
||||
private ClassName targetClassName;
|
||||
|
||||
private List<ClassName> usesClassNameList;
|
||||
|
||||
private List<AutoMappingMetadata> fieldMappingList;
|
||||
|
||||
private List<AutoMappingMetadata> fieldReverseMappingList;
|
||||
|
||||
private ClassName superClass;
|
||||
|
||||
private ClassName[] superGenerics;
|
||||
|
||||
private ClassName mapstructConfigClass;
|
||||
|
||||
private boolean convertGenerate;
|
||||
|
||||
private boolean reverseConvertGenerate;
|
||||
|
||||
public String mapperName() {
|
||||
@ -83,4 +87,20 @@ public class AutoMapperMetadata extends AbstractMapperMetadata {
|
||||
public void setReverseConvertGenerate(final boolean reverseConvertGenerate) {
|
||||
this.reverseConvertGenerate = reverseConvertGenerate;
|
||||
}
|
||||
|
||||
public List<AutoMappingMetadata> getFieldReverseMappingList() {
|
||||
return fieldReverseMappingList;
|
||||
}
|
||||
|
||||
public void setFieldReverseMappingList(final List<AutoMappingMetadata> fieldReverseMappingList) {
|
||||
this.fieldReverseMappingList = fieldReverseMappingList;
|
||||
}
|
||||
|
||||
public boolean isConvertGenerate() {
|
||||
return convertGenerate;
|
||||
}
|
||||
|
||||
public void setConvertGenerate(final boolean convertGenerate) {
|
||||
this.convertGenerate = convertGenerate;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,9 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* @author linpl
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface AutoMapper {
|
||||
@ -13,11 +16,17 @@ public @interface AutoMapper {
|
||||
|
||||
Class<?>[] uses() default {};
|
||||
|
||||
/**
|
||||
* 是否生成转换的接口,当只想生成反向接口时,可以指定当前属性为 {@code false}
|
||||
*
|
||||
* @return {@code true} 生成类型转换的接口 {@code false} 不生成类型转换的接口
|
||||
*/
|
||||
boolean convertGenerate() default true;
|
||||
|
||||
/**
|
||||
* 是否生成反向转换的接口
|
||||
*
|
||||
* @return true : 生成反向转换的接口
|
||||
* false : 不生成反向转换的接口
|
||||
* @return true : 生成反向转换的接口 false : 不生成反向转换的接口
|
||||
*/
|
||||
boolean reverseConvertGenerate() default true;
|
||||
|
||||
|
||||
@ -16,10 +16,11 @@ public @interface AutoMapping {
|
||||
* 来源,默认取当前字段名称
|
||||
* - 可以是当前类中的属性名
|
||||
* - 也可以是属性名.属性名,例如:address.city.name
|
||||
* @return 当前类中的属性
|
||||
*/
|
||||
String source() default "";
|
||||
|
||||
String target();
|
||||
String target() default "";
|
||||
|
||||
String dateFormat() default "";
|
||||
|
||||
@ -31,6 +32,7 @@ public @interface AutoMapping {
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
* @return 当源属性为null时,设置的默认值
|
||||
*/
|
||||
String defaultValue() default "";
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@ public @interface MapperConfig {
|
||||
|
||||
/**
|
||||
* 所生成的 Mapper 接口的包
|
||||
* @return Mapper 接口自动生成后的包名,如果为空,则默认生成在要转换的类同包下
|
||||
*/
|
||||
String mapperPackage() default "";
|
||||
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
package io.github.linpeilie.annotations;
|
||||
|
||||
import io.github.linpeilie.DefaultMapping;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 由目标类生成当前类的配置
|
||||
* <p>
|
||||
* {@link AutoMapper} 的生成规则是由配置注解的当前类,生成与目标类之间的转换接口,所以其内部字段中的 {@link AutoMapping} 都是基于该条件来配置的。
|
||||
* 虽然默认情况下会生成目标类到当前类的转换,但如果自定义配置的话,仍需要到目标类上面进行配置。
|
||||
* </p>
|
||||
* <p>
|
||||
* 但现实情况中,可能会出现目标类,不能或者不建议增加配置注解,所以,这里提供一种在一种类上面自定义配置两个类转换的方式。 如果需要配置由目标类转换为配置注解的当前类具体转换逻辑的话,可以使用当前注解
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>需要注意的是,如果在当前类中配置了该注解信息,则在目标类中不能够再定义与该类转换相关的注解,例如{@code AutoMapper}、{@code AutoMapping}</strong>
|
||||
* </p>
|
||||
*
|
||||
* @author linpl
|
||||
*/
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface ReverseAutoMapping {
|
||||
|
||||
Class<?> targetClass() default DefaultMapping.class;
|
||||
|
||||
/**
|
||||
* 来源,默认取当前字段名称
|
||||
* <ul><li>可以是当前类中的属性名</li>
|
||||
* <li>也可以是属性名.属性名,例如:address.city.name</li></ul>
|
||||
* <strong>这里的来源,指的是目标类中的字段信息</strong>
|
||||
*
|
||||
* @return 目标类中的属性
|
||||
*/
|
||||
String source() default "";
|
||||
|
||||
/**
|
||||
* 目标属性,默认取当前字段名称
|
||||
* <ul>
|
||||
* <li>可以是当前类中的属性名</li>
|
||||
* <li>也可以是属性名.属性名,例如:address.city.name</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return 当前类中的属性
|
||||
*/
|
||||
String target() default "";
|
||||
|
||||
String dateFormat() default "";
|
||||
|
||||
String numberFormat() default "";
|
||||
|
||||
String expression() default "";
|
||||
|
||||
boolean ignore() default false;
|
||||
|
||||
/**
|
||||
* 默认值
|
||||
*
|
||||
* @return 当来源属性为null时,所设置的默认值
|
||||
*/
|
||||
String defaultValue() default "";
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package io.github.linpeilie.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
public @interface ReverseAutoMappings {
|
||||
|
||||
ReverseAutoMapping[] value();
|
||||
|
||||
}
|
||||
@ -38,10 +38,6 @@ public class MapObjectConvert {
|
||||
return Convert.toDouble(obj);
|
||||
}
|
||||
|
||||
public static Number objToNumber(Object obj) {
|
||||
return Convert.toNumber(obj);
|
||||
}
|
||||
|
||||
public static Boolean objToBoolean(Object obj) {
|
||||
return Convert.toBool(obj);
|
||||
}
|
||||
|
||||
6
pom.xml
6
pom.xml
@ -9,7 +9,7 @@
|
||||
<packaging>pom</packaging>
|
||||
<version>${mapstruct-plus.version}</version>
|
||||
<name>Mapstruct Plus</name>
|
||||
<description>mapstruct增加工具包</description>
|
||||
<description>mapstruct增强工具包</description>
|
||||
<modules>
|
||||
<module>mapstruct-plus</module>
|
||||
<module>mapstruct-plus-spring-boot-starter</module>
|
||||
@ -17,11 +17,11 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<mapstruct-plus.version>1.1.5</mapstruct-plus.version>
|
||||
<mapstruct-plus.version>1.1.6</mapstruct-plus.version>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mapstruct.version>1.5.1.Final</mapstruct.version>
|
||||
<mapstruct.version>1.5.3.Final</mapstruct.version>
|
||||
<hutool.version>5.8.9</hutool.version>
|
||||
<projectUrl>https://github.com/linpeilie/mapstruct-plus.git</projectUrl>
|
||||
</properties>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user