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 9d7150b..08d9f95 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 @@ -180,6 +180,7 @@ public class AutoMapperProcessor extends AbstractProcessor { // 根据配置生成适配类生成器 switch (AutoMapperProperties.getComponentModel()) { case MappingConstants.ComponentModel.SPRING: + case ContextConstants.ComponentModelConfig.springLazy: this.adapterMapperGenerator = new SpringAdapterMapperGenerator(); break; case ComponentModelConstant.SOLON: 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 19deb35..23b0db3 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 @@ -7,12 +7,12 @@ import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterizedTypeName; +import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import io.github.linpeilie.processor.ContextConstants; import io.github.linpeilie.processor.metadata.AutoMapperMetadata; import io.github.linpeilie.processor.metadata.AutoMappingMetadata; import io.github.linpeilie.utils.CollectionUtils; -import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; @@ -55,7 +55,7 @@ public class AutoMapperGenerator { JavaFile.builder(metadata.mapperPackage(), createTypeSpec(processingEnv, metadata, mapperName)) .build() .writeTo(writer); - } catch (IOException e) { + } catch (Exception e) { processingEnv.getMessager() .printMessage(ERROR, "Error while opening " + metadata.mapperName() + " output file: " + e.getMessage()); @@ -79,19 +79,69 @@ public class AutoMapperGenerator { ParameterSpec target = ParameterSpec.builder(targetClassName, "target") .addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build()) .build(); + ParameterSpec sourceList = ParameterSpec.builder( + ParameterizedTypeName.get( + ClassName.get("java.util", "List"), + metadata.getSourceClassName() + ), "sourceList").build(); ParameterSpec context = ParameterSpec.builder(ClassName.get("io.github.linpeilie", "CycleAvoidingMappingContext"), "context") .addAnnotation(ClassName.get("org.mapstruct", "Context")) .build(); - if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) { - builder.addMethod(addConvertMethodSpec( - metadata.isCycleAvoiding() ? CollectionUtils.newArrayList(source, context) : Collections.singletonList( - source), - metadata.getFieldMappingList(), - targetClassName, - CONVERT_METHOD_NAME)); + ParameterizedTypeName targetList = ParameterizedTypeName.get( + ClassName.get("java.util", "List"), + targetClassName + ); + + // 如果需要避免循环依赖,则把 BaseMapper 中的实现,全部添加 DoIgnore 防止使用该方法进行转换 + if (metadata.isCycleAvoiding()) { + // convert(source) + builder.addMethod( + addCallSuperConvertMethodSpec( + metadata.getSuperClass(), + CollectionUtils.newArrayList(source), + targetClassName, + CONVERT_METHOD_NAME) + ); + // convert(source, target) + builder.addMethod( + addCallSuperConvertMethodSpec( + metadata.getSuperClass(), CollectionUtils.newArrayList(source, target), + targetClassName, + CONVERT_METHOD_NAME + ) + ); + // convert(sourceList) + builder.addMethod( + addCallSuperConvertMethodSpec( + metadata.getSuperClass(), CollectionUtils.newArrayList(sourceList), + targetList, + CONVERT_METHOD_NAME + ) + ); + // convert(sourceList, context) + builder.addMethod( + addCallSuperConvertMethodSpec( + metadata.getSuperClass(), CollectionUtils.newArrayList(sourceList, context), + targetList, + CONVERT_METHOD_NAME + ) + ); } + // convert(source) | convert(source, context) + if (CollectionUtils.isNotEmpty(metadata.getFieldMappingList()) || metadata.isCycleAvoiding()) { + builder.addMethod(addConvertMethodSpec( + metadata.isCycleAvoiding() + ? CollectionUtils.newArrayList(source, context) + : Collections.singletonList(source), + metadata.getFieldMappingList(), + targetClassName, + CONVERT_METHOD_NAME, + metadata.isCycleAvoiding())); + } + + // convert(source, target) boolean targetIsImmutable = classIsImmutable(processingEnv, targetClassName); if (targetIsImmutable) { builder.addMethod( @@ -100,13 +150,15 @@ public class AutoMapperGenerator { context) : CollectionUtils.newArrayList(source, target), targetClassName, CONVERT_METHOD_NAME)); - } else if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) { + } else if (CollectionUtils.isNotEmpty(metadata.getFieldMappingList()) || metadata.isCycleAvoiding()) { builder.addMethod(addConvertMethodSpec( - metadata.isCycleAvoiding() ? CollectionUtils.newArrayList(source, target, - context) : CollectionUtils.newArrayList(source, target), + metadata.isCycleAvoiding() + ? CollectionUtils.newArrayList(source, target, context) + : CollectionUtils.newArrayList(source, target), metadata.getFieldMappingList(), targetClassName, - CONVERT_METHOD_NAME)); + CONVERT_METHOD_NAME, + metadata.isCycleAvoiding())); } return builder.build(); @@ -137,15 +189,50 @@ public class AutoMapperGenerator { private MethodSpec addConvertMethodSpec(List parameterSpecs, List autoMappingMetadataList, - ClassName target, String methodName) { + ClassName target, + String methodName, + boolean cycleAvoiding) { final MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(methodName) .addParameters(parameterSpecs) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) - .addAnnotation(ClassName.get(ContextConstants.DoIgnore.packageName, ContextConstants.DoIgnore.className)) .returns(target); if (CollectionUtils.isNotEmpty(autoMappingMetadataList)) { methodSpecBuilder.addAnnotations(buildMappingAnnotations(autoMappingMetadataList)); } + if (cycleAvoiding) { + methodSpecBuilder.addAnnotation( + ClassName.get(ContextConstants.DoIgnore.packageName, ContextConstants.DoIgnore.className)); + } + return methodSpecBuilder.build(); + } + + private ClassName doIgnore() { + return ClassName.get(ContextConstants.DoIgnore.packageName, ContextConstants.DoIgnore.className); + } + + private MethodSpec addCallSuperConvertMethodSpec(ClassName superClass, + List parameterSpecs, + TypeName target, + String methodName) { + MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(methodName) + .addParameters(parameterSpecs) + .addModifiers(Modifier.DEFAULT, Modifier.PUBLIC) + .addAnnotation(doIgnore()) + .returns(target); + + // return super.convert( *** ); + CodeBlock.Builder codeBlock = CodeBlock.builder(); + codeBlock.add("return $T.super.$L(", superClass, methodName); + for (int i = 0; i < parameterSpecs.size(); i++) { + codeBlock.add("$N", parameterSpecs.get(i)); + if (i != parameterSpecs.size() -1) { + codeBlock.add(","); + } + } + codeBlock.add(");\n"); + + methodSpecBuilder.addCode(codeBlock.build()); + return methodSpecBuilder.build(); } diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/BaseCycleAvoidingMapper.java b/mapstruct-plus/src/main/java/io/github/linpeilie/BaseCycleAvoidingMapper.java index 75ba1f6..48c7773 100644 --- a/mapstruct-plus/src/main/java/io/github/linpeilie/BaseCycleAvoidingMapper.java +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/BaseCycleAvoidingMapper.java @@ -1,6 +1,5 @@ package io.github.linpeilie; -import io.github.linpeilie.annotations.DoIgnore; import java.util.List; import java.util.stream.Collectors; import org.mapstruct.Context; @@ -8,13 +7,10 @@ import org.mapstruct.MappingTarget; public interface BaseCycleAvoidingMapper extends BaseMapper { - @DoIgnore T convert(S source, @Context CycleAvoidingMappingContext context); - @DoIgnore T convert(S source, @MappingTarget T target, @Context CycleAvoidingMappingContext context); - @DoIgnore default List convert(List sourceList, @Context CycleAvoidingMappingContext context) { return sourceList.stream() .map(item -> convert(item, context)) @@ -22,20 +18,17 @@ public interface BaseCycleAvoidingMapper extends BaseMapper { } @Override - @DoIgnore default T convert(S source) { return convert(source, new CycleAvoidingMappingContext()); } @Override - @DoIgnore default T convert(S source, @MappingTarget T target) { return convert(source, new CycleAvoidingMappingContext()); } @Override - @DoIgnore default List convert(List sourceList) { return convert(sourceList, new CycleAvoidingMappingContext()); } diff --git a/mapstruct-plus/src/main/java/io/github/linpeilie/BaseMapper.java b/mapstruct-plus/src/main/java/io/github/linpeilie/BaseMapper.java index a89fa3e..eec5536 100644 --- a/mapstruct-plus/src/main/java/io/github/linpeilie/BaseMapper.java +++ b/mapstruct-plus/src/main/java/io/github/linpeilie/BaseMapper.java @@ -1,6 +1,5 @@ package io.github.linpeilie; -import io.github.linpeilie.annotations.DoIgnore; import io.github.linpeilie.utils.CollectionUtils; import java.util.ArrayList; import java.util.List; @@ -9,13 +8,10 @@ import org.mapstruct.MappingTarget; public interface BaseMapper { - @DoIgnore T convert(S source); - @DoIgnore T convert(S source, @MappingTarget T target); - @DoIgnore default List convert(List sourceList) { if (CollectionUtils.isEmpty(sourceList)) { return new ArrayList<>();