mirror of
https://gitee.com/easii/mapstruct-plus.git
synced 2025-12-07 01:28:31 +08:00
modified the approach to avoid circular dependencies.
This commit is contained in:
parent
b12cd2b14a
commit
9bfe62a0c2
@ -180,6 +180,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
|||||||
// 根据配置生成适配类生成器
|
// 根据配置生成适配类生成器
|
||||||
switch (AutoMapperProperties.getComponentModel()) {
|
switch (AutoMapperProperties.getComponentModel()) {
|
||||||
case MappingConstants.ComponentModel.SPRING:
|
case MappingConstants.ComponentModel.SPRING:
|
||||||
|
case ContextConstants.ComponentModelConfig.springLazy:
|
||||||
this.adapterMapperGenerator = new SpringAdapterMapperGenerator();
|
this.adapterMapperGenerator = new SpringAdapterMapperGenerator();
|
||||||
break;
|
break;
|
||||||
case ComponentModelConstant.SOLON:
|
case ComponentModelConstant.SOLON:
|
||||||
|
|||||||
@ -7,12 +7,12 @@ import com.squareup.javapoet.JavaFile;
|
|||||||
import com.squareup.javapoet.MethodSpec;
|
import com.squareup.javapoet.MethodSpec;
|
||||||
import com.squareup.javapoet.ParameterSpec;
|
import com.squareup.javapoet.ParameterSpec;
|
||||||
import com.squareup.javapoet.ParameterizedTypeName;
|
import com.squareup.javapoet.ParameterizedTypeName;
|
||||||
|
import com.squareup.javapoet.TypeName;
|
||||||
import com.squareup.javapoet.TypeSpec;
|
import com.squareup.javapoet.TypeSpec;
|
||||||
import io.github.linpeilie.processor.ContextConstants;
|
import io.github.linpeilie.processor.ContextConstants;
|
||||||
import io.github.linpeilie.processor.metadata.AutoMapperMetadata;
|
import io.github.linpeilie.processor.metadata.AutoMapperMetadata;
|
||||||
import io.github.linpeilie.processor.metadata.AutoMappingMetadata;
|
import io.github.linpeilie.processor.metadata.AutoMappingMetadata;
|
||||||
import io.github.linpeilie.utils.CollectionUtils;
|
import io.github.linpeilie.utils.CollectionUtils;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -55,7 +55,7 @@ public class AutoMapperGenerator {
|
|||||||
JavaFile.builder(metadata.mapperPackage(), createTypeSpec(processingEnv, metadata, mapperName))
|
JavaFile.builder(metadata.mapperPackage(), createTypeSpec(processingEnv, metadata, mapperName))
|
||||||
.build()
|
.build()
|
||||||
.writeTo(writer);
|
.writeTo(writer);
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
processingEnv.getMessager()
|
processingEnv.getMessager()
|
||||||
.printMessage(ERROR,
|
.printMessage(ERROR,
|
||||||
"Error while opening " + metadata.mapperName() + " output file: " + e.getMessage());
|
"Error while opening " + metadata.mapperName() + " output file: " + e.getMessage());
|
||||||
@ -79,19 +79,69 @@ public class AutoMapperGenerator {
|
|||||||
ParameterSpec target = ParameterSpec.builder(targetClassName, "target")
|
ParameterSpec target = ParameterSpec.builder(targetClassName, "target")
|
||||||
.addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build())
|
.addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build())
|
||||||
.build();
|
.build();
|
||||||
|
ParameterSpec sourceList = ParameterSpec.builder(
|
||||||
|
ParameterizedTypeName.get(
|
||||||
|
ClassName.get("java.util", "List"),
|
||||||
|
metadata.getSourceClassName()
|
||||||
|
), "sourceList").build();
|
||||||
ParameterSpec context =
|
ParameterSpec context =
|
||||||
ParameterSpec.builder(ClassName.get("io.github.linpeilie", "CycleAvoidingMappingContext"), "context")
|
ParameterSpec.builder(ClassName.get("io.github.linpeilie", "CycleAvoidingMappingContext"), "context")
|
||||||
.addAnnotation(ClassName.get("org.mapstruct", "Context"))
|
.addAnnotation(ClassName.get("org.mapstruct", "Context"))
|
||||||
.build();
|
.build();
|
||||||
if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) {
|
ParameterizedTypeName targetList = ParameterizedTypeName.get(
|
||||||
builder.addMethod(addConvertMethodSpec(
|
ClassName.get("java.util", "List"),
|
||||||
metadata.isCycleAvoiding() ? CollectionUtils.newArrayList(source, context) : Collections.singletonList(
|
targetClassName
|
||||||
source),
|
);
|
||||||
metadata.getFieldMappingList(),
|
|
||||||
|
// 如果需要避免循环依赖,则把 BaseMapper 中的实现,全部添加 DoIgnore 防止使用该方法进行转换
|
||||||
|
if (metadata.isCycleAvoiding()) {
|
||||||
|
// convert(source)
|
||||||
|
builder.addMethod(
|
||||||
|
addCallSuperConvertMethodSpec(
|
||||||
|
metadata.getSuperClass(),
|
||||||
|
CollectionUtils.newArrayList(source),
|
||||||
targetClassName,
|
targetClassName,
|
||||||
CONVERT_METHOD_NAME));
|
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);
|
boolean targetIsImmutable = classIsImmutable(processingEnv, targetClassName);
|
||||||
if (targetIsImmutable) {
|
if (targetIsImmutable) {
|
||||||
builder.addMethod(
|
builder.addMethod(
|
||||||
@ -100,13 +150,15 @@ public class AutoMapperGenerator {
|
|||||||
context) : CollectionUtils.newArrayList(source, target),
|
context) : CollectionUtils.newArrayList(source, target),
|
||||||
targetClassName,
|
targetClassName,
|
||||||
CONVERT_METHOD_NAME));
|
CONVERT_METHOD_NAME));
|
||||||
} else if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) {
|
} else if (CollectionUtils.isNotEmpty(metadata.getFieldMappingList()) || metadata.isCycleAvoiding()) {
|
||||||
builder.addMethod(addConvertMethodSpec(
|
builder.addMethod(addConvertMethodSpec(
|
||||||
metadata.isCycleAvoiding() ? CollectionUtils.newArrayList(source, target,
|
metadata.isCycleAvoiding()
|
||||||
context) : CollectionUtils.newArrayList(source, target),
|
? CollectionUtils.newArrayList(source, target, context)
|
||||||
|
: CollectionUtils.newArrayList(source, target),
|
||||||
metadata.getFieldMappingList(),
|
metadata.getFieldMappingList(),
|
||||||
targetClassName,
|
targetClassName,
|
||||||
CONVERT_METHOD_NAME));
|
CONVERT_METHOD_NAME,
|
||||||
|
metadata.isCycleAvoiding()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
@ -137,15 +189,50 @@ public class AutoMapperGenerator {
|
|||||||
|
|
||||||
private MethodSpec addConvertMethodSpec(List<ParameterSpec> parameterSpecs,
|
private MethodSpec addConvertMethodSpec(List<ParameterSpec> parameterSpecs,
|
||||||
List<AutoMappingMetadata> autoMappingMetadataList,
|
List<AutoMappingMetadata> autoMappingMetadataList,
|
||||||
ClassName target, String methodName) {
|
ClassName target,
|
||||||
|
String methodName,
|
||||||
|
boolean cycleAvoiding) {
|
||||||
final MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(methodName)
|
final MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(methodName)
|
||||||
.addParameters(parameterSpecs)
|
.addParameters(parameterSpecs)
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
|
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
|
||||||
.addAnnotation(ClassName.get(ContextConstants.DoIgnore.packageName, ContextConstants.DoIgnore.className))
|
|
||||||
.returns(target);
|
.returns(target);
|
||||||
if (CollectionUtils.isNotEmpty(autoMappingMetadataList)) {
|
if (CollectionUtils.isNotEmpty(autoMappingMetadataList)) {
|
||||||
methodSpecBuilder.addAnnotations(buildMappingAnnotations(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<ParameterSpec> 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();
|
return methodSpecBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package io.github.linpeilie;
|
package io.github.linpeilie;
|
||||||
|
|
||||||
import io.github.linpeilie.annotations.DoIgnore;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.mapstruct.Context;
|
import org.mapstruct.Context;
|
||||||
@ -8,13 +7,10 @@ import org.mapstruct.MappingTarget;
|
|||||||
|
|
||||||
public interface BaseCycleAvoidingMapper<S, T> extends BaseMapper<S, T> {
|
public interface BaseCycleAvoidingMapper<S, T> extends BaseMapper<S, T> {
|
||||||
|
|
||||||
@DoIgnore
|
|
||||||
T convert(S source, @Context CycleAvoidingMappingContext context);
|
T convert(S source, @Context CycleAvoidingMappingContext context);
|
||||||
|
|
||||||
@DoIgnore
|
|
||||||
T convert(S source, @MappingTarget T target, @Context CycleAvoidingMappingContext context);
|
T convert(S source, @MappingTarget T target, @Context CycleAvoidingMappingContext context);
|
||||||
|
|
||||||
@DoIgnore
|
|
||||||
default List<T> convert(List<S> sourceList, @Context CycleAvoidingMappingContext context) {
|
default List<T> convert(List<S> sourceList, @Context CycleAvoidingMappingContext context) {
|
||||||
return sourceList.stream()
|
return sourceList.stream()
|
||||||
.map(item -> convert(item, context))
|
.map(item -> convert(item, context))
|
||||||
@ -22,20 +18,17 @@ public interface BaseCycleAvoidingMapper<S, T> extends BaseMapper<S, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DoIgnore
|
|
||||||
default T convert(S source) {
|
default T convert(S source) {
|
||||||
return convert(source, new CycleAvoidingMappingContext());
|
return convert(source, new CycleAvoidingMappingContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DoIgnore
|
|
||||||
default T convert(S source, @MappingTarget T target) {
|
default T convert(S source, @MappingTarget T target) {
|
||||||
return convert(source, new CycleAvoidingMappingContext());
|
return convert(source, new CycleAvoidingMappingContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DoIgnore
|
|
||||||
default List<T> convert(List<S> sourceList) {
|
default List<T> convert(List<S> sourceList) {
|
||||||
return convert(sourceList, new CycleAvoidingMappingContext());
|
return convert(sourceList, new CycleAvoidingMappingContext());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package io.github.linpeilie;
|
package io.github.linpeilie;
|
||||||
|
|
||||||
import io.github.linpeilie.annotations.DoIgnore;
|
|
||||||
import io.github.linpeilie.utils.CollectionUtils;
|
import io.github.linpeilie.utils.CollectionUtils;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -9,13 +8,10 @@ import org.mapstruct.MappingTarget;
|
|||||||
|
|
||||||
public interface BaseMapper<S, T> {
|
public interface BaseMapper<S, T> {
|
||||||
|
|
||||||
@DoIgnore
|
|
||||||
T convert(S source);
|
T convert(S source);
|
||||||
|
|
||||||
@DoIgnore
|
|
||||||
T convert(S source, @MappingTarget T target);
|
T convert(S source, @MappingTarget T target);
|
||||||
|
|
||||||
@DoIgnore
|
|
||||||
default List<T> convert(List<S> sourceList) {
|
default List<T> convert(List<S> sourceList) {
|
||||||
if (CollectionUtils.isEmpty(sourceList)) {
|
if (CollectionUtils.isEmpty(sourceList)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user