diff --git a/README.md b/README.md index 2ca61ae..c8bf5a0 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/example/pom.xml b/example/pom.xml index 75ed9d8..8c4d04e 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -18,7 +18,7 @@ UTF-8 1.5.1.Final - 1.1.5 + 1.1.6 1.18.22 diff --git a/example/spring-boot-3/pom.xml b/example/spring-boot-3/pom.xml index 9dc5f19..4cd889f 100644 --- a/example/spring-boot-3/pom.xml +++ b/example/spring-boot-3/pom.xml @@ -12,8 +12,8 @@ spring-boot-3 - 17 - 17 + 8 + 8 UTF-8 @@ -55,8 +55,8 @@ maven-compiler-plugin 3.8.1 - 17 - 17 + 8 + 8 org.projectlombok diff --git a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/StringToListStringConverter.java b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/StringToListStringConverter.java index faafac9..95cffab 100644 --- a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/StringToListStringConverter.java +++ b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/StringToListStringConverter.java @@ -9,4 +9,8 @@ public class StringToListStringConverter { return Arrays.asList(str.split(",")); } + public static String listStringToString(List list) { + return String.join(",", list); + } + } diff --git a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/Order.java b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/Order.java new file mode 100644 index 0000000..d9b9d0a --- /dev/null +++ b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/Order.java @@ -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 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; + +} diff --git a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/OrderEntity.java b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/OrderEntity.java new file mode 100644 index 0000000..9975528 --- /dev/null +++ b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/OrderEntity.java @@ -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; + +} diff --git a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/OrderVO.java b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/OrderVO.java new file mode 100644 index 0000000..54347f2 --- /dev/null +++ b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/OrderVO.java @@ -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; + +} diff --git a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/User.java b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/User.java index b820578..10c3d2f 100644 --- a/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/User.java +++ b/example/spring-boot-with-lombok/src/main/java/io/github/linpeilie/model/User.java @@ -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 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({ diff --git a/example/spring-boot-with-lombok/src/test/java/io/github/linpeilie/QuickStartTest.java b/example/spring-boot-with-lombok/src/test/java/io/github/linpeilie/QuickStartTest.java index ddb2ec7..4acb0e3 100644 --- a/example/spring-boot-with-lombok/src/test/java/io/github/linpeilie/QuickStartTest.java +++ b/example/spring-boot-with-lombok/src/test/java/io/github/linpeilie/QuickStartTest.java @@ -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"); + } + } diff --git a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/AutoMapperProcessor.java b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/AutoMapperProcessor.java index 913d10c..d1320f6 100644 --- a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/AutoMapperProcessor.java +++ b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/AutoMapperProcessor.java @@ -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 mapperList = new ArrayList<>(); + private final Set 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 mapperSet = new HashSet<>(); - - // 去重 - mapperList.removeIf(mapper -> !mapperSet.add(mapper.mapperName())); - List 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,23 +256,25 @@ 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())); - // 需要继承的属性 - final List fieldMetadataList = - autoMapperMetadata.getFieldMappingList().stream().map(fieldMapping -> { - final AutoMappingMetadata autoMappingMetadata = new AutoMappingMetadata(); - autoMappingMetadata.setSource(fieldMapping.getTarget()); - autoMappingMetadata.setTarget(fieldMapping.getSource()); - return autoMappingMetadata; - }).collect(Collectors.toList()); - reverseMapperMetadata.setFieldMappingList(fieldMetadataList); + if (CollectionUtil.isNotEmpty(autoMapperMetadata.getFieldReverseMappingList())) { + reverseMapperMetadata.setFieldMappingList(autoMapperMetadata.getFieldReverseMappingList()); + } else { + // 需要继承的属性 + final List fieldMetadataList = + autoMapperMetadata.getFieldMappingList().stream().map(fieldMapping -> { + final AutoMappingMetadata autoMappingMetadata = new AutoMappingMetadata(); + autoMappingMetadata.setSource(fieldMapping.getTarget()); + autoMappingMetadata.setTarget(fieldMapping.getSource()); + 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 buildAutoMapperMetadataByAutoMappers(final Element ele) { final AutoMappers autoMappers = ele.getAnnotation(AutoMappers.class); if (autoMappers == null) { return null; } + Set 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 uses = transToClassNameList(autoMapper::uses); List 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 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 buildFieldReverseMappingMetadata(final TypeElement ele) { + List 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 buildFieldMappingMetadata(final TypeElement autoMapperEle) { List 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()); } + if (StrUtil.isNotEmpty(autoMapping.target())) { + metadata.setTarget(autoMapping.target()); + } else { + metadata.setTarget(ele.getSimpleName().toString()); + } metadata.setTargetClass(targetClass); - metadata.setTarget(autoMapping.target()); metadata.setDefaultValue(autoMapping.defaultValue()); metadata.setIgnore(autoMapping.ignore()); metadata.setExpression(autoMapping.expression()); diff --git a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/DuplicateMapperException.java b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/DuplicateMapperException.java new file mode 100644 index 0000000..67eee7e --- /dev/null +++ b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/DuplicateMapperException.java @@ -0,0 +1,8 @@ +package io.github.linpeilie.processor; + +public class DuplicateMapperException extends RuntimeException { + + public DuplicateMapperException(final String message) { + super(message); + } +} diff --git a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/generator/AutoMapperGenerator.java b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/generator/AutoMapperGenerator.java index 747632d..32c3eba 100644 --- a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/generator/AutoMapperGenerator.java +++ b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/generator/AutoMapperGenerator.java @@ -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", diff --git a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/metadata/AutoMapperMetadata.java b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/metadata/AutoMapperMetadata.java index 92ebcca..c10c0bb 100644 --- a/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/metadata/AutoMapperMetadata.java +++ b/mapstruct-plus-processor/src/main/java/io/github/linpeilie/processor/metadata/AutoMapperMetadata.java @@ -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 usesClassNameList; private List fieldMappingList; + private List 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 getFieldReverseMappingList() { + return fieldReverseMappingList; + } + + public void setFieldReverseMappingList(final List fieldReverseMappingList) { + this.fieldReverseMappingList = fieldReverseMappingList; + } + + public boolean isConvertGenerate() { + return convertGenerate; + } + + public void setConvertGenerate(final boolean convertGenerate) { + this.convertGenerate = convertGenerate; + } } diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapper.java b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapper.java index 7bf781e..550afde 100644 --- a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapper.java +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapper.java @@ -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; diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapping.java b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapping.java index 936c2cd..f864356 100644 --- a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapping.java +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/AutoMapping.java @@ -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 ""; diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/MapperConfig.java b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/MapperConfig.java index 2f28a8b..a1218ef 100644 --- a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/MapperConfig.java +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/MapperConfig.java @@ -18,6 +18,7 @@ public @interface MapperConfig { /** * 所生成的 Mapper 接口的包 + * @return Mapper 接口自动生成后的包名,如果为空,则默认生成在要转换的类同包下 */ String mapperPackage() default ""; diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/ReverseAutoMapping.java b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/ReverseAutoMapping.java new file mode 100644 index 0000000..ad0564f --- /dev/null +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/ReverseAutoMapping.java @@ -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; + +/** + * 由目标类生成当前类的配置 + *

+ * {@link AutoMapper} 的生成规则是由配置注解的当前类,生成与目标类之间的转换接口,所以其内部字段中的 {@link AutoMapping} 都是基于该条件来配置的。 + * 虽然默认情况下会生成目标类到当前类的转换,但如果自定义配置的话,仍需要到目标类上面进行配置。 + *

+ *

+ * 但现实情况中,可能会出现目标类,不能或者不建议增加配置注解,所以,这里提供一种在一种类上面自定义配置两个类转换的方式。 如果需要配置由目标类转换为配置注解的当前类具体转换逻辑的话,可以使用当前注解 + *

+ *

+ * 需要注意的是,如果在当前类中配置了该注解信息,则在目标类中不能够再定义与该类转换相关的注解,例如{@code AutoMapper}、{@code AutoMapping} + *

+ * + * @author linpl + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.CLASS) +public @interface ReverseAutoMapping { + + Class targetClass() default DefaultMapping.class; + + /** + * 来源,默认取当前字段名称 + *
  • 可以是当前类中的属性名
  • + *
  • 也可以是属性名.属性名,例如:address.city.name
+ * 这里的来源,指的是目标类中的字段信息 + * + * @return 目标类中的属性 + */ + String source() default ""; + + /** + * 目标属性,默认取当前字段名称 + *
    + *
  • 可以是当前类中的属性名
  • + *
  • 也可以是属性名.属性名,例如:address.city.name
  • + *
+ * + * @return 当前类中的属性 + */ + String target() default ""; + + String dateFormat() default ""; + + String numberFormat() default ""; + + String expression() default ""; + + boolean ignore() default false; + + /** + * 默认值 + * + * @return 当来源属性为null时,所设置的默认值 + */ + String defaultValue() default ""; + +} diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/ReverseAutoMappings.java b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/ReverseAutoMappings.java new file mode 100644 index 0000000..47ea79c --- /dev/null +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/annotations/ReverseAutoMappings.java @@ -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(); + +} diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/map/MapObjectConvert.java b/mapstruct-plus/src/main/java/io/github/linpeilie/map/MapObjectConvert.java index 1e1a653..6ad4a0e 100644 --- a/mapstruct-plus/src/main/java/io/github/linpeilie/map/MapObjectConvert.java +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/map/MapObjectConvert.java @@ -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); } diff --git a/pom.xml b/pom.xml index 6fef724..af11f26 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ pom ${mapstruct-plus.version} Mapstruct Plus - mapstruct增加工具包 + mapstruct增强工具包 mapstruct-plus mapstruct-plus-spring-boot-starter @@ -17,11 +17,11 @@ - 1.1.5 + 1.1.6 8 8 UTF-8 - 1.5.1.Final + 1.5.3.Final 5.8.9 https://github.com/linpeilie/mapstruct-plus.git