mirror of
https://gitee.com/easii/mapstruct-plus.git
synced 2025-12-06 17:18:43 +08:00
- 适配对象循环嵌套
- 优化转换逻辑
This commit is contained in:
parent
19f163d174
commit
4e103c7cd1
@ -0,0 +1,19 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = DeptDTO.class)
|
||||
public class Dept {
|
||||
|
||||
private String code;
|
||||
|
||||
private String name;
|
||||
|
||||
private Long parentId;
|
||||
|
||||
private Set<Dept> children;
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = Dept.class)
|
||||
public class DeptDTO {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Set<DeptDTO> children;
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = Employee1Dto.class)
|
||||
public class Employee1 {
|
||||
|
||||
private Employee employee;
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = Employee1.class)
|
||||
public class Employee1Dto {
|
||||
|
||||
private EmployeeDto employee;
|
||||
|
||||
}
|
||||
@ -1,10 +1,12 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = ProductPropertyDto.class, cycles = true)
|
||||
public class ProductProperty {
|
||||
|
||||
private Long id;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
package io.github.linpeilie.model;
|
||||
|
||||
import io.github.linpeilie.annotations.AutoMapper;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@AutoMapper(target = ProductProperty.class, cycles = true)
|
||||
public class ProductPropertyDto {
|
||||
|
||||
private Long id;
|
||||
|
||||
@ -9,38 +9,78 @@ import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
|
||||
import io.github.linpeilie.processor.metadata.AdapterMapMethodMetadata;
|
||||
import io.github.linpeilie.processor.metadata.AdapterMethodMetadata;
|
||||
import io.github.linpeilie.processor.utils.ClassUtil;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
|
||||
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||
|
||||
public abstract class AbstractAdapterMapperGenerator {
|
||||
|
||||
protected static final String PARAM__PARAMETER_NAME = "param";
|
||||
|
||||
protected static final String CONTEXT__PARAMETER_NAME = "context";
|
||||
|
||||
public void write(ProcessingEnvironment processingEnv,
|
||||
Collection<AbstractAdapterMethodMetadata> adapterMethods,
|
||||
String adapterClassName) {
|
||||
String adapterClassName,
|
||||
boolean cycle) {
|
||||
write(processingEnv, createAdapterTypeSpec(adapterClassName, adapterMethods, cycle));
|
||||
}
|
||||
|
||||
private void write(ProcessingEnvironment processingEnv, TypeSpec typeSpec) {
|
||||
if (typeSpec == null) {
|
||||
return;
|
||||
}
|
||||
// write Adapter
|
||||
try (final Writer writer = processingEnv.getFiler()
|
||||
.createSourceFile(adapterPackage() + "." + adapterClassName)
|
||||
.createSourceFile(adapterPackage() + "." + typeSpec.name)
|
||||
.openWriter()) {
|
||||
JavaFile.builder(adapterPackage(), createTypeSpec(adapterMethods, adapterClassName))
|
||||
JavaFile.builder(adapterPackage(), typeSpec)
|
||||
.build()
|
||||
.writeTo(writer);
|
||||
} catch (IOException e) {
|
||||
processingEnv.getMessager()
|
||||
.printMessage(ERROR, "Error while opening " + adapterClassName + " output file: " + e.getMessage());
|
||||
.printMessage(ERROR, "Error while opening " + typeSpec.name + " output file: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract TypeSpec createTypeSpec(Collection<AbstractAdapterMethodMetadata> adapterMethods,
|
||||
String adapterClassName);
|
||||
protected TypeSpec createAdapterTypeSpec(String adapterClassName,
|
||||
Collection<AbstractAdapterMethodMetadata> adapterMethods,
|
||||
boolean cycle) {
|
||||
List<MethodSpec> methods = adapterMethods.stream()
|
||||
.filter(method -> !cycle || method.needCycleAvoiding())
|
||||
.map(method -> buildProxyMethod(method, cycle))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
if (methods.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return createTypeSpec(methods, adapterClassName,
|
||||
cycle ? ClassName.get(adapterPackage(), AutoMapperProperties.getAdapterClassName()) : null);
|
||||
}
|
||||
|
||||
protected TypeSpec createTypeSpec(List<MethodSpec> methods, String adapterClassName, ClassName superClass) {
|
||||
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(ClassName.get(adapterPackage(), adapterClassName))
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
if (superClass != null) {
|
||||
adapterBuilder.superclass(superClass);
|
||||
}
|
||||
|
||||
// adapter methods
|
||||
adapterBuilder.addMethods(methods);
|
||||
|
||||
return adapterBuilder.build();
|
||||
}
|
||||
|
||||
protected String adapterPackage() {
|
||||
return AutoMapperProperties.getAdapterPackage();
|
||||
@ -57,50 +97,138 @@ public abstract class AbstractAdapterMapperGenerator {
|
||||
return source;
|
||||
}
|
||||
|
||||
protected List<MethodSpec> buildProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
private List<MethodSpec> buildProxyMethod(AbstractAdapterMethodMetadata adapterMethod, boolean cycle) {
|
||||
List<MethodSpec> methodSpecs = new ArrayList<>();
|
||||
if (cycle) {
|
||||
methodSpecs.addAll(buildCycleAvoidingProxyMethod(adapterMethod));
|
||||
} else {
|
||||
methodSpecs.addAll(buildDefaultProxyMethod(adapterMethod, null));
|
||||
}
|
||||
return methodSpecs;
|
||||
}
|
||||
|
||||
protected List<MethodSpec> buildDefaultProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata,
|
||||
ClassName annotation) {
|
||||
List<MethodSpec> methodSpecs = new ArrayList<>();
|
||||
|
||||
if (adapterMethodMetadata.needCycleAvoiding()) {
|
||||
methodSpecs.add(buildCycleAvoidingProxyMethod(adapterMethodMetadata));
|
||||
} else {
|
||||
methodSpecs.add(buildDefaultProxyMethod(adapterMethodMetadata));
|
||||
ParameterSpec parameterSpec =
|
||||
ParameterSpec.builder(wrapperTypeName(adapterMethodMetadata.getSource()), PARAM__PARAMETER_NAME).build();
|
||||
MethodSpec methodSpecForSingle =
|
||||
buildDefaultProxyMethod(adapterMethodMetadata, parameterSpec, adapterMethodMetadata.getReturn(),
|
||||
annotation);
|
||||
methodSpecs.add(methodSpecForSingle);
|
||||
|
||||
// 自定义类型转换
|
||||
if (adapterMethodMetadata instanceof AdapterMethodMetadata) {
|
||||
ParameterSpec listParameter = ParameterSpec.builder(
|
||||
ParameterizedTypeName.get(ClassName.get("java.util", "List"), adapterMethodMetadata.getSource()),
|
||||
PARAM__PARAMETER_NAME
|
||||
).build();
|
||||
MethodSpec methodSpecForList =
|
||||
buildDefaultProxyMethod(adapterMethodMetadata, listParameter, ClassName.get("java.util", "List"),
|
||||
annotation);
|
||||
methodSpecs.add(methodSpecForList);
|
||||
}
|
||||
// 自定义类型与 Map 进行转换
|
||||
else if (adapterMethodMetadata instanceof AdapterMapMethodMetadata) {
|
||||
methodSpecs.add(buildObjConversionProxyMethod(adapterMethodMetadata, annotation));
|
||||
}
|
||||
|
||||
return methodSpecs;
|
||||
}
|
||||
|
||||
protected MethodSpec buildDefaultProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
private MethodSpec buildObjConversionProxyMethod(AbstractAdapterMethodMetadata adapterMethod,
|
||||
ClassName annotation) {
|
||||
CodeBlock code = CodeBlock.builder()
|
||||
.add("if($N == null) {\n", PARAM__PARAMETER_NAME)
|
||||
.add(" return null;\n")
|
||||
.add("}\n")
|
||||
.add("if($N instanceof $T) {\n", PARAM__PARAMETER_NAME, ClassName.get("java.util", "Map"))
|
||||
.add(" return $N((Map<$T, $T>) $N);\n",
|
||||
adapterMethod.getMethodName(), ClassName.get("java.lang", "String"),
|
||||
ClassName.get("java.lang", "Object"), PARAM__PARAMETER_NAME)
|
||||
.add("}\n")
|
||||
.add("return null;\n")
|
||||
.build();
|
||||
MethodSpec.Builder methodSpecBuilder =
|
||||
MethodSpec.methodBuilder("objTo" + ClassUtil.simplifyQualifiedName(adapterMethod.getReturn().toString()))
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(
|
||||
ParameterSpec.builder(ClassName.get("java.lang", "Object"), PARAM__PARAMETER_NAME)
|
||||
.build()
|
||||
)
|
||||
.returns(adapterMethod.getReturn())
|
||||
.addCode(code);
|
||||
if (annotation != null) {
|
||||
methodSpecBuilder.addAnnotation(annotation);
|
||||
}
|
||||
return methodSpecBuilder.build();
|
||||
}
|
||||
|
||||
private MethodSpec buildDefaultProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata,
|
||||
ParameterSpec parameterSpec,
|
||||
TypeName returns,
|
||||
ClassName annotation) {
|
||||
CodeBlock targetCode = adapterMethodMetadata.isStatic()
|
||||
? CodeBlock.of("return $T.$N($N);", adapterMethodMetadata.getMapper(),
|
||||
adapterMethodMetadata.getMapperMethodName(), "param")
|
||||
: proxyMethodTarget(adapterMethodMetadata);
|
||||
ParameterSpec parameterSpec =
|
||||
ParameterSpec.builder(wrapperTypeName(adapterMethodMetadata.getSource()), "param").build();
|
||||
return MethodSpec.methodBuilder(adapterMethodMetadata.getMethodName())
|
||||
MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(adapterMethodMetadata.getMethodName())
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(parameterSpec)
|
||||
.returns(adapterMethodMetadata.getReturn())
|
||||
.addCode(targetCode)
|
||||
.build();
|
||||
.returns(returns)
|
||||
.addCode(targetCode);
|
||||
if (annotation != null) {
|
||||
methodSpecBuilder.addAnnotation(annotation);
|
||||
}
|
||||
return methodSpecBuilder.build();
|
||||
}
|
||||
|
||||
protected MethodSpec buildCycleAvoidingProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
protected List<MethodSpec> buildCycleAvoidingProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
|
||||
// default impl
|
||||
List<MethodSpec> defaultMethods = buildDefaultProxyMethod(adapterMethodMetadata,
|
||||
ClassName.get("io.github.linpeilie.annotations", "DoIgnore"));
|
||||
List<MethodSpec> methodSpecs = new ArrayList<>(defaultMethods);
|
||||
|
||||
ParameterSpec parameterSpec =
|
||||
ParameterSpec.builder(wrapperTypeName(adapterMethodMetadata.getSource()), PARAM__PARAMETER_NAME).build();
|
||||
methodSpecs.add(
|
||||
buildCycleAvoidingProxyMethod(adapterMethodMetadata, parameterSpec, adapterMethodMetadata.getReturn()));
|
||||
|
||||
if (adapterMethodMetadata instanceof AdapterMethodMetadata) {
|
||||
ParameterSpec listParameter = ParameterSpec.builder(
|
||||
ParameterizedTypeName.get(ClassName.get("java.util", "List"), adapterMethodMetadata.getSource()),
|
||||
"param"
|
||||
).build();
|
||||
MethodSpec methodSpecForList =
|
||||
buildCycleAvoidingProxyMethod(adapterMethodMetadata, listParameter,
|
||||
ClassName.get("java.util", "List"));
|
||||
methodSpecs.add(methodSpecForList);
|
||||
}
|
||||
|
||||
return methodSpecs;
|
||||
}
|
||||
|
||||
private MethodSpec buildCycleAvoidingProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata,
|
||||
ParameterSpec parameterSpec,
|
||||
TypeName returns
|
||||
) {
|
||||
CodeBlock targetCode = adapterMethodMetadata.isStatic()
|
||||
? CodeBlock.of("return $T.$N($N, $N);", adapterMethodMetadata.getMapper(),
|
||||
adapterMethodMetadata.getMapperMethodName(), "param", "context")
|
||||
adapterMethodMetadata.getMapperMethodName(), "param", CONTEXT__PARAMETER_NAME)
|
||||
: cycleAvoidingMethodTarget(adapterMethodMetadata);
|
||||
ParameterSpec parameterSpec =
|
||||
ParameterSpec.builder(wrapperTypeName(adapterMethodMetadata.getSource()), "param").build();
|
||||
ParameterSpec contextParameterSpec =
|
||||
ParameterSpec.builder(
|
||||
ClassName.get("io.github.linpeilie", "CycleAvoidingMappingContext"),
|
||||
"context")
|
||||
ClassName.get("io.github.linpeilie", "CycleAvoidingMappingContext"),
|
||||
CONTEXT__PARAMETER_NAME)
|
||||
.addAnnotation(ClassName.get("org.mapstruct", "Context"))
|
||||
.build();
|
||||
return MethodSpec.methodBuilder(adapterMethodMetadata.getMethodName())
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addParameter(parameterSpec)
|
||||
.addParameter(contextParameterSpec)
|
||||
.returns(adapterMethodMetadata.getReturn())
|
||||
.returns(returns)
|
||||
.addCode(targetCode)
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -46,7 +47,6 @@ import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
@ -63,13 +63,6 @@ import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic;
|
||||
import org.mapstruct.MappingConstants;
|
||||
|
||||
import static io.github.linpeilie.processor.Constants.AUTO_ENUM_MAPPER_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.AUTO_MAPPERS_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.AUTO_MAPPER_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.AUTO_MAP_MAPPER_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.COMPONENT_MODEL_CONFIG_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.MAPPER_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.Constants.MAPPER_CONFIG_ANNOTATION;
|
||||
import static io.github.linpeilie.processor.ProcessorOptions.ADAPTER_CLASS_NAME;
|
||||
import static io.github.linpeilie.processor.ProcessorOptions.ADAPTER_PACKAGE;
|
||||
import static io.github.linpeilie.processor.ProcessorOptions.BUILDER_BUILD_METHOD;
|
||||
@ -83,22 +76,17 @@ import static io.github.linpeilie.processor.ProcessorOptions.UNMAPPED_SOURCE_POL
|
||||
import static io.github.linpeilie.processor.ProcessorOptions.UNMAPPED_TARGET_POLICY;
|
||||
import static javax.tools.Diagnostic.Kind.ERROR;
|
||||
|
||||
@SupportedAnnotationTypes({AUTO_MAPPER_ANNOTATION, AUTO_MAPPERS_ANNOTATION, AUTO_MAP_MAPPER_ANNOTATION,
|
||||
AUTO_ENUM_MAPPER_ANNOTATION, MAPPER_CONFIG_ANNOTATION, COMPONENT_MODEL_CONFIG_ANNOTATION,
|
||||
MAPPER_ANNOTATION})
|
||||
@SupportedOptions({
|
||||
MAPPER_CONFIG_CLASS,
|
||||
MAPPER_PACKAGE,
|
||||
UNMAPPED_SOURCE_POLICY,
|
||||
UNMAPPED_TARGET_POLICY,
|
||||
NULL_VALUE_MAPPING_STRATEGY,
|
||||
NULL_VALUE_PROPERTY_MAPPING_STRATEGY,
|
||||
BUILDER_BUILD_METHOD,
|
||||
BUILDER_DISABLE_BUILDER,
|
||||
ADAPTER_PACKAGE,
|
||||
ADAPTER_CLASS_NAME,
|
||||
MAP_ADAPTER_CLASS_NAME,
|
||||
})
|
||||
@SupportedAnnotationTypes({
|
||||
ContextConstants.Annotations.autoMapper,
|
||||
ContextConstants.Annotations.autoMappers,
|
||||
ContextConstants.Annotations.autoMapMapper,
|
||||
ContextConstants.Annotations.autoEnumMapper,
|
||||
ContextConstants.Annotations.mapperConfig,
|
||||
ContextConstants.Annotations.componentModel,
|
||||
ContextConstants.Annotations.mapper})
|
||||
@SupportedOptions({MAPPER_CONFIG_CLASS, MAPPER_PACKAGE, UNMAPPED_SOURCE_POLICY, UNMAPPED_TARGET_POLICY,
|
||||
NULL_VALUE_MAPPING_STRATEGY, NULL_VALUE_PROPERTY_MAPPING_STRATEGY, BUILDER_BUILD_METHOD,
|
||||
BUILDER_DISABLE_BUILDER, ADAPTER_PACKAGE, ADAPTER_CLASS_NAME, MAP_ADAPTER_CLASS_NAME,})
|
||||
public class AutoMapperProcessor extends AbstractProcessor {
|
||||
|
||||
private static final ClassName MAPPING_DEFAULT_TARGET = ClassName.get("io.github.linpeilie", "DefaultMapping");
|
||||
@ -121,46 +109,39 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
|
||||
private Messager messager;
|
||||
|
||||
private Filer filer;
|
||||
|
||||
public AutoMapperProcessor() {
|
||||
this.mapperGenerator = new AutoMapperGenerator();
|
||||
this.mapperConfigGenerator = new MapperConfigGenerator();
|
||||
}
|
||||
|
||||
private boolean isAutoMapperAnnotation(TypeElement annotation) {
|
||||
return AUTO_MAPPER_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
return ContextConstants.Annotations.autoMapper.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
private boolean isAutoMappersAnnotation(TypeElement annotation) {
|
||||
return AUTO_MAPPERS_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
return ContextConstants.Annotations.autoMappers.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
private boolean isAutoMapMapperAnnotation(TypeElement annotation) {
|
||||
return AUTO_MAP_MAPPER_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
return ContextConstants.Annotations.autoMapMapper.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
private boolean isAutoEnumMapperAnnotation(TypeElement annotation) {
|
||||
return AUTO_ENUM_MAPPER_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
return ContextConstants.Annotations.autoEnumMapper.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
private boolean isMapperConfigAnnotation(TypeElement annotation) {
|
||||
return MAPPER_CONFIG_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
private boolean isMapperAnnotation(TypeElement annotation) {
|
||||
return MAPPER_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
return ContextConstants.Annotations.mapperConfig.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
private boolean isComponentModelConfigAnnotation(TypeElement annotation) {
|
||||
return COMPONENT_MODEL_CONFIG_ANNOTATION.contentEquals(annotation.getQualifiedName());
|
||||
return ContextConstants.Annotations.componentModel.contentEquals(annotation.getQualifiedName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void init(final ProcessingEnvironment processingEnv) {
|
||||
super.init(processingEnv);
|
||||
messager = processingEnv.getMessager();
|
||||
filer = processingEnv.getFiler();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -200,25 +181,27 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
|
||||
// AutoMapMapper
|
||||
final TypeElement autoMapMapperAnnotation =
|
||||
processingEnv.getElementUtils().getTypeElement(AUTO_MAP_MAPPER_ANNOTATION);
|
||||
processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoMapMapper);
|
||||
processAutoMapMapperAnnotation(roundEnv, autoMapMapperAnnotation);
|
||||
|
||||
// AutoEnumMapper
|
||||
final TypeElement autoEnumMapperAnnotation =
|
||||
processingEnv.getElementUtils().getTypeElement(AUTO_ENUM_MAPPER_ANNOTATION);
|
||||
processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoEnumMapper);
|
||||
processAutoEnumMapperAnnotation(roundEnv, autoEnumMapperAnnotation);
|
||||
|
||||
// AutoMapper
|
||||
final TypeElement autoMapperAnnotation = processingEnv.getElementUtils().getTypeElement(AUTO_MAPPER_ANNOTATION);
|
||||
final TypeElement autoMapperAnnotation =
|
||||
processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoMapper);
|
||||
processAutoMapperAnnotation(roundEnv, autoMapperAnnotation);
|
||||
|
||||
// AutoMappers
|
||||
final TypeElement autoMappersAnnotation =
|
||||
processingEnv.getElementUtils().getTypeElement(AUTO_MAPPERS_ANNOTATION);
|
||||
processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoMappers);
|
||||
processAutoMappersAnnotation(roundEnv, autoMappersAnnotation);
|
||||
|
||||
// custom mapper
|
||||
final TypeElement mapperAnnotation = processingEnv.getElementUtils().getTypeElement(MAPPER_ANNOTATION);
|
||||
final TypeElement mapperAnnotation =
|
||||
processingEnv.getElementUtils().getTypeElement(ContextConstants.Mapper.qualifiedClassName);
|
||||
processMapperAnnotation(roundEnv, mapperAnnotation);
|
||||
|
||||
// 生成类
|
||||
@ -238,7 +221,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
final List<TypeElement> elements = getElementAndMergeHistory(roundEnv, annotation,
|
||||
new BuildCollator(processingEnv, Constants.MAPPERS_FILE_NAME));
|
||||
new BuildCollator(processingEnv, ContextConstants.MetaInf.mappers));
|
||||
|
||||
elements.forEach(element -> customMapperList.add(element.asType()));
|
||||
}
|
||||
@ -248,7 +231,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
return;
|
||||
}
|
||||
final List<TypeElement> elements = getElementAndMergeHistory(roundEnv, annotation,
|
||||
new BuildCollator(processingEnv, Constants.ENUM_MAPPERS_FILE_NAME));
|
||||
new BuildCollator(processingEnv, ContextConstants.MetaInf.enumMappers));
|
||||
elements.stream()
|
||||
.map(this::buildAutoEnumMapperMetadata)
|
||||
.filter(Objects::nonNull)
|
||||
@ -277,14 +260,12 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
final AdapterEnumMethodMetadata toValueProxyMethod =
|
||||
new AdapterEnumMethodMetadata(autoEnumMapperMetadata.getSourceClassName(),
|
||||
ClassName.get(autoEnumMapperMetadata.mapperPackage(), autoEnumMapperMetadata.mapperName()),
|
||||
autoEnumMapperMetadata.toValueMethodName(),
|
||||
autoEnumMapperMetadata.getReturnType());
|
||||
autoEnumMapperMetadata.toValueMethodName(), autoEnumMapperMetadata.getReturnType());
|
||||
// toEnum
|
||||
final AdapterEnumMethodMetadata toEnumProxyMethod =
|
||||
new AdapterEnumMethodMetadata(autoEnumMapperMetadata.getReturnType(),
|
||||
ClassName.get(autoEnumMapperMetadata.mapperPackage(), autoEnumMapperMetadata.mapperName()),
|
||||
autoEnumMapperMetadata.toEnumMethodName(),
|
||||
autoEnumMapperMetadata.getSourceClassName());
|
||||
autoEnumMapperMetadata.toEnumMethodName(), autoEnumMapperMetadata.getSourceClassName());
|
||||
methodMap.putIfAbsent(
|
||||
autoEnumMapperMetadata.getSourceClassName().simpleName() + toValueProxyMethod.getMapperMethodName(),
|
||||
toValueProxyMethod);
|
||||
@ -304,8 +285,8 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
if (!ElementKind.METHOD.equals(ele.getKind())) {
|
||||
continue;
|
||||
}
|
||||
boolean isGetter = StrUtil.equalsIgnoreCase(ele.getSimpleName(), "get" + enumCodeFieldName)
|
||||
|| StrUtil.equalsIgnoreCase(ele.getSimpleName(), "is" + enumCodeFieldName);
|
||||
boolean isGetter = StrUtil.equalsIgnoreCase(ele.getSimpleName(), "get" + enumCodeFieldName) ||
|
||||
StrUtil.equalsIgnoreCase(ele.getSimpleName(), "is" + enumCodeFieldName);
|
||||
if (isGetter) {
|
||||
enumCodeGetterElement = ele;
|
||||
break;
|
||||
@ -331,18 +312,20 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
final List<TypeElement> elements = getElementAndMergeHistory(roundEnv, annotation,
|
||||
new BuildCollator(processingEnv, Constants.AUTO_MAP_MAPPERS_FILE_NAME));
|
||||
new BuildCollator(processingEnv, ContextConstants.MetaInf.autoMapMappers));
|
||||
|
||||
elements.stream()
|
||||
.map(ele -> buildAutoMapMapperMetadata((TypeElement) ele))
|
||||
.map(this::buildAutoMapMapperMetadata)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(metadata -> {
|
||||
this.writeAutoMapperClassFile(metadata);
|
||||
addAdapterMapMethod(metadata);
|
||||
});
|
||||
|
||||
adapterMapperGenerator.write(processingEnv, mapMethodMap.values(),
|
||||
AutoMapperProperties.getMapAdapterClassName());
|
||||
adapterMapperGenerator.write(processingEnv,
|
||||
mapMethodMap.values(),
|
||||
AutoMapperProperties.getMapAdapterClassName(),
|
||||
false);
|
||||
|
||||
mapperConfigGenerator.write(processingEnv, AutoMapperProperties.getMapConfigClassName(),
|
||||
AutoMapperProperties.getMapAdapterClassName(), null);
|
||||
@ -352,18 +335,20 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
if (element.getAnnotation(AutoMapMapper.class) == null) {
|
||||
return null;
|
||||
}
|
||||
ClassName source = ClassName.get("java.util", "Map");
|
||||
ClassName source = ClassName.get(ContextConstants.Map.packageName, ContextConstants.Map.className);
|
||||
ClassName target = ClassName.get(element);
|
||||
List<ClassName> uses = Arrays.asList(ClassName.get("io.github.linpeilie.map", "MapObjectConvert"));
|
||||
List<ClassName> uses = Collections.singletonList(
|
||||
ClassName.get(ContextConstants.MapObjectConvert.packageName, ContextConstants.MapObjectConvert.className));
|
||||
|
||||
final AutoMapperMetadata autoMapperMetadata = new AutoMapMapperMetadata();
|
||||
autoMapperMetadata.setTargetClassName(target);
|
||||
autoMapperMetadata.setSourceClassName(source);
|
||||
autoMapperMetadata.setUsesClassNameList(uses);
|
||||
autoMapperMetadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseMapMapper"));
|
||||
autoMapperMetadata.setSuperClass(
|
||||
ClassName.get(ContextConstants.BaseMapMapper.packageName, ContextConstants.BaseMapMapper.className));
|
||||
autoMapperMetadata.setSuperGenerics(new ClassName[] {target});
|
||||
autoMapperMetadata.setMapstructConfigClass(ClassName.get(AutoMapperProperties.getConfigPackage(),
|
||||
AutoMapperProperties.getMapConfigClassName()));
|
||||
autoMapperMetadata.setMapstructConfigClass(
|
||||
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getMapConfigClassName()));
|
||||
return autoMapperMetadata;
|
||||
}
|
||||
|
||||
@ -373,8 +358,6 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
addAdapterMapMethod(metadata.getSourceClassName(), metadata.getTargetClassName(), metadata.mapperClass(),
|
||||
false);
|
||||
addAdapterMapMethod(ClassName.get("java.lang", "Object"), metadata.getTargetClassName(),
|
||||
metadata.mapperClass(), true);
|
||||
}
|
||||
|
||||
private void loadMapperConfig(MapperConfig mapperConfig) {
|
||||
@ -411,7 +394,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
private void refreshProperties(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
|
||||
final BuildCollator buildCollator = new BuildCollator(processingEnv, Constants.MAPPER_CONFIG_FILE_NAME);
|
||||
final BuildCollator buildCollator = new BuildCollator(processingEnv, ContextConstants.MetaInf.mapperConfig);
|
||||
|
||||
// load previous mapper config
|
||||
final List<TypeElement> typeElements = buildCollator.getRecords();
|
||||
@ -423,12 +406,10 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
|
||||
// annotation --> MapperConfig
|
||||
final TypeElement mapperConfigAnnotation =
|
||||
processingEnv.getElementUtils().getTypeElement(MAPPER_CONFIG_ANNOTATION);
|
||||
processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.mapperConfig);
|
||||
if (mapperConfigAnnotation != null) {
|
||||
final Optional<? extends Element> mapperConfigOptional =
|
||||
roundEnv.getElementsAnnotatedWith(mapperConfigAnnotation)
|
||||
.stream()
|
||||
.findFirst();
|
||||
roundEnv.getElementsAnnotatedWith(mapperConfigAnnotation).stream().findFirst();
|
||||
if (mapperConfigOptional.isPresent()) {
|
||||
loadMapperConfig(mapperConfigOptional.get().getAnnotation(MapperConfig.class));
|
||||
// record
|
||||
@ -473,13 +454,10 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
return;
|
||||
}
|
||||
final List<TypeElement> elements = getElementAndMergeHistory(roundEnv, annotation,
|
||||
new BuildCollator(processingEnv, Constants.AUTO_MAPPER_FILE_NAME));
|
||||
new BuildCollator(processingEnv, ContextConstants.MetaInf.autoMapper));
|
||||
|
||||
final List<AutoMapperMetadata> autoMapperMetadataList = elements
|
||||
.stream()
|
||||
.map(this::buildAutoMapperMetadata)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
final List<AutoMapperMetadata> autoMapperMetadataList =
|
||||
elements.stream().map(this::buildAutoMapperMetadata).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
|
||||
mapperList.addAll(autoMapperMetadataList);
|
||||
}
|
||||
@ -489,8 +467,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
return;
|
||||
}
|
||||
final List<AutoMapperMetadata> autoMapperMetadata = getElementAndMergeHistory(roundEnv, annotation,
|
||||
new BuildCollator(processingEnv, Constants.AUTO_MAPPERS_FILE_NAME))
|
||||
.stream()
|
||||
new BuildCollator(processingEnv, ContextConstants.MetaInf.autoMappers)).stream()
|
||||
.map(this::buildAutoMapperMetadataByAutoMappers)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
@ -526,25 +503,46 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
addAdapterMethod(metadata);
|
||||
});
|
||||
|
||||
adapterMapperGenerator.write(processingEnv, methodMap.values(), AutoMapperProperties.getAdapterClassName());
|
||||
adapterMapperGenerator.write(processingEnv,
|
||||
methodMap.values(),
|
||||
AutoMapperProperties.getAdapterClassName(),
|
||||
false);
|
||||
|
||||
mapperConfigGenerator.write(processingEnv, AutoMapperProperties.getConfigClassName(),
|
||||
AutoMapperProperties.getAdapterClassName(), customMapperList);
|
||||
mapperConfigGenerator.write(processingEnv,
|
||||
AutoMapperProperties.getConfigClassName(),
|
||||
AutoMapperProperties.getAdapterClassName(),
|
||||
customMapperList);
|
||||
|
||||
boolean needCycleAvoiding = methodMap.values().stream().anyMatch(
|
||||
AbstractAdapterMethodMetadata::needCycleAvoiding);
|
||||
|
||||
if (needCycleAvoiding) {
|
||||
adapterMapperGenerator.write(processingEnv,
|
||||
methodMap.values(),
|
||||
AutoMapperProperties.getCycleAvoidingAdapterClassName(),
|
||||
true);
|
||||
mapperConfigGenerator.write(processingEnv,
|
||||
AutoMapperProperties.getCycleAvoidingConfigClassName(),
|
||||
AutoMapperProperties.getCycleAvoidingAdapterClassName(),
|
||||
customMapperList);
|
||||
}
|
||||
}
|
||||
|
||||
private AutoMapperMetadata reverseMapper(AutoMapperMetadata autoMapperMetadata) {
|
||||
AutoMapperMetadata reverseMapperMetadata = initAutoMapperMetadata(
|
||||
autoMapperMetadata.getTargetClassName(), autoMapperMetadata.getSourceClassName());
|
||||
AutoMapperMetadata reverseMapperMetadata =
|
||||
initAutoMapperMetadata(autoMapperMetadata.getTargetClassName(),
|
||||
autoMapperMetadata.getSourceClassName(),
|
||||
autoMapperMetadata.isCycles());
|
||||
reverseMapperMetadata.setConvertGenerate(autoMapperMetadata.isReverseConvertGenerate());
|
||||
reverseMapperMetadata.setUsesClassNameList(autoMapperMetadata.getUsesClassNameList());
|
||||
reverseMapperMetadata.setImportsClassNameList(autoMapperMetadata.getImportsClassNameList());
|
||||
reverseMapperMetadata.setMapstructConfigClass(
|
||||
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getConfigClassName()));
|
||||
reverseMapperMetadata.setCycles(autoMapperMetadata.isCycles());
|
||||
if (reverseMapperMetadata.isCycles()) {
|
||||
reverseMapperMetadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseCycleAvoidingMapper"));
|
||||
reverseMapperMetadata.setSuperClass(ClassName.get(ContextConstants.BaseCycleAvoidingMapper.packageName,
|
||||
ContextConstants.BaseCycleAvoidingMapper.className));
|
||||
} else {
|
||||
reverseMapperMetadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseMapper"));
|
||||
reverseMapperMetadata.setSuperClass(
|
||||
ClassName.get(ContextConstants.BaseMapper.packageName, ContextConstants.BaseMapper.className));
|
||||
}
|
||||
if (CollectionUtil.isNotEmpty(autoMapperMetadata.getFieldReverseMappingList())) {
|
||||
reverseMapperMetadata.setFieldMappingList(autoMapperMetadata.getFieldReverseMappingList());
|
||||
@ -580,9 +578,9 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
if (metadata == null) {
|
||||
return;
|
||||
}
|
||||
AdapterMethodMetadata adapterMethodMetadata = AdapterMethodMetadata.newInstance(
|
||||
metadata.getSourceClassName(), metadata.getTargetClassName(), metadata.mapperClass(),
|
||||
metadata.isCycles());
|
||||
AdapterMethodMetadata adapterMethodMetadata =
|
||||
AdapterMethodMetadata.newInstance(metadata.getSourceClassName(), metadata.getTargetClassName(),
|
||||
metadata.mapperClass(), metadata.isCycles());
|
||||
methodMap.putIfAbsent(adapterMethodMetadata.getMethodName(), adapterMethodMetadata);
|
||||
}
|
||||
|
||||
@ -592,14 +590,21 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
mapMethodMap.putIfAbsent(adapterMapMethodMetadata.getMethodName(), adapterMapMethodMetadata);
|
||||
}
|
||||
|
||||
private AutoMapperMetadata initAutoMapperMetadata(ClassName source, ClassName target) {
|
||||
private AutoMapperMetadata initAutoMapperMetadata(ClassName source, ClassName target, boolean cycles) {
|
||||
AutoMapperMetadata metadata = new AutoMapperMetadata();
|
||||
|
||||
metadata.setSourceClassName(source);
|
||||
metadata.setTargetClassName(target);
|
||||
metadata.setSuperGenerics(new ClassName[] {source, target});
|
||||
metadata.setMapstructConfigClass(
|
||||
ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getConfigClassName()));
|
||||
ClassName mapStructConfigClass;
|
||||
if (cycles) {
|
||||
mapStructConfigClass = ClassName.get(AutoMapperProperties.getConfigPackage(),
|
||||
AutoMapperProperties.getCycleAvoidingConfigClassName());
|
||||
} else {
|
||||
mapStructConfigClass = ClassName.get(AutoMapperProperties.getConfigPackage(),
|
||||
AutoMapperProperties.getConfigClassName());
|
||||
}
|
||||
metadata.setMapstructConfigClass(mapStructConfigClass);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@ -609,16 +614,13 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
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());
|
||||
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());
|
||||
}
|
||||
|
||||
private AutoMapperMetadata buildAutoMapperMetadata(final Element ele) {
|
||||
@ -670,7 +672,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
List<AutoMappingMetadata> reverseMappingMetadataList = buildFieldReverseMappingMetadata((TypeElement) ele);
|
||||
reverseMappingMetadataList.removeIf(mappingMetadata -> !isTargetFieldMapping(target, mappingMetadata));
|
||||
|
||||
AutoMapperMetadata metadata = initAutoMapperMetadata(source, target);
|
||||
AutoMapperMetadata metadata = initAutoMapperMetadata(source, target, autoMapper.cycles());
|
||||
|
||||
metadata.setUsesClassNameList(uses);
|
||||
metadata.setImportsClassNameList(importsClassNameList);
|
||||
@ -680,9 +682,11 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
metadata.setReverseConvertGenerate(autoMapper.reverseConvertGenerate());
|
||||
metadata.setCycles(autoMapper.cycles());
|
||||
if (metadata.isCycles()) {
|
||||
metadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseCycleAvoidingMapper"));
|
||||
metadata.setSuperClass(ClassName.get(ContextConstants.BaseCycleAvoidingMapper.packageName,
|
||||
ContextConstants.BaseCycleAvoidingMapper.className));
|
||||
} else {
|
||||
metadata.setSuperClass(ClassName.get("io.github.linpeilie", "BaseMapper"));
|
||||
metadata.setSuperClass(
|
||||
ClassName.get(ContextConstants.BaseMapper.packageName, ContextConstants.BaseMapper.className));
|
||||
}
|
||||
|
||||
addMapper(metadata);
|
||||
@ -701,27 +705,24 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
ReverseAutoMapping reverseAutoMapping = field.getAnnotation(ReverseAutoMapping.class);
|
||||
if (reverseAutoMapping != null) {
|
||||
list.add(buildAutoMappingMetadata(reverseAutoMapping, field, ele));
|
||||
list.add(buildAutoMappingMetadata(reverseAutoMapping, field));
|
||||
}
|
||||
ReverseAutoMappings reverseAutoMappings = field.getAnnotation(ReverseAutoMappings.class);
|
||||
if (reverseAutoMappings != null) {
|
||||
for (ReverseAutoMapping mapping : reverseAutoMappings.value()) {
|
||||
list.add(buildAutoMappingMetadata(mapping, field, ele));
|
||||
list.add(buildAutoMappingMetadata(mapping, field));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// super class
|
||||
getSuperClass(ele)
|
||||
.ifPresent(superClass -> list.addAll(buildFieldReverseMappingMetadata(superClass)));
|
||||
getSuperClass(ele).ifPresent(superClass -> list.addAll(buildFieldReverseMappingMetadata(superClass)));
|
||||
|
||||
list.removeIf(Objects::isNull);
|
||||
return list;
|
||||
}
|
||||
|
||||
private AutoMappingMetadata buildAutoMappingMetadata(ReverseAutoMapping reverseAutoMapping,
|
||||
Element ele,
|
||||
TypeElement type) {
|
||||
private AutoMappingMetadata buildAutoMappingMetadata(ReverseAutoMapping reverseAutoMapping, Element ele) {
|
||||
ClassName targetClass = transToClassName(reverseAutoMapping::targetClass);
|
||||
if (targetClass == null) {
|
||||
return null;
|
||||
@ -751,10 +752,10 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
|
||||
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());
|
||||
throw new DuplicateMapperException("An exception occurred to generate " + metadata.mapperName() +
|
||||
", check the mapping configuration for " +
|
||||
metadata.getSourceClassName().reflectionName() + " or " +
|
||||
metadata.getTargetClassName().reflectionName());
|
||||
}
|
||||
}
|
||||
|
||||
@ -771,25 +772,24 @@ public class AutoMapperProcessor extends AbstractProcessor {
|
||||
}
|
||||
AutoMapping autoMapping = ele.getAnnotation(AutoMapping.class);
|
||||
if (autoMapping != null) {
|
||||
list.add(buildAutoMappingMetadata(autoMapping, ele, autoMapperEle));
|
||||
list.add(buildAutoMappingMetadata(autoMapping, ele));
|
||||
}
|
||||
final AutoMappings autoMappings = ele.getAnnotation(AutoMappings.class);
|
||||
if (autoMappings != null) {
|
||||
for (AutoMapping autoMappingEle : autoMappings.value()) {
|
||||
list.add(buildAutoMappingMetadata(autoMappingEle, ele, autoMapperEle));
|
||||
list.add(buildAutoMappingMetadata(autoMappingEle, ele));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add super class AutoMappings
|
||||
getSuperClass(autoMapperEle)
|
||||
.ifPresent(superClass -> list.addAll(buildFieldMappingMetadata(superClass)));
|
||||
getSuperClass(autoMapperEle).ifPresent(superClass -> list.addAll(buildFieldMappingMetadata(superClass)));
|
||||
|
||||
list.removeIf(Objects::isNull);
|
||||
return list;
|
||||
}
|
||||
|
||||
private AutoMappingMetadata buildAutoMappingMetadata(AutoMapping autoMapping, Element ele, TypeElement type) {
|
||||
private AutoMappingMetadata buildAutoMappingMetadata(AutoMapping autoMapping, Element ele) {
|
||||
ClassName targetClass = transToClassName(autoMapping::targetClass);
|
||||
if (targetClass == null) {
|
||||
return null;
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
package io.github.linpeilie.processor;
|
||||
|
||||
import org.mapstruct.Builder;
|
||||
import org.mapstruct.NullValueMappingStrategy;
|
||||
import org.mapstruct.NullValuePropertyMappingStrategy;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import static io.github.linpeilie.processor.Constants.*;
|
||||
|
||||
public class AutoMapperProperties {
|
||||
|
||||
private static String mapperPackage;
|
||||
|
||||
private static String componentModel = DEFAULT_COMPONENT_MODEL;
|
||||
private static String componentModel = ContextConstants.ComponentModelConfig.defaultComponentModel;
|
||||
|
||||
private static ReportingPolicy unmappedSourcePolicy = ReportingPolicy.IGNORE;
|
||||
|
||||
@ -25,17 +22,19 @@ public class AutoMapperProperties {
|
||||
|
||||
private static boolean disableBuilder = true;
|
||||
|
||||
private static String adapterPackage = DEFAULT_BASE_PACKAGE;
|
||||
private static String adapterPackage = ContextConstants.ConvertAdapter.packageName;
|
||||
|
||||
private static String adapterClassName = DEFAULT_ADAPTER_CLASS_NAME;
|
||||
private static String adapterClassName = ContextConstants.ConvertAdapter.convertMapperAdapterClassName;
|
||||
|
||||
private static String mapAdapterClassName = DEFAULT_MAP_ADAPTER_CLASS_NAME;
|
||||
private static String mapAdapterClassName = ContextConstants.ConvertAdapter.mapConvertMapperAdapterClassName;
|
||||
|
||||
private static String autoConfigPackage = DEFAULT_BASE_PACKAGE;
|
||||
private static String autoConfigPackage = ContextConstants.AutoConfig.packageName;
|
||||
|
||||
private static String autoMapperConfigClassName = AUTO_MAPPER_CONFIG_CLASS_NAME;
|
||||
private static String autoMapperConfigClassName = ContextConstants.AutoConfig.autoMapperConfigClassName;
|
||||
|
||||
private static String autoMapMapperConfigClassName = AUTO_MAP_MAPPER_CONFIG_CLASS_NAME;
|
||||
private static String autoMapMapperConfigClassName = ContextConstants.AutoConfig.autoMapMapperConfigClassName;
|
||||
|
||||
/* ******************** getter/setter ******************** */
|
||||
|
||||
public static String getMapperPackage() {
|
||||
return mapperPackage;
|
||||
@ -53,6 +52,10 @@ public class AutoMapperProperties {
|
||||
return adapterClassName;
|
||||
}
|
||||
|
||||
public static String getCycleAvoidingAdapterClassName() {
|
||||
return getAdapterClassName() + "ForCycleAvoiding";
|
||||
}
|
||||
|
||||
public static void setAdapterClassName(final String adapterClassName) {
|
||||
AutoMapperProperties.adapterClassName = adapterClassName;
|
||||
}
|
||||
@ -77,6 +80,10 @@ public class AutoMapperProperties {
|
||||
return autoMapperConfigClassName;
|
||||
}
|
||||
|
||||
public static String getCycleAvoidingConfigClassName() {
|
||||
return getConfigClassName() + "ForCycleAvoiding";
|
||||
}
|
||||
|
||||
public static void setAutoMapperConfigClassName(String autoMapperConfigClassName) {
|
||||
AutoMapperProperties.autoMapperConfigClassName = autoMapperConfigClassName;
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ public class BuildCollator {
|
||||
Filer filer = processingEnv.getFiler();
|
||||
try {
|
||||
FileObject fileObject = filer.getResource(StandardLocation.CLASS_OUTPUT, "",
|
||||
Constants.MAPSTRUCT_PLUS_META_INF + fileName);
|
||||
ContextConstants.MetaInf.folder + fileName);
|
||||
this.collatorFile = new File(fileObject.getName());
|
||||
if (collatorFile.exists()) {
|
||||
records = FileUtil.readUtf8Lines(collatorFile)
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
package io.github.linpeilie.processor;
|
||||
|
||||
import java.io.File;
|
||||
import org.mapstruct.MappingConstants;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String DEFAULT_BASE_PACKAGE = "io.github.linpeilie";
|
||||
|
||||
public static final String DEFAULT_COMPONENT_MODEL = MappingConstants.ComponentModel.SPRING;
|
||||
|
||||
public static final String DEFAULT_ADAPTER_CLASS_NAME = "ConvertMapperAdapter";
|
||||
|
||||
public static final String DEFAULT_MAP_ADAPTER_CLASS_NAME = "MapConvertMapperAdapter";
|
||||
|
||||
public static final String AUTO_MAPPER_CONFIG_CLASS_NAME = "AutoMapperConfig";
|
||||
|
||||
public static final String AUTO_MAP_MAPPER_CONFIG_CLASS_NAME = "AutoMapMapperConfig";
|
||||
|
||||
public static final String AUTO_MAPPER_ANNOTATION = "io.github.linpeilie.annotations.AutoMapper";
|
||||
|
||||
public static final String AUTO_MAPPERS_ANNOTATION = "io.github.linpeilie.annotations.AutoMappers";
|
||||
|
||||
public static final String AUTO_MAP_MAPPER_ANNOTATION = "io.github.linpeilie.annotations.AutoMapMapper";
|
||||
|
||||
public static final String AUTO_ENUM_MAPPER_ANNOTATION = "io.github.linpeilie.annotations.AutoEnumMapper";
|
||||
|
||||
public static final String MAPPER_CONFIG_ANNOTATION = "io.github.linpeilie.annotations.MapperConfig";
|
||||
|
||||
public static final String MAPPER_ANNOTATION = "org.mapstruct.Mapper";
|
||||
|
||||
public static final String COMPONENT_MODEL_CONFIG_ANNOTATION = "io.github.linpeilie.annotations.ComponentModelConfig";
|
||||
|
||||
public static final String MAPSTRUCT_MAPPER_PACKAGE = "org.mapstruct";
|
||||
|
||||
public static final String MAPSTRUCT_MAPPER_CLASS_NAME = "Mapper";
|
||||
|
||||
public static final String MAPSTRUCT_PLUS_META_INF = "META-INF/mps/";
|
||||
|
||||
public static final String MAPPER_CONFIG_FILE_NAME = "config";
|
||||
|
||||
public static final String MAPPERS_FILE_NAME = "mappers";
|
||||
|
||||
public static final String AUTO_MAPPER_FILE_NAME = "autoMapper";
|
||||
|
||||
public static final String AUTO_MAPPERS_FILE_NAME = "autoMappers";
|
||||
|
||||
public static final String AUTO_MAP_MAPPERS_FILE_NAME = "autoMapMappers";
|
||||
|
||||
public static final String ENUM_MAPPERS_FILE_NAME = "enumMappers";
|
||||
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
package io.github.linpeilie.processor;
|
||||
|
||||
import org.mapstruct.MappingConstants;
|
||||
|
||||
/**
|
||||
* 上下文常量
|
||||
*/
|
||||
public interface ContextConstants {
|
||||
|
||||
/**
|
||||
* BaseMapper 接口
|
||||
*/
|
||||
interface BaseMapper {
|
||||
String packageName = "io.github.linpeilie";
|
||||
String className = "BaseMapper";
|
||||
}
|
||||
|
||||
/**
|
||||
* BaseMapMapper 接口
|
||||
*/
|
||||
interface BaseMapMapper {
|
||||
String packageName = "io.github.linpeilie";
|
||||
String className = "BaseMapMapper";
|
||||
}
|
||||
|
||||
/**
|
||||
* BaseCycleAvoidingMapper 接口
|
||||
*/
|
||||
interface BaseCycleAvoidingMapper {
|
||||
String packageName = "io.github.linpeilie";
|
||||
String className = "BaseCycleAvoidingMapper";
|
||||
}
|
||||
|
||||
interface Mapper {
|
||||
String qualifiedClassName = "org.mapstruct.Mapper";
|
||||
String packageName = "org.mapstruct";
|
||||
String className = "Mapper";
|
||||
}
|
||||
|
||||
interface AutoMapper {
|
||||
String qualifiedClassName = "io.github.linpeilie.annotations.AutoMapper";
|
||||
}
|
||||
|
||||
interface AutoMappers {
|
||||
String qualifiedClassName = "io.github.linpeilie.annotations.AutoMappers";
|
||||
}
|
||||
|
||||
interface AutoMapMapper {
|
||||
String qualifiedClassName = "io.github.linpeilie.annotations.AutoMapMapper";
|
||||
}
|
||||
|
||||
interface AutoEnumMapper {
|
||||
String qualifiedClassName = "io.github.linpeilie.annotations.AutoEnumMapper";
|
||||
}
|
||||
|
||||
interface MapperConfig {
|
||||
String qualifiedClassName = "io.github.linpeilie.annotations.MapperConfig";
|
||||
}
|
||||
|
||||
interface ComponentModelConfig {
|
||||
String qualifiedClassName = "io.github.linpeilie.annotations.ComponentModelConfig";
|
||||
String defaultComponentModel = MappingConstants.ComponentModel.SPRING;
|
||||
}
|
||||
|
||||
interface ConvertAdapter {
|
||||
String packageName = "io.github.linpeilie";
|
||||
String convertMapperAdapterClassName = "ConverterMapperAdapter";
|
||||
String mapConvertMapperAdapterClassName = "MapConvertMapperAdapter";
|
||||
}
|
||||
|
||||
interface AutoConfig {
|
||||
String packageName = "io.github.linpeilie";
|
||||
String autoMapperConfigClassName = "AutoMapperConfig";
|
||||
String autoMapMapperConfigClassName = "AutoMapMapperConfig";
|
||||
}
|
||||
|
||||
interface Annotations {
|
||||
String mapper = Mapper.qualifiedClassName;
|
||||
String autoMapper = AutoMapper.qualifiedClassName;
|
||||
String autoMappers = AutoMappers.qualifiedClassName;
|
||||
String autoMapMapper = AutoMapMapper.qualifiedClassName;
|
||||
String autoEnumMapper = AutoEnumMapper.qualifiedClassName;
|
||||
String mapperConfig = MapperConfig.qualifiedClassName;
|
||||
String componentModel = ComponentModelConfig.qualifiedClassName;
|
||||
}
|
||||
|
||||
interface MetaInf {
|
||||
String folder = "META-INF/mps/";
|
||||
String mapperConfig = "config";
|
||||
String mappers = "mappers";
|
||||
String autoMapper = "autoMapper";
|
||||
String autoMappers = "autoMappers";
|
||||
String autoMapMappers = "autoMapMappers";
|
||||
String enumMappers = "enumMappers";
|
||||
}
|
||||
|
||||
interface Map {
|
||||
String packageName = "java.util";
|
||||
String className = "Map";
|
||||
}
|
||||
|
||||
interface MapObjectConvert {
|
||||
String packageName = "io.github.linpeilie.map";
|
||||
String className = "MapObjectConvert";
|
||||
}
|
||||
|
||||
}
|
||||
@ -10,13 +10,13 @@ import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
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 java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -27,21 +27,15 @@ import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import static io.github.linpeilie.processor.Constants.*;
|
||||
|
||||
public class AutoMapperGenerator {
|
||||
|
||||
public static final String CONVERT_METHOD_NAME = "convert";
|
||||
|
||||
public static final String CONVERT_WITH_CYCLE_METHOD_NAME = "convertWithCycle";
|
||||
|
||||
public void write(AutoMapperMetadata metadata, final ProcessingEnvironment processingEnv, Writer writer) {
|
||||
try {
|
||||
JavaFile.builder(metadata.mapperPackage(), createTypeSpec(processingEnv, metadata)).build().writeTo(writer);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +45,6 @@ public class AutoMapperGenerator {
|
||||
|
||||
final ClassName targetClassName = metadata.getTargetClassName();
|
||||
|
||||
|
||||
TypeSpec.Builder builder = TypeSpec.interfaceBuilder(metadata.mapperName())
|
||||
.addSuperinterface(converterName)
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
@ -61,33 +54,48 @@ public class AutoMapperGenerator {
|
||||
final ParameterSpec target = ParameterSpec.builder(targetClassName, "target")
|
||||
.addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build())
|
||||
.build();
|
||||
final 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(Collections.singletonList(source), metadata.getFieldMappingList(),
|
||||
targetClassName, metadata.isCycles()));
|
||||
builder.addMethod(addConvertMethodSpec(
|
||||
metadata.isCycles() ? CollectionUtil.newArrayList(source, context) : Collections.singletonList(source),
|
||||
metadata.getFieldMappingList(),
|
||||
targetClassName,
|
||||
CONVERT_METHOD_NAME));
|
||||
}
|
||||
|
||||
boolean targetIsImmutable = classIsImmutable(processingEnv, targetClassName);
|
||||
if (targetIsImmutable) {
|
||||
builder.addMethod(addEmptyConvertMethodForImmutableEntity(source, target, targetClassName, metadata.isCycles()));
|
||||
} else {
|
||||
builder.addMethod(addConvertMethodSpec(Arrays.asList(source, target), metadata.getFieldMappingList(),
|
||||
targetClassName, metadata.isCycles()));
|
||||
builder.addMethod(
|
||||
addEmptyConvertMethodForImmutableEntity(
|
||||
metadata.isCycles() ? CollectionUtil.newArrayList(source, target,
|
||||
context) : CollectionUtil.newArrayList(source, target),
|
||||
targetClassName,
|
||||
CONVERT_METHOD_NAME));
|
||||
} else if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) {
|
||||
builder.addMethod(addConvertMethodSpec(
|
||||
metadata.isCycles() ? CollectionUtil.newArrayList(source, target,
|
||||
context) : CollectionUtil.newArrayList(source, target),
|
||||
metadata.getFieldMappingList(),
|
||||
targetClassName,
|
||||
CONVERT_METHOD_NAME));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private MethodSpec addEmptyConvertMethodForImmutableEntity(ParameterSpec source,
|
||||
ParameterSpec target,
|
||||
ClassName targetClassName, boolean cycles) {
|
||||
String methodName = cycles ? CONVERT_WITH_CYCLE_METHOD_NAME : CONVERT_METHOD_NAME;
|
||||
return MethodSpec.methodBuilder(methodName)
|
||||
private MethodSpec addEmptyConvertMethodForImmutableEntity(List<ParameterSpec> parameterSpecs,
|
||||
ClassName targetClassName,
|
||||
String methodName) {
|
||||
MethodSpec.Builder builder = MethodSpec.methodBuilder(methodName)
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
|
||||
.addParameter(source)
|
||||
.addParameter(target)
|
||||
.addParameters(parameterSpecs)
|
||||
.returns(targetClassName)
|
||||
.addCode("return target;")
|
||||
.build();
|
||||
.addCode("return target;");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private boolean classIsImmutable(ProcessingEnvironment processingEnv, ClassName className) {
|
||||
@ -103,9 +111,8 @@ public class AutoMapperGenerator {
|
||||
}
|
||||
|
||||
private MethodSpec addConvertMethodSpec(List<ParameterSpec> parameterSpecs,
|
||||
List<AutoMappingMetadata> autoMappingMetadataList,
|
||||
ClassName target, boolean cycles) {
|
||||
String methodName = cycles ? CONVERT_WITH_CYCLE_METHOD_NAME : CONVERT_METHOD_NAME;
|
||||
List<AutoMappingMetadata> autoMappingMetadataList,
|
||||
ClassName target, String methodName) {
|
||||
final MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(methodName)
|
||||
.addParameters(parameterSpecs)
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
|
||||
@ -140,10 +147,12 @@ public class AutoMapperGenerator {
|
||||
builder.addMember("source", CodeBlock.builder().add("$S", autoMappingMetadata.getSource()).build());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(autoMappingMetadata.getDefaultExpression())) {
|
||||
builder.addMember("defaultExpression",CodeBlock.builder().add("$S", autoMappingMetadata.getDefaultExpression()).build());
|
||||
builder.addMember("defaultExpression",
|
||||
CodeBlock.builder().add("$S", autoMappingMetadata.getDefaultExpression()).build());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(autoMappingMetadata.getConditionExpression())) {
|
||||
builder.addMember("conditionExpression", CodeBlock.builder().add("$S", autoMappingMetadata.getConditionExpression()).build());
|
||||
builder.addMember("conditionExpression",
|
||||
CodeBlock.builder().add("$S", autoMappingMetadata.getConditionExpression()).build());
|
||||
}
|
||||
return builder.build();
|
||||
}).collect(Collectors.toList());
|
||||
@ -182,7 +191,8 @@ public class AutoMapperGenerator {
|
||||
final CodeBlock importsCodeBlock = importsCodeBuilder.add("}").build();
|
||||
|
||||
AnnotationSpec.Builder builder =
|
||||
AnnotationSpec.builder(ClassName.get(MAPSTRUCT_MAPPER_PACKAGE, MAPSTRUCT_MAPPER_CLASS_NAME))
|
||||
AnnotationSpec.builder(
|
||||
ClassName.get(ContextConstants.Mapper.packageName, ContextConstants.Mapper.className))
|
||||
.addMember("config", configCodeBlock)
|
||||
.addMember("uses", usesCodeBlock)
|
||||
.addMember("imports", importsCodeBlock);
|
||||
|
||||
@ -12,31 +12,17 @@ import javax.lang.model.element.Modifier;
|
||||
|
||||
public class DefaultAdapterMapperGenerator extends AbstractAdapterMapperGenerator {
|
||||
|
||||
public TypeSpec createTypeSpec(Collection<AbstractAdapterMethodMetadata> adapterMethods, String adapterClassName) {
|
||||
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(
|
||||
ClassName.get(adapterPackage(), adapterClassName))
|
||||
.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
adapterMethods.forEach(adapterMethod -> adapterBuilder.addMethods(buildProxyMethod(adapterMethod)));
|
||||
|
||||
return adapterBuilder.build();
|
||||
}
|
||||
|
||||
private String firstWordToLower(String str) {
|
||||
return str.substring(0, 1).toLowerCase() + str.substring(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CodeBlock proxyMethodTarget(final AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
return CodeBlock.of("return ($T.getMapper($T.class)).$N($N);",
|
||||
ClassName.get("org.mapstruct.factory", "Mappers"), adapterMethodMetadata.getMapper(),
|
||||
adapterMethodMetadata.getMapperMethodName(), "param");
|
||||
adapterMethodMetadata.getMapperMethodName(), PARAM__PARAMETER_NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CodeBlock cycleAvoidingMethodTarget(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
return CodeBlock.of("return ($T.getMapper($T.class)).$N($N, $N);",
|
||||
ClassName.get("org.mapstruct.factory", "Mappers"), adapterMethodMetadata.getMapper(),
|
||||
adapterMethodMetadata.cycleAvoidingMethodName(), "param", "context");
|
||||
adapterMethodMetadata.cycleAvoidingMethodName(), PARAM__PARAMETER_NAME, CONTEXT__PARAMETER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,40 +4,44 @@ import com.squareup.javapoet.AnnotationSpec;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.FieldSpec;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import io.github.linpeilie.processor.AbstractAdapterMapperGenerator;
|
||||
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.lang.model.element.Modifier;
|
||||
|
||||
public abstract class IocAdapterMapperGenerator extends AbstractAdapterMapperGenerator {
|
||||
|
||||
protected static final String CONVERTER_FIELD_NAME = "converter";
|
||||
|
||||
protected abstract AnnotationSpec componentAnnotation();
|
||||
|
||||
protected abstract List<AnnotationSpec> injectAnnotations();
|
||||
|
||||
@Override
|
||||
protected TypeSpec createTypeSpec(final Collection<AbstractAdapterMethodMetadata> adapterMethods,
|
||||
final String adapterClassName) {
|
||||
protected TypeSpec createTypeSpec(List<MethodSpec> methods, String adapterClassName, ClassName superClass) {
|
||||
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(ClassName.get(adapterPackage(), adapterClassName))
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addAnnotation(componentAnnotation());
|
||||
|
||||
adapterMethods.stream()
|
||||
.filter(adapterMethodMetadata -> !adapterMethodMetadata.isStatic())
|
||||
.map(AbstractAdapterMethodMetadata::getMapper)
|
||||
.distinct()
|
||||
.forEach(mapper -> adapterBuilder.addField(buildMapperField(mapper)));
|
||||
adapterBuilder.addField(buildConverterField());
|
||||
|
||||
adapterMethods.forEach(adapterMethod -> adapterBuilder
|
||||
.addMethods(buildProxyMethod(adapterMethod)));
|
||||
adapterBuilder.addMethods(methods);
|
||||
|
||||
if (superClass != null) {
|
||||
adapterBuilder.superclass(superClass);
|
||||
}
|
||||
|
||||
return adapterBuilder.build();
|
||||
}
|
||||
|
||||
private FieldSpec buildMapperField(ClassName mapper) {
|
||||
return FieldSpec.builder(mapper, firstWordToLower(mapper.simpleName()), Modifier.PRIVATE)
|
||||
private FieldSpec buildConverterField() {
|
||||
return FieldSpec.builder(
|
||||
ClassName.get("io.github.linpeilie", "Converter"),
|
||||
CONVERTER_FIELD_NAME,
|
||||
Modifier.PRIVATE
|
||||
)
|
||||
.addAnnotations(injectAnnotations())
|
||||
.build();
|
||||
}
|
||||
@ -46,21 +50,33 @@ public abstract class IocAdapterMapperGenerator extends AbstractAdapterMapperGen
|
||||
return str.substring(0, 1).toLowerCase() + str.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* return converter.convert(param, Target.class);
|
||||
* </code>
|
||||
*/
|
||||
@Override
|
||||
protected CodeBlock proxyMethodTarget(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
return CodeBlock.builder()
|
||||
.add("return $N.$N($N);", firstWordToLower(adapterMethodMetadata.getMapper().simpleName()),
|
||||
adapterMethodMetadata.getMapperMethodName(),
|
||||
"param")
|
||||
.add("return $N.convert($N, $T.class);\n", CONVERTER_FIELD_NAME,
|
||||
PARAM__PARAMETER_NAME,
|
||||
adapterMethodMetadata.getReturn())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>
|
||||
* return converter.convert(param, Target.class, context);
|
||||
* </code>
|
||||
*/
|
||||
@Override
|
||||
protected CodeBlock cycleAvoidingMethodTarget(AbstractAdapterMethodMetadata adapterMethodMetadata) {
|
||||
return CodeBlock.builder()
|
||||
.add("return $N.$N($N, $N);", firstWordToLower(adapterMethodMetadata.getMapper().simpleName()),
|
||||
adapterMethodMetadata.cycleAvoidingMethodName(),
|
||||
"param", "context")
|
||||
.add("return $N.convert($N, $T.class, $N);\n",
|
||||
CONVERTER_FIELD_NAME,
|
||||
PARAM__PARAMETER_NAME,
|
||||
adapterMethodMetadata.getReturn(),
|
||||
CONTEXT__PARAMETER_NAME)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,12 +28,6 @@ public class SpringAdapterMapperGenerator extends IocAdapterMapperGenerator {
|
||||
.build();
|
||||
}
|
||||
|
||||
private AnnotationSpec lazy() {
|
||||
return AnnotationSpec
|
||||
.builder(ClassName.get("org.springframework.context.annotation", "Lazy"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AnnotationSpec componentAnnotation() {
|
||||
return component();
|
||||
@ -41,7 +35,7 @@ public class SpringAdapterMapperGenerator extends IocAdapterMapperGenerator {
|
||||
|
||||
@Override
|
||||
protected List<AnnotationSpec> injectAnnotations() {
|
||||
return CollectionUtil.newArrayList(autowired(), lazy());
|
||||
return CollectionUtil.newArrayList(autowired());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package io.github.linpeilie.processor.metadata;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import io.github.linpeilie.processor.utils.ClassUtil;
|
||||
|
||||
public class AdapterMethodMetadata extends AbstractAdapterMethodMetadata {
|
||||
|
||||
@ -19,9 +20,9 @@ public class AdapterMethodMetadata extends AbstractAdapterMethodMetadata {
|
||||
|
||||
@Override
|
||||
public String getMethodName() {
|
||||
final String sourceName = source.toString().replace(".", "_");
|
||||
return sourceName.substring(0, 1).toLowerCase() + sourceName.substring(1) + "To" +
|
||||
target.simpleName();
|
||||
String source = ClassUtil.simplifyQualifiedName(this.source.toString());
|
||||
source = source.substring(0, 1).toLowerCase() + source.substring(1);
|
||||
return source + "To" + target.simpleName();
|
||||
}
|
||||
|
||||
public ClassName getTarget() {
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package io.github.linpeilie.processor.utils;
|
||||
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* 简化类全限定名
|
||||
* @param qualifiedName
|
||||
* @return
|
||||
*/
|
||||
public static String simplifyQualifiedName(String qualifiedName) {
|
||||
String[] arr = qualifiedName.split("\\.");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
if (i == arr.length - 1) {
|
||||
sb.append("_");
|
||||
sb.append(arr[i]);
|
||||
} else {
|
||||
sb.append(arr[i].charAt(0));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package io.github.linpeilie.mapstruct;
|
||||
|
||||
import io.github.linpeilie.AbstractCachedConverterFactory;
|
||||
import io.github.linpeilie.BaseCycleAvoidingMapper;
|
||||
import io.github.linpeilie.BaseMapMapper;
|
||||
import io.github.linpeilie.BaseMapper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
@ -6,18 +6,20 @@ public abstract class AbstractCachedConverterFactory implements ConverterFactory
|
||||
|
||||
private final ConcurrentHashMap<String, BaseMapper> mapperMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<String, BaseCycleAvoidingMapper> cycleAvoidingMapper = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<String, BaseMapMapper> mapMapperMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S, T> BaseMapper<S, T> getMapper(final Class<S> sourceType, final Class<T> targetType) {
|
||||
final Class<?> source = wrapperClass(sourceType);
|
||||
final Class<?> target = wrapperClass(targetType);
|
||||
final String key = key(source, target);
|
||||
Class<?> source = wrapperClass(sourceType);
|
||||
Class<?> target = wrapperClass(targetType);
|
||||
String key = key(source, target);
|
||||
if (mapperMap.containsKey(key)) {
|
||||
return mapperMap.get(key);
|
||||
}
|
||||
final BaseMapper mapper = findMapper(source, target);
|
||||
BaseMapper mapper = findMapper(source, target);
|
||||
if (mapper != null) {
|
||||
mapperMap.put(key, mapper);
|
||||
return mapper;
|
||||
@ -25,6 +27,18 @@ public abstract class AbstractCachedConverterFactory implements ConverterFactory
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, T> BaseCycleAvoidingMapper<S, T> getCycleAvoidingMapper(Class<S> sourceType, Class<T> targetType) {
|
||||
BaseMapper<S, T> mapper = getMapper(sourceType, targetType);
|
||||
if (mapper == null) {
|
||||
return null;
|
||||
}
|
||||
if (mapper instanceof BaseCycleAvoidingMapper) {
|
||||
return (BaseCycleAvoidingMapper<S, T>) mapper;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S> BaseMapMapper<S> getMapMapper(final Class<S> sourceType) {
|
||||
final Class<?> source = wrapperClass(sourceType);
|
||||
@ -44,7 +58,7 @@ public abstract class AbstractCachedConverterFactory implements ConverterFactory
|
||||
return clazz;
|
||||
}
|
||||
|
||||
protected abstract <S, T> BaseMapper findMapper(final Class<S> source, final Class<T> target);
|
||||
protected abstract <S, T> BaseMapper findMapper(Class<S> source, Class<T> target);
|
||||
|
||||
protected abstract <S> BaseMapMapper findMapMapper(final Class<?> source);
|
||||
|
||||
|
||||
@ -3,34 +3,42 @@ package io.github.linpeilie;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import io.github.linpeilie.annotations.DoIgnore;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.mapstruct.Context;
|
||||
import org.mapstruct.MappingTarget;
|
||||
|
||||
public interface BaseCycleAvoidingMapper<S, T> extends BaseMapper<S, T> {
|
||||
|
||||
@DoIgnore
|
||||
T convertWithCycle(S source, @Context CycleAvoidingMappingContext context);
|
||||
T convert(S source, @Context CycleAvoidingMappingContext context);
|
||||
|
||||
@DoIgnore
|
||||
T convertWithCycle(S source, @MappingTarget T target, @Context CycleAvoidingMappingContext context);
|
||||
T convert(S source, @MappingTarget T target, @Context CycleAvoidingMappingContext context);
|
||||
|
||||
List<T> convertWithCycle(List<S> sourceList, @Context CycleAvoidingMappingContext context);
|
||||
|
||||
@Override
|
||||
@DoIgnore
|
||||
default List<T> convert(List<S> sourceList) {
|
||||
return convertWithCycle(sourceList, new CycleAvoidingMappingContext());
|
||||
default List<T> convert(List<S> sourceList, @Context CycleAvoidingMappingContext context) {
|
||||
return sourceList.stream()
|
||||
.map(item -> convert(item, context))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@DoIgnore
|
||||
default T convert(S source) {
|
||||
return convertWithCycle(source, new CycleAvoidingMappingContext());
|
||||
return convert(source, new CycleAvoidingMappingContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@DoIgnore
|
||||
default T convert(S source, T target) {
|
||||
return convertWithCycle(source, new CycleAvoidingMappingContext());
|
||||
default T convert(S source, @MappingTarget T target) {
|
||||
return convert(source, new CycleAvoidingMappingContext());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@DoIgnore
|
||||
default List<T> convert(List<S> sourceList) {
|
||||
return convert(sourceList, new CycleAvoidingMappingContext());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,14 +6,4 @@ public interface BaseMapMapper<T> {
|
||||
|
||||
T convert(Map<String, Object> map);
|
||||
|
||||
default T convertByObj(Object obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
if (obj instanceof Map) {
|
||||
return convert((Map<String, Object>) obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ public interface BaseMapper<S, T> {
|
||||
@DoIgnore
|
||||
T convert(S source, @MappingTarget T target);
|
||||
|
||||
@DoIgnore
|
||||
default List<T> convert(List<S> sourceList) {
|
||||
if (CollectionUtil.isEmpty(sourceList)) {
|
||||
return new ArrayList<>();
|
||||
|
||||
@ -48,12 +48,36 @@ public class Converter {
|
||||
}
|
||||
|
||||
public <S, T> List<T> convert(List<S> source, Class<T> targetType) {
|
||||
if (source == null || source.size() == 0) {
|
||||
if (source == null || source.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return source.stream().map(item -> convert(item, targetType)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <S, T> T convert(S source, Class<T> target, CycleAvoidingMappingContext context) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
BaseCycleAvoidingMapper<S, T> mapper =
|
||||
(BaseCycleAvoidingMapper<S, T>) converterFactory.getCycleAvoidingMapper(source.getClass(), target);
|
||||
if (mapper != null) {
|
||||
return mapper.convert(source, context);
|
||||
}
|
||||
throw new ConvertException("cannot find converter from " + source.getClass().getSimpleName() + " to " +
|
||||
target.getSimpleName());
|
||||
}
|
||||
|
||||
public <S, T> List<T> convert(List<S> source, Class<T> targetType, CycleAvoidingMappingContext context) {
|
||||
if (source == null || source.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return source.stream().map(item -> convert(item, targetType, context)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public <T> T convert(Map<String, Object> map, Class<T> target) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return null;
|
||||
|
||||
@ -4,6 +4,8 @@ public interface ConverterFactory {
|
||||
|
||||
<S, T> BaseMapper<S, T> getMapper(Class<S> sourceType, Class<T> targetType);
|
||||
|
||||
<S, T> BaseCycleAvoidingMapper<S, T> getCycleAvoidingMapper(Class<S> sourceType, Class<T> targetType);
|
||||
|
||||
<S> BaseMapMapper<S> getMapMapper(Class<S> sourceType);
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user