All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.linpeilie.processor.AutoMapperProcessor Maven / Gradle / Ivy

The newest version!
package io.github.linpeilie.processor;

import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import io.github.linpeilie.ComponentModelConstant;
import io.github.linpeilie.annotations.AutoEnumMapper;
import io.github.linpeilie.annotations.AutoMapMapper;
import io.github.linpeilie.annotations.ComponentModelConfig;
import io.github.linpeilie.processor.gem.AutoMapperGem;
import io.github.linpeilie.processor.gem.AutoMappersGem;
import io.github.linpeilie.processor.gem.AutoMappingGem;
import io.github.linpeilie.processor.gem.AutoMappingsGem;
import io.github.linpeilie.processor.gem.BuilderGem;
import io.github.linpeilie.processor.gem.MapperConfigGem;
import io.github.linpeilie.processor.gem.ReverseAutoMappingGem;
import io.github.linpeilie.processor.gem.ReverseAutoMappingsGem;
import io.github.linpeilie.processor.generator.AutoEnumMapperGenerator;
import io.github.linpeilie.processor.generator.AutoMapperGenerator;
import io.github.linpeilie.processor.generator.DefaultAdapterMapperGenerator;
import io.github.linpeilie.processor.generator.MapperConfigGenerator;
import io.github.linpeilie.processor.generator.SolonAdapterMapperGenerator;
import io.github.linpeilie.processor.generator.SpringAdapterMapperGenerator;
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
import io.github.linpeilie.processor.metadata.AdapterEnumMethodMetadata;
import io.github.linpeilie.processor.metadata.AdapterMapMethodMetadata;
import io.github.linpeilie.processor.metadata.AdapterMethodMetadata;
import io.github.linpeilie.processor.metadata.AutoEnumMapperMetadata;
import io.github.linpeilie.processor.metadata.AutoMapMapperMetadata;
import io.github.linpeilie.processor.metadata.AutoMapperMetadata;
import io.github.linpeilie.processor.metadata.AutoMappingMetadata;
import io.github.linpeilie.processor.utils.ExceptionUtils;
import io.github.linpeilie.processor.utils.MapperUtils;
import io.github.linpeilie.processor.utils.ObjectUtils;
import io.github.linpeilie.utils.CollectionUtils;
import io.github.linpeilie.utils.StrUtil;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.MirroredTypesException;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import org.mapstruct.MappingConstants;

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;
import static io.github.linpeilie.processor.ProcessorOptions.BUILDER_DISABLE_BUILDER;
import static io.github.linpeilie.processor.ProcessorOptions.COLLECTION_MAPPING_STRATEGY;
import static io.github.linpeilie.processor.ProcessorOptions.MAPPER_CONFIG_CLASS;
import static io.github.linpeilie.processor.ProcessorOptions.MAPPER_PACKAGE;
import static io.github.linpeilie.processor.ProcessorOptions.MAP_ADAPTER_CLASS_NAME;
import static io.github.linpeilie.processor.ProcessorOptions.NULL_VALUE_CHECK_STRATEGY;
import static io.github.linpeilie.processor.ProcessorOptions.NULL_VALUE_ITERABLE_MAPPING_STRATEGY;
import static io.github.linpeilie.processor.ProcessorOptions.NULL_VALUE_MAPPING_STRATEGY;
import static io.github.linpeilie.processor.ProcessorOptions.NULL_VALUE_MAP_MAPPING_STRATEGY;
import static io.github.linpeilie.processor.ProcessorOptions.NULL_VALUE_PROPERTY_MAPPING_STRATEGY;
import static io.github.linpeilie.processor.ProcessorOptions.SUPPRESS_TIMESTAMP_IN_GENERATED;
import static io.github.linpeilie.processor.ProcessorOptions.TYPE_CONVERSION_POLICY;
import static io.github.linpeilie.processor.ProcessorOptions.UNMAPPED_SOURCE_POLICY;
import static io.github.linpeilie.processor.ProcessorOptions.UNMAPPED_TARGET_POLICY;
import static javax.tools.Diagnostic.Kind.ERROR;

@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,
                   TYPE_CONVERSION_POLICY, COLLECTION_MAPPING_STRATEGY, NULL_VALUE_ITERABLE_MAPPING_STRATEGY,
                   NULL_VALUE_MAP_MAPPING_STRATEGY, NULL_VALUE_CHECK_STRATEGY, SUPPRESS_TIMESTAMP_IN_GENERATED})
public class AutoMapperProcessor extends AbstractProcessor {

    private static final ClassName MAPPING_DEFAULT_TARGET = ClassName.get("io.github.linpeilie", "DefaultMapping");

    private final AutoMapperGenerator mapperGenerator;

    private AbstractAdapterMapperGenerator adapterMapperGenerator;

    private final MapperConfigGenerator mapperConfigGenerator;

    private final Map methodMap = new HashMap<>();

    private final Map mapMethodMap = new HashMap<>();

    private final List mapperList = new ArrayList<>();

    private final List customMapperList = new ArrayList<>();

    private final Set mapperSet = new HashSet<>();

    private static final Map AUTO_MAPPER_INDEX = new HashMap<>();

    private final Map> typeRelationMappers = new HashMap<>();

    private Messager messager;

    public AutoMapperProcessor() {
        this.mapperGenerator = new AutoMapperGenerator();
        this.mapperConfigGenerator = new MapperConfigGenerator();
    }

    private boolean isAutoMapperAnnotation(TypeElement annotation) {
        return ContextConstants.Annotations.autoMapper.contentEquals(annotation.getQualifiedName());
    }

    private boolean isAutoMappersAnnotation(TypeElement annotation) {
        return ContextConstants.Annotations.autoMappers.contentEquals(annotation.getQualifiedName());
    }

    private boolean isAutoMapMapperAnnotation(TypeElement annotation) {
        return ContextConstants.Annotations.autoMapMapper.contentEquals(annotation.getQualifiedName());
    }

    private boolean isAutoEnumMapperAnnotation(TypeElement annotation) {
        return ContextConstants.Annotations.autoEnumMapper.contentEquals(annotation.getQualifiedName());
    }

    private boolean isMapperConfigAnnotation(TypeElement annotation) {
        return ContextConstants.Annotations.mapperConfig.contentEquals(annotation.getQualifiedName());
    }

    private boolean isComponentModelConfigAnnotation(TypeElement annotation) {
        return ContextConstants.Annotations.componentModel.contentEquals(annotation.getQualifiedName());
    }

    @Override
    public synchronized void init(final ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
    }

    @Override
    public boolean process(final Set annotations, final RoundEnvironment roundEnv) {
        try {
            doProcess(annotations, roundEnv);
        } catch (Exception e) {
            messager.printMessage(ERROR, ExceptionUtils.getStackTrace(e));
        }

        return false;
    }

    private void doProcess(final Set annotations, final RoundEnvironment roundEnv) {
        boolean hasAutoMapper = annotations.stream().anyMatch(this::isAutoMapperAnnotation);
        final boolean hasAutoMapMapper = annotations.stream().anyMatch(this::isAutoMapMapperAnnotation);
        final boolean hasAutoEnumMapper = annotations.stream().anyMatch(this::isAutoEnumMapperAnnotation);
        final boolean hasAutoMapMappers = annotations.stream().anyMatch(this::isAutoMappersAnnotation);
        final boolean hasMapperConfig = annotations.stream().anyMatch(this::isMapperConfigAnnotation);
        if (!hasAutoMapper && !hasAutoMapMapper && !hasAutoEnumMapper && !hasAutoMapMappers && !hasMapperConfig) {
            return;
        }
        // 刷新配置
        refreshProperties(annotations, roundEnv);

        // 根据配置生成适配类生成器
        this.adapterMapperGenerator = AdapterMapperGeneratorFactory.instance(AutoMapperProperties.getComponentModel());

        // AutoMapMapper
        final TypeElement autoMapMapperAnnotation =
            processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoMapMapper);
        processAutoMapMapperAnnotation(roundEnv, autoMapMapperAnnotation);

        // AutoEnumMapper
        final TypeElement autoEnumMapperAnnotation =
            processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoEnumMapper);
        processAutoEnumMapperAnnotation(roundEnv, autoEnumMapperAnnotation);

        // AutoMapper
        final TypeElement autoMapperAnnotation =
            processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoMapper);
        processAutoMapperAnnotation(roundEnv, autoMapperAnnotation);

        // AutoMappers
        final TypeElement autoMappersAnnotation =
            processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.autoMappers);
        processAutoMappersAnnotation(roundEnv, autoMappersAnnotation);

        // custom mapper
        final TypeElement mapperAnnotation =
            processingEnv.getElementUtils().getTypeElement(ContextConstants.Mapper.qualifiedClassName);
        processMapperAnnotation(roundEnv, mapperAnnotation);

        // 生成类
        generateMapper();
    }

    private List getElementAndMergeHistory(final RoundEnvironment roundEnv,
        TypeElement annotation,
        BuildCollator buildCollator) {
        buildCollator.appendNonexistent(roundEnv.getElementsAnnotatedWith(annotation));
        return buildCollator.getRecords();
    }

    private void processMapperAnnotation(final RoundEnvironment roundEnv, final TypeElement annotation) {
        if (annotation == null) {
            return;
        }

        final List elements = getElementAndMergeHistory(roundEnv, annotation,
            new BuildCollator(processingEnv, ContextConstants.MetaInf.mappers));

        elements.forEach(element -> customMapperList.add(element.asType()));
    }

    private void processAutoEnumMapperAnnotation(final RoundEnvironment roundEnv, final TypeElement annotation) {
        if (annotation == null) {
            return;
        }
        final List elements = getElementAndMergeHistory(roundEnv, annotation,
            new BuildCollator(processingEnv, ContextConstants.MetaInf.enumMappers));
        elements.stream()
            .map(this::buildAutoEnumMapperMetadata)
            .filter(Objects::nonNull)
            .forEach(this::writeAutoEnumMapperFile);
    }

    private void writeAutoEnumMapperFile(final AutoEnumMapperMetadata autoEnumMapperMetadata) {
        final AutoEnumMapperGenerator autoEnumMapperGenerator = new AutoEnumMapperGenerator();
        try (final Writer writer = processingEnv.getFiler()
            .createSourceFile(autoEnumMapperMetadata.mapperPackage() + "." + autoEnumMapperMetadata.mapperName())
            .openWriter()) {
            autoEnumMapperGenerator.write(autoEnumMapperMetadata, writer);
        } catch (IOException e) {
            processingEnv.getMessager()
                .printMessage(ERROR,
                    "Error while opening " + autoEnumMapperMetadata.mapperName() + " output file : " + e.getMessage());
        }
        addAdapterMethodMetadata(autoEnumMapperMetadata);
    }

    private void addAdapterMethodMetadata(final AutoEnumMapperMetadata autoEnumMapperMetadata) {
        if (autoEnumMapperMetadata == null) {
            return;
        }
        // toValue
        final AdapterEnumMethodMetadata toValueProxyMethod =
            new AdapterEnumMethodMetadata(autoEnumMapperMetadata.getSourceClassName(),
                ClassName.get(autoEnumMapperMetadata.mapperPackage(), autoEnumMapperMetadata.mapperName()),
                autoEnumMapperMetadata.toValueMethodName(), autoEnumMapperMetadata.getReturnType());
        // toEnum
        final AdapterEnumMethodMetadata toEnumProxyMethod =
            new AdapterEnumMethodMetadata(autoEnumMapperMetadata.getReturnType(),
                ClassName.get(autoEnumMapperMetadata.mapperPackage(), autoEnumMapperMetadata.mapperName()),
                autoEnumMapperMetadata.toEnumMethodName(), autoEnumMapperMetadata.getSourceClassName());
        methodMap.putIfAbsent(
            autoEnumMapperMetadata.getSourceClassName().simpleName() + toValueProxyMethod.getMapperMethodName(),
            toValueProxyMethod);
        methodMap.put(
            autoEnumMapperMetadata.getSourceClassName().simpleName() + toEnumProxyMethod.getMapperMethodName(),
            toEnumProxyMethod);
    }

    private AutoEnumMapperMetadata buildAutoEnumMapperMetadata(final Element element) {
        final AutoEnumMapper autoEnumMapper = element.getAnnotation(AutoEnumMapper.class);
        final ClassName enumClassName = ClassName.get((TypeElement) element);
        final String enumCodeFieldName = autoEnumMapper.value();
        Element enumCodeGetterElement = null;
        // 获取getter
        final List enclosedElements = element.getEnclosedElements();
        for (Element ele : enclosedElements) {
            if (!ElementKind.METHOD.equals(ele.getKind())) {
                continue;
            }
            boolean isGetter = StrUtil.equalsIgnoreCase(ele.getSimpleName(), "get" + enumCodeFieldName) ||
                               StrUtil.equalsIgnoreCase(ele.getSimpleName(), "is" + enumCodeFieldName);
            if (isGetter) {
                enumCodeGetterElement = ele;
                break;
            }
        }
        if (enumCodeGetterElement == null) {
            return null;
        }
        final String getter = enumCodeGetterElement.getSimpleName().toString();
        final TypeName returnType = TypeName.get(((ExecutableElement) enumCodeGetterElement).getReturnType());

        AutoEnumMapperMetadata autoEnumMapperMetadata = new AutoEnumMapperMetadata();
        autoEnumMapperMetadata.setSourceClassName(enumClassName);
        autoEnumMapperMetadata.setGetter(getter);
        autoEnumMapperMetadata.setReturnType(returnType);

        return autoEnumMapperMetadata;
    }

    private void processAutoMapMapperAnnotation(final RoundEnvironment roundEnv, final TypeElement annotation) {
        if (annotation == null) {
            return;
        }

        final List elements = getElementAndMergeHistory(roundEnv, annotation,
            new BuildCollator(processingEnv, ContextConstants.MetaInf.autoMapMappers));

        elements.stream()
            .map(this::buildAutoMapMapperMetadata)
            .filter(Objects::nonNull)
            .forEach(metadata -> {
                this.writeAutoMapperClassFile(metadata);
                addAdapterMapMethod(metadata);
            });

        if (mapMethodMap.isEmpty()) {
            return;
        }

        adapterMapperGenerator.write(processingEnv,
            mapMethodMap.values(),
            AutoMapperProperties.getMapAdapterClassName(),
            false);

        mapperConfigGenerator.write(processingEnv, AutoMapperProperties.getMapConfigClassName(),
            AutoMapperProperties.getMapAdapterClassName(), null);
    }

    private AutoMapperMetadata buildAutoMapMapperMetadata(TypeElement element) {
        if (element.getAnnotation(AutoMapMapper.class) == null) {
            return null;
        }
        ClassName source = ClassName.get(ContextConstants.Map.packageName, ContextConstants.Map.className);
        ClassName target = ClassName.get(element);
        List uses = Collections.singletonList(
            ClassName.get(ContextConstants.MapObjectConvert.packageName, ContextConstants.MapObjectConvert.className));

        final AutoMapperMetadata autoMapperMetadata = new AutoMapMapperMetadata(source, target);
        autoMapperMetadata.setUsesClassNameList(uses);
        autoMapperMetadata.setSuperClass(
            ClassName.get(ContextConstants.BaseMapMapper.packageName, ContextConstants.BaseMapMapper.className));
        autoMapperMetadata.setSuperGenerics(new ClassName[] {target});
        autoMapperMetadata.setMapstructConfigClass(
            ClassName.get(AutoMapperProperties.getConfigPackage(), AutoMapperProperties.getMapConfigClassName()));
        return autoMapperMetadata;
    }

    private void addAdapterMapMethod(AutoMapperMetadata metadata) {
        if (metadata == null) {
            return;
        }
        addAdapterMapMethod(metadata.getSourceClassName(), metadata.getTargetClassName(), metadata.mapperClass(),
            false);
    }

    private void loadMapperConfig(MapperConfigGem mapperConfigGem) {
        if (mapperConfigGem == null || !mapperConfigGem.isValid()) {
            return;
        }
        if (mapperConfigGem.mapperPackage().hasValue()) {
            AutoMapperProperties.setMapperPackage(mapperConfigGem.mapperPackage().get());
        }
        AutoMapperProperties.setUnmappedSourcePolicy(mapperConfigGem.unmappedSourcePolicy().getValue());
        // 重定义 MapStruct 中 unmappedTargetPolicy 的默认值 WARN ---> IGNORE
        AutoMapperProperties.setUnmappedTargetPolicy(mapperConfigGem.unmappedTargetPolicy().get());
        AutoMapperProperties.setTypeConversionPolicy(mapperConfigGem.typeConversionPolicy().getValue());
        AutoMapperProperties.setCollectionMappingStrategy(mapperConfigGem.collectionMappingStrategy().getValue());
        AutoMapperProperties.setNullValueMappingStrategy(mapperConfigGem.nullValueMappingStrategy().getValue());
        AutoMapperProperties.setNullValueIterableMappingStrategy(
            mapperConfigGem.nullValueIterableMappingStrategy().getValue());
        AutoMapperProperties.setNullValueMapMappingStrategy(mapperConfigGem.nullValueMapMappingStrategy().getValue());
        AutoMapperProperties.setNullValuePropertyMappingStrategy(
            mapperConfigGem.nullValuePropertyMappingStrategy().getValue());
        AutoMapperProperties.setNullValueCheckStrategy(mapperConfigGem.nullValueCheckStrategy().getValue());
        if (mapperConfigGem.mappingControl().hasValue()) {
            AutoMapperProperties.setMappingControl(transToClassName(mapperConfigGem.mappingControl().get()));
        }
        if (mapperConfigGem.unexpectedValueMappingException().hasValue()) {
            AutoMapperProperties.setUnexpectedValueMappingException(
                transToClassName(mapperConfigGem.unexpectedValueMappingException().get()));
        }
        AutoMapperProperties.setSuppressTimestampInGenerated(mapperConfigGem.suppressTimestampInGenerated().getValue());
        BuilderGem builderGem = mapperConfigGem.builder().get();
        if (builderGem.buildMethod().hasValue()) {
            AutoMapperProperties.setBuildMethod(builderGem.buildMethod().get());
        }
        AutoMapperProperties.setDisableBuilder(builderGem.disableBuilder().get());
        if (mapperConfigGem.adapterPackage().hasValue()) {
            AutoMapperProperties.setAdapterPackage(mapperConfigGem.adapterPackage().get());
        }
        if (mapperConfigGem.adapterClassName().hasValue()) {
            AutoMapperProperties.setAdapterClassName(mapperConfigGem.adapterClassName().get());
        }
        if (mapperConfigGem.mapAdapterClassName().hasValue()) {
            AutoMapperProperties.setMapAdapterClassName(mapperConfigGem.mapAdapterClassName().get());
        }
        if (mapperConfigGem.autoConfigPackage().hasValue()) {
            AutoMapperProperties.setAutoConfigPackage(mapperConfigGem.autoConfigPackage().get());
        }
        if (mapperConfigGem.autoMapperConfigClassName().hasValue()) {
            AutoMapperProperties.setAutoMapperConfigClassName(mapperConfigGem.autoMapperConfigClassName().get());
        }
        if (mapperConfigGem.autoMapMapperConfigClassName().hasValue()) {
            AutoMapperProperties.setAutoMapMapperConfigClassName(mapperConfigGem.autoMapMapperConfigClassName().get());
        }
    }

    private void refreshProperties(final Set annotations, final RoundEnvironment roundEnv) {
        final BuildCollator buildCollator = new BuildCollator(processingEnv, ContextConstants.MetaInf.mapperConfig);

        // load previous mapper config
        final List typeElements = buildCollator.getRecords();
        if (CollectionUtils.isNotEmpty(typeElements)) {
            messager.printMessage(Diagnostic.Kind.NOTE,
                "The previous Mapper Config Class was read , class name : " + typeElements.get(0));
            loadMapperConfig(MapperConfigGem.instanceOn(typeElements.get(0)));
        }

        // annotation --> MapperConfig
        final TypeElement mapperConfigAnnotation =
            processingEnv.getElementUtils().getTypeElement(ContextConstants.Annotations.mapperConfig);
        if (mapperConfigAnnotation != null) {
            final Optional mapperConfigOptional =
                roundEnv.getElementsAnnotatedWith(mapperConfigAnnotation).stream().findFirst();
            if (mapperConfigOptional.isPresent()) {
                loadMapperConfig(MapperConfigGem.instanceOn(mapperConfigOptional.get()));
                // record
                buildCollator.writeTypeElements(Collections.singletonList((TypeElement) mapperConfigOptional.get()));
            }
        }

        // special MapperConfig Class
        final String mapperConfigClass = processingEnv.getOptions().get(MAPPER_CONFIG_CLASS);
        if (StrUtil.isNotEmpty(mapperConfigClass)) {
            final TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(mapperConfigClass);
            if (typeElement != null) {
                loadMapperConfig(MapperConfigGem.instanceOn(typeElement));
            }
        }

        // annotation --> ComponentModelConfig
        annotations.stream()
            .filter(this::isComponentModelConfigAnnotation)
            .findFirst()
            .flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream().findFirst())
            .ifPresent(element -> {
                final ComponentModelConfig componentModelConfig = element.getAnnotation(ComponentModelConfig.class);
                String componentModelByAnnotation = componentModelConfig.componentModel();
                AutoMapperProperties.setComponentModel(componentModelByAnnotation);
            });
        // compilerArgs
        loadCompilerArgs();
    }

    private void loadCompilerArgs() {
        ProcessorOptions.optionConsumers().forEach((key, consumer) -> {
            final String value = processingEnv.getOptions().get(key);
            if (StrUtil.isNotEmpty(value)) {
                consumer.accept(value);
            }
        });
    }

    private void processAutoMapperAnnotation(final RoundEnvironment roundEnv, final TypeElement annotation) {
        if (annotation == null) {
            return;
        }
        final List elements = getElementAndMergeHistory(roundEnv, annotation,
            new BuildCollator(processingEnv, ContextConstants.MetaInf.autoMapper));

        final List autoMapperMetadataList =
            elements.stream().map(this::buildAutoMapperMetadata).filter(Objects::nonNull).collect(Collectors.toList());

        mapperList.addAll(autoMapperMetadataList);
    }

    private void processAutoMappersAnnotation(final RoundEnvironment roundEnv, final TypeElement annotation) {
        if (annotation == null) {
            return;
        }
        final List autoMapperMetadata = getElementAndMergeHistory(roundEnv, annotation,
            new BuildCollator(processingEnv, ContextConstants.MetaInf.autoMappers)).stream()
            .map(this::buildAutoMapperMetadataByAutoMappers)
            .filter(Objects::nonNull)
            .flatMap(Collection::stream)
            .collect(Collectors.toList());

        mapperList.addAll(autoMapperMetadata);
    }

    private List generateReverseConverters() {
        List reverseMapperMetadataList = new ArrayList<>();

        mapperList.forEach(autoMapperMetadata -> {
            if (!autoMapperMetadata.isReverseConvertGenerate()) {
                return;
            }
            boolean defineReverseMapping = CollectionUtils.isNotEmpty(autoMapperMetadata.getFieldReverseMappingList());
            final AutoMapperMetadata reverseMapperMetadata = reverseMapper(autoMapperMetadata);
            if (defineReverseMapping) {
                addMapper(reverseMapperMetadata, true);
            } else if (!addMapper(reverseMapperMetadata, false)) {
                return;
            }
            reverseMapperMetadataList.add(reverseMapperMetadata);
        });

        return reverseMapperMetadataList;
    }

    private void typeRelationMapper(AutoMapperMetadata metadata) {
        String source = metadata.getSourceClassName().reflectionName();
        if (!typeRelationMappers.containsKey(source)) {
            typeRelationMappers.put(source, new ArrayList<>());
        }
        typeRelationMappers.get(source).add(metadata.mapperClass());

        String target = metadata.getTargetClassName().reflectionName();
        if (!typeRelationMappers.containsKey(target)) {
            typeRelationMappers.put(target, new ArrayList<>());
        }
        typeRelationMappers.get(target).add(metadata.mapperClass());
    }

    private void generateMapper() {
        mapperList.addAll(generateReverseConverters());

        mapperList.removeIf(metadata -> !metadata.isConvertGenerate());

        mapperList.forEach(metadata -> {
            // 兼容同模块下,同名不同包的场景
            this.mapperNameAddSuffix(metadata);

            if (metadata.isCycleAvoiding()) {
                addAdapterMethod(metadata);
            } else {
                typeRelationMapper(metadata);
            }
        });

        mapperList.forEach(metadata -> {
            this.relationDependencies(metadata);
            this.usesRemoveItself(metadata);
            this.writeAutoMapperClassFile(metadata);
        });

        adapterMapperGenerator.write(processingEnv,
            methodMap.values(),
            AutoMapperProperties.getAdapterClassName(),
            false);

        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 void mapperNameAddSuffix(AutoMapperMetadata metadata) {
        String mapperName = metadata.mapperName();
        // 同名类时,增加后缀
        Integer index = AUTO_MAPPER_INDEX.getOrDefault(mapperName, 0);
        if (index > 0) {
            mapperName = mapperName + "__" + index;
        }
        AUTO_MAPPER_INDEX.put(metadata.mapperName(), ++index);
        metadata.setMapperName(mapperName);
    }

    private void relationDependencies(AutoMapperMetadata metadata) {
        Set dependencies = metadata.getDependencies();
        if (CollectionUtils.isNotEmpty(dependencies)) {
            List dependencyMappers = dependencies.stream().map(dependency ->
                typeRelationMappers.get(dependency.toString())
            ).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(dependencyMappers)) {
                metadata.addUseList(dependencyMappers);
            }
        }
        // source
        List sourceDependencies =
            typeRelationMappers.get(metadata.getSourceClassName().reflectionName());

        if (CollectionUtils.isNotEmpty(sourceDependencies)) {
            metadata.addUseList(sourceDependencies);
        }
    }

    private void usesRemoveItself(AutoMapperMetadata metadata) {
        // remove itself
        if (CollectionUtils.isNotEmpty(metadata.getUsesClassNameList())) {
            metadata.getUsesClassNameList()
                .removeIf(use -> use.reflectionName().equals(metadata.mapperClass().reflectionName()));
        }
    }

    private Set listDependencies(TypeElement autoMapperEle) {
        Set set = new HashSet<>();

        if (!autoMapperEle.getKind().isClass() && !autoMapperEle.getKind().isInterface()) {
            return set;
        }

        for (Element ele : autoMapperEle.getEnclosedElements()) {
            if (ele.getKind() != ElementKind.FIELD) {
                continue;
            }
            TypeName typeName = ClassName.get(ele.asType());
            if (typeName instanceof ArrayTypeName) {
                ArrayTypeName arrayTypeName = (ArrayTypeName) typeName;
                typeName = arrayTypeName.componentType;
            } else if (typeName instanceof ParameterizedTypeName) {
                ParameterizedTypeName parameterizedTypeName = (ParameterizedTypeName) typeName;
                List typeArguments = parameterizedTypeName.typeArguments;
                set.addAll(typeArguments);
                continue;
            }
            set.add(typeName);
        }

        // add super class dependencies
        getSuperClass(autoMapperEle).ifPresent(superClass -> set.addAll(listDependencies(superClass)));

        set.removeIf(ele -> {
            if (ele == null) {
                return true;
            }
            try {
                if (ele.box().isBoxedPrimitive()) {
                    return true;
                }
            } catch (Exception e) {
                // ignore
            }
            return false;
        });
        return set;
    }

    private AutoMapperMetadata reverseMapper(AutoMapperMetadata autoMapperMetadata) {
        AutoMapperMetadata reverseMapperMetadata =
            initAutoMapperMetadata(autoMapperMetadata.getTargetClassName(),
                autoMapperMetadata.getSourceClassName(),
                autoMapperMetadata.isCycleAvoiding());
        reverseMapperMetadata.setConvertGenerate(autoMapperMetadata.isReverseConvertGenerate());
        reverseMapperMetadata.setUsesClassNameList(autoMapperMetadata.getUsesClassNameList());
        reverseMapperMetadata.setImportsClassNameList(autoMapperMetadata.getImportsClassNameList());
        reverseMapperMetadata.setCycleAvoiding(autoMapperMetadata.isCycleAvoiding());
        if (reverseMapperMetadata.isCycleAvoiding()) {
            reverseMapperMetadata.setSuperClass(ClassName.get(ContextConstants.BaseCycleAvoidingMapper.packageName,
                ContextConstants.BaseCycleAvoidingMapper.className));
        } else {
            reverseMapperMetadata.setSuperClass(
                ClassName.get(ContextConstants.BaseMapper.packageName, ContextConstants.BaseMapper.className));
        }
        reverseMapperMetadata.setUnmappedSourcePolicy(autoMapperMetadata.getUnmappedSourcePolicy());
        reverseMapperMetadata.setUnmappedTargetPolicy(autoMapperMetadata.getUnmappedTargetPolicy());
        reverseMapperMetadata.setTypeConversionPolicy(autoMapperMetadata.getTypeConversionPolicy());
        reverseMapperMetadata.setCollectionMappingStrategy(autoMapperMetadata.getCollectionMappingStrategy());
        reverseMapperMetadata.setNullValueMappingStrategy(autoMapperMetadata.getNullValueMappingStrategy());
        reverseMapperMetadata.setNullValueIterableMappingStrategy(
            autoMapperMetadata.getNullValueIterableMappingStrategy());
        reverseMapperMetadata.setNullValuePropertyMappingStrategy(
            autoMapperMetadata.getNullValuePropertyMappingStrategy());
        reverseMapperMetadata.setNullValueCheckStrategy(autoMapperMetadata.getNullValueCheckStrategy());
        reverseMapperMetadata.setMappingControl(autoMapperMetadata.getMappingControl());
        reverseMapperMetadata.setMapperNameSuffix(autoMapperMetadata.getMapperNameSuffix());

        List fieldReverseMappingList = autoMapperMetadata.getFieldReverseMappingList();
        if (CollectionUtils.isEmpty(fieldReverseMappingList)) {
            // 默认的规则
            Map autoMappingMap =
                autoMapperMetadata.getFieldMappingList().stream()
                    .filter(AutoMappingMetadata::getReverseConvertGenerate)
                    .map(fieldMapping -> {
                        final AutoMappingMetadata autoMappingMetadata = new AutoMappingMetadata();
                        autoMappingMetadata.setSource(fieldMapping.getTarget());
                        autoMappingMetadata.setTarget(fieldMapping.getSource());
                        return autoMappingMetadata;
                    }).collect(Collectors.toMap(AutoMappingMetadata::getTarget, Function.identity(), (a, b) -> a));
            fieldReverseMappingList = new ArrayList<>(autoMappingMap.values());
        }
        reverseMapperMetadata.setFieldMappingList(fieldReverseMappingList);
        return reverseMapperMetadata;
    }

    private void writeAutoMapperClassFile(AutoMapperMetadata metadata) {
        mapperGenerator.write(metadata, processingEnv);
    }

    private void addAdapterMethod(AutoMapperMetadata metadata) {
        if (metadata == null) {
            return;
        }
        AdapterMethodMetadata adapterMethodMetadata =
            AdapterMethodMetadata.newInstance(metadata.getSourceClassName(), metadata.getTargetClassName(),
                metadata.mapperClass(), metadata.isCycleAvoiding());
        methodMap.putIfAbsent(adapterMethodMetadata.getMethodName(), adapterMethodMetadata);
    }

    private void addAdapterMapMethod(ClassName source, ClassName target, ClassName mapper, boolean objectConverter) {
        final AdapterMapMethodMetadata adapterMapMethodMetadata =
            new AdapterMapMethodMetadata(source, target, mapper, objectConverter);
        mapMethodMap.putIfAbsent(adapterMapMethodMetadata.getMethodName(), adapterMapMethodMetadata);
    }

    private AutoMapperMetadata initAutoMapperMetadata(ClassName source, ClassName target, boolean cycleAvoiding) {
        AutoMapperMetadata metadata = new AutoMapperMetadata(source, target);

        metadata.setSuperGenerics(new ClassName[] {source, target});
        ClassName mapStructConfigClass;
        if (cycleAvoiding) {
            mapStructConfigClass = ClassName.get(AutoMapperProperties.getConfigPackage(),
                AutoMapperProperties.getCycleAvoidingConfigClassName());
        } else {
            mapStructConfigClass = ClassName.get(AutoMapperProperties.getConfigPackage(),
                AutoMapperProperties.getConfigClassName());
        }
        metadata.setMapstructConfigClass(mapStructConfigClass);
        return metadata;
    }

    private List buildAutoMapperMetadataByAutoMappers(final Element ele) {
        AutoMappersGem autoMappersGem = AutoMappersGem.instanceOn(ele);
        if (autoMappersGem == null || !autoMappersGem.isValid()) {
            return null;
        }

        Set targetClassNames = new HashSet<>();

        return autoMappersGem.value().getValue().stream().filter(autoMapperGem -> {
                if (autoMapperGem == null || !autoMapperGem.isValid()) {
                    return false;
                }
                TypeMirror target = autoMapperGem.target().getValue();
                return targetClassNames.add(target.toString());
            }).map(autoMapperGem -> buildAutoMapperMetadata(autoMapperGem, ele))
            .collect(Collectors.toList());
    }

    private AutoMapperMetadata buildAutoMapperMetadata(final Element ele) {
        AutoMapperGem autoMapperGem = AutoMapperGem.instanceOn(ele);
        if (autoMapperGem == null || !autoMapperGem.isValid()) {
            return null;
        }

        return buildAutoMapperMetadata(autoMapperGem, ele);
    }

    private List matchTargetFieldMapping(List autoMappingMetadataList,
        ClassName target) {
        // 先删除非当面目标类或父类的
        autoMappingMetadataList.removeIf(mappingMetadata -> !isTargetFieldMapping(target, mappingMetadata));
        // 适配目标属性同时配置了目标类及目标类父类的场景
        Map> targetFieldAutoMappingMap = autoMappingMetadataList.stream()
            .collect(Collectors.groupingBy(AutoMappingMetadata::getTarget));

        List result = new ArrayList<>();

        targetFieldAutoMappingMap.forEach((key, list) -> {
            // 只有一个场景
            if (list.size() == 1) {
                result.add(list.get(0));
                return;
            }
            // 有多个时,先匹配目标类型
            ClassName targetClassName = target;
            while (targetClassName != null) {
                ClassName finalTargetClassName = targetClassName;
                List matchedList = list.stream()
                    .filter(mappingMetadata -> mappingMetadata.getTargetClass()
                        .reflectionName()
                        .equals(finalTargetClassName.reflectionName()))
                    .collect(Collectors.toList());
                if (!matchedList.isEmpty()) {
                    result.addAll(matchedList);
                    return;
                }
                targetClassName = getSuperClass(classNameToTypeElement(targetClassName))
                    .map(ClassName::get)
                    .orElse(null);
            }
            // 如果没有匹配到,则添加所有的
            result.addAll(list);
        });

        return result;
    }

    private boolean isTargetFieldMapping(ClassName target, AutoMappingMetadata mappingMetadata) {
        if (MAPPING_DEFAULT_TARGET.reflectionName().contentEquals(mappingMetadata.getTargetClass().reflectionName())) {
            return true;
        }
        if (target.reflectionName().contentEquals(mappingMetadata.getTargetClass().reflectionName())) {
            return true;
        }
        TypeElement targetTypeElement = classNameToTypeElement(target);
        Optional superClass = getSuperClass(targetTypeElement);
        return superClass.filter(typeElement -> isTargetFieldMapping(ClassName.get(typeElement), mappingMetadata))
            .isPresent();
    }

    private Optional getSuperClass(TypeElement ele) {
        TypeMirror superclass = ele.getSuperclass();
        if (superclass == null) {
            return Optional.empty();
        }
        if ("java.lang.Object".equals(superclass.toString())) {
            return Optional.empty();
        }
        if (ele.getQualifiedName().contentEquals(superclass.toString())) {
            return Optional.empty();
        }
        return Optional.of((TypeElement) processingEnv.getTypeUtils().asElement(superclass));
    }

    private AutoMapperMetadata buildAutoMapperMetadata(final AutoMapperGem autoMapperGem, final Element ele) {
        ClassName source = ClassName.get((TypeElement) ele);
        ClassName target = (ClassName) ClassName.get(autoMapperGem.target().getValue());
        if (target == null) {
            return null;
        }

        List autoMappingMetadataList =
            matchTargetFieldMapping(buildFieldMappingMetadata((TypeElement) ele), target);

        List reverseMappingMetadataList =
            matchTargetFieldMapping(buildFieldReverseMappingMetadata((TypeElement) ele), target);

        AutoMapperMetadata metadata = initAutoMapperMetadata(source, target, autoMapperGem.cycleAvoiding().get());

        List usesClassNameList = transToClassNameList(autoMapperGem.uses().get());
        List useEnumClassNameList = transToClassNameList(autoMapperGem.useEnums().get()).stream()
            .map(enumClass -> ClassName.get(MapperUtils.getMapperPackage(enumClass.packageName()),
                MapperUtils.getEnumMapperClassName(enumClass.simpleName())))
            .collect(Collectors.toList());

        // dependencies
        Set dependencies = listDependencies((TypeElement) ele);

        usesClassNameList.addAll(useEnumClassNameList);

        metadata.setUsesClassNameList(usesClassNameList);
        metadata.setImportsClassNameList(transToClassNameList(autoMapperGem.imports().get()));
        metadata.setFieldMappingList(autoMappingMetadataList);
        metadata.setFieldReverseMappingList(reverseMappingMetadataList);
        metadata.setConvertGenerate(autoMapperGem.convertGenerate().get());
        metadata.setReverseConvertGenerate(autoMapperGem.reverseConvertGenerate().get());
        metadata.setCycleAvoiding(autoMapperGem.cycleAvoiding().get());
        if (metadata.isCycleAvoiding()) {
            metadata.setSuperClass(ClassName.get(ContextConstants.BaseCycleAvoidingMapper.packageName,
                ContextConstants.BaseCycleAvoidingMapper.className));
        } else {
            metadata.setSuperClass(
                ClassName.get(ContextConstants.BaseMapper.packageName, ContextConstants.BaseMapper.className));
        }
        metadata.setUnmappedSourcePolicy(autoMapperGem.unmappedSourcePolicy().getValue());
        metadata.setUnmappedTargetPolicy(autoMapperGem.unmappedTargetPolicy().getValue());
        metadata.setTypeConversionPolicy(autoMapperGem.typeConversionPolicy().getValue());
        metadata.setCollectionMappingStrategy(autoMapperGem.collectionMappingStrategy().getValue());
        metadata.setNullValueMappingStrategy(autoMapperGem.nullValueMappingStrategy().getValue());
        metadata.setNullValueIterableMappingStrategy(autoMapperGem.nullValueIterableMappingStrategy().getValue());
        metadata.setNullValuePropertyMappingStrategy(autoMapperGem.nullValuePropertyMappingStrategy().getValue());
        metadata.setNullValueCheckStrategy(autoMapperGem.nullValueCheckStrategy().getValue());
        metadata.setMappingControl(transToClassName(autoMapperGem.mappingControl().getValue()));
        if (StrUtil.isNotEmpty(autoMapperGem.mapperName().getValue())) {
            metadata.setMapperName(autoMapperGem.mapperName().getValue());
        }
        metadata.setMapperNameSuffix(autoMapperGem.mapperNameSuffix().getValue());
        metadata.setDependencies(dependencies);

        addMapper(metadata, true);

        return metadata;
    }

    private List buildFieldReverseMappingMetadata(final TypeElement ele) {
        List list = new ArrayList<>();
        if (!ele.getKind().isClass() && !ele.getKind().isInterface()) {
            return list;
        }
        for (Element field : ele.getEnclosedElements()) {
            if (field.getKind() != ElementKind.FIELD && field.getKind() != ElementKind.METHOD) {
                continue;
            }
            ReverseAutoMappingGem reverseAutoMappingGem = ReverseAutoMappingGem.instanceOn(field);
            if (reverseAutoMappingGem != null && reverseAutoMappingGem.isValid()) {
                list.add(buildAutoMappingMetadata(reverseAutoMappingGem, field));
            }
            ReverseAutoMappingsGem reverseAutoMappingsGem = ReverseAutoMappingsGem.instanceOn(field);
            if (reverseAutoMappingsGem != null && reverseAutoMappingsGem.isValid()) {
                reverseAutoMappingsGem.value().get().forEach(a -> list.add(buildAutoMappingMetadata(a, field)));
            }
        }

        // super class
        getSuperClass(ele).ifPresent(superClass -> list.addAll(buildFieldReverseMappingMetadata(superClass)));

        list.removeIf(Objects::isNull);
        return list;
    }

    private AutoMappingMetadata buildAutoMappingMetadata(ReverseAutoMappingGem reverseAutoMappingGem, Element ele) {
        ClassName targetClass = transToClassName(reverseAutoMappingGem.targetClass().get());
        if (targetClass == null) {
            return null;
        }

        AutoMappingMetadata metadata = new AutoMappingMetadata();
        if (StrUtil.isNotEmpty(reverseAutoMappingGem.source().get())) {
            metadata.setSource(reverseAutoMappingGem.source().get());
        } else {
            metadata.setSource(ele.getSimpleName().toString());
        }
        if (StrUtil.isNotEmpty(reverseAutoMappingGem.target().get())) {
            metadata.setTarget(reverseAutoMappingGem.target().get());
        } else {
            metadata.setTarget(ele.getSimpleName().toString());
        }
        metadata.setTargetClass(targetClass);
        metadata.setDefaultValue(reverseAutoMappingGem.defaultValue().getValue());
        metadata.setIgnore(reverseAutoMappingGem.ignore().getValue());
        metadata.setExpression(reverseAutoMappingGem.expression().getValue());
        metadata.setDefaultExpression(reverseAutoMappingGem.defaultExpression().getValue());
        metadata.setConditionExpression(reverseAutoMappingGem.conditionExpression().getValue());
        metadata.setDateFormat(reverseAutoMappingGem.dateFormat().getValue());
        metadata.setNumberFormat(reverseAutoMappingGem.numberFormat().getValue());
        metadata.setQualifiedByName(reverseAutoMappingGem.qualifiedByName().getValue());
        metadata.setConditionQualifiedByName(reverseAutoMappingGem.conditionQualifiedByName().getValue());
        metadata.setDependsOn(reverseAutoMappingGem.dependsOn().getValue());
        metadata.setConstant(reverseAutoMappingGem.constant().getValue());
        metadata.setQualifiedBy(transToClassNameList(reverseAutoMappingGem.qualifiedBy().getValue()));
        metadata.setNullValueCheckStrategy(reverseAutoMappingGem.nullValueCheckStrategy().getValue());
        metadata.setNullValuePropertyMappingStrategy(
            reverseAutoMappingGem.nullValuePropertyMappingStrategy().getValue());
        metadata.setMappingControl(transToClassName(reverseAutoMappingGem.mappingControl().getValue()));

        return metadata;
    }

    private boolean addMapper(AutoMapperMetadata metadata, boolean throwsException) {
        boolean addSuccess = mapperSet.add(
            metadata.getSourceClassName().reflectionName() + "To" + metadata.getTargetClassName().reflectionName());
        if (throwsException) {

            if (!addSuccess) {
                throw new DuplicateMapperException("An exception occurred to generate " + metadata.mapperName() +
                                                   ", check the mapping configuration for " +
                                                   metadata.getSourceClassName().reflectionName() + " or " +
                                                   metadata.getTargetClassName().reflectionName());
            }
        }
        return addSuccess;
    }

    private List buildFieldMappingMetadata(final TypeElement autoMapperEle) {
        List list = new ArrayList<>();

        if (!autoMapperEle.getKind().isClass() && !autoMapperEle.getKind().isInterface()) {
            return list;
        }

        for (Element ele : autoMapperEle.getEnclosedElements()) {
            if (ele.getKind() != ElementKind.FIELD && ele.getKind() != ElementKind.METHOD) {
                continue;
            }
            AutoMappingGem autoMappingGem = AutoMappingGem.instanceOn(ele);
            if (autoMappingGem != null && autoMappingGem.isValid()) {
                list.add(buildAutoMappingMetadata(autoMappingGem, ele));
            }
            AutoMappingsGem autoMappingsGem = AutoMappingsGem.instanceOn(ele);
            if (autoMappingsGem != null && autoMappingsGem.isValid()) {
                autoMappingsGem.value().get().forEach(a -> list.add(buildAutoMappingMetadata(a, ele)));
            }
        }

        // add super class AutoMappings
        getSuperClass(autoMapperEle).ifPresent(superClass -> list.addAll(buildFieldMappingMetadata(superClass)));

        list.removeIf(Objects::isNull);
        return list;
    }

    private AutoMappingMetadata buildAutoMappingMetadata(AutoMappingGem autoMappingGem, Element ele) {
        ClassName targetClass = transToClassName(autoMappingGem.targetClass().get());
        if (targetClass == null) {
            return null;
        }

        AutoMappingMetadata metadata = new AutoMappingMetadata();
        String elementName = ele.getSimpleName().toString();

        if (ele.getKind() == ElementKind.METHOD) {
            elementName = ObjectUtils.defaultIfNull(StrUtil.getGeneralField(elementName), elementName);
        }

        if (StrUtil.isNotEmpty(autoMappingGem.source().get())) {
            metadata.setSource(autoMappingGem.source().get());
        } else {
            metadata.setSource(elementName);
        }
        if (StrUtil.isNotEmpty(autoMappingGem.target().get())) {
            metadata.setTarget(autoMappingGem.target().get());
        } else {
            metadata.setTarget(elementName);
        }
        metadata.setTargetClass(targetClass);
        metadata.setReverseConvertGenerate(autoMappingGem.reverseConvertGenerate().get());
        metadata.setDefaultValue(autoMappingGem.defaultValue().getValue());
        metadata.setIgnore(autoMappingGem.ignore().getValue());
        metadata.setExpression(autoMappingGem.expression().getValue());
        metadata.setDefaultExpression(autoMappingGem.defaultExpression().getValue());
        metadata.setConditionExpression(autoMappingGem.conditionExpression().getValue());
        metadata.setDateFormat(autoMappingGem.dateFormat().getValue());
        metadata.setNumberFormat(autoMappingGem.numberFormat().getValue());
        metadata.setQualifiedByName(autoMappingGem.qualifiedByName().getValue());
        metadata.setConditionQualifiedByName(autoMappingGem.conditionQualifiedByName().getValue());
        metadata.setDependsOn(autoMappingGem.dependsOn().getValue());
        metadata.setConstant(autoMappingGem.constant().getValue());
        metadata.setQualifiedBy(transToClassNameList(autoMappingGem.qualifiedBy().getValue()));
        metadata.setNullValueCheckStrategy(autoMappingGem.nullValueCheckStrategy().getValue());
        metadata.setNullValuePropertyMappingStrategy(autoMappingGem.nullValuePropertyMappingStrategy().getValue());
        metadata.setMappingControl(transToClassName(autoMappingGem.mappingControl().getValue()));
        return metadata;
    }

    private ClassName transToClassName(Supplier> classSupplier) {
        TypeMirror typeMirror = null;
        try {
            Class targetClass = classSupplier.get();
        } catch (MirroredTypeException e) {
            typeMirror = e.getTypeMirror();
        }
        if (typeMirror == null) {
            return null;
        }
        return (ClassName) ClassName.get(typeMirror);
    }

    private List transToClassNameList(Supplier[]> classSuppler) {
        List typeMirrors = null;
        try {
            Class[] classes = classSuppler.get();
        } catch (MirroredTypesException e) {
            typeMirrors = e.getTypeMirrors();
        }
        return typeMirrors.stream()
            .map(typeMirror -> (ClassName) ClassName.get(typeMirror))
            .collect(Collectors.toList());
    }

    private List transToClassNameList(List typeMirrors) {
        if (typeMirrors == null) {
            return new ArrayList<>();
        }
        return typeMirrors.stream()
            .map(this::transToClassName)
            .collect(Collectors.toList());
    }

    private ClassName transToClassName(TypeMirror typeMirror) {
        if (typeMirror == null) {
            return null;
        }
        return (ClassName) ClassName.get(typeMirror);
    }

    private TypeElement classNameToTypeElement(ClassName className) {
        String classNameString = className.toString();
        return processingEnv.getElementUtils().getTypeElement(classNameString);
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy