不可变对象支持

This commit is contained in:
linpeilie 2023-06-17 21:37:07 +08:00
parent 13dad0a31b
commit 48bc0b863c
4 changed files with 69 additions and 18 deletions

View File

@ -459,7 +459,7 @@ public class AutoMapperProcessor extends AbstractProcessor {
try (final Writer writer = processingEnv.getFiler() try (final Writer writer = processingEnv.getFiler()
.createSourceFile(mapperPackage + "." + mapperClassName) .createSourceFile(mapperPackage + "." + mapperClassName)
.openWriter()) { .openWriter()) {
mapperGenerator.write(metadata, writer); mapperGenerator.write(metadata, processingEnv, writer);
} catch (IOException e) { } catch (IOException e) {
processingEnv.getMessager() processingEnv.getMessager()
.printMessage(ERROR, .printMessage(ERROR,

View File

@ -1,5 +1,6 @@
package io.github.linpeilie.processor.generator; package io.github.linpeilie.processor.generator;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
@ -9,7 +10,7 @@ import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec;
import io.github.linpeilie.processor.AutoMapperProperties; import io.github.linpeilie.annotations.ImmutableEntity;
import io.github.linpeilie.processor.metadata.AutoMapperMetadata; import io.github.linpeilie.processor.metadata.AutoMapperMetadata;
import io.github.linpeilie.processor.metadata.AutoMappingMetadata; import io.github.linpeilie.processor.metadata.AutoMappingMetadata;
import java.io.IOException; import java.io.IOException;
@ -21,17 +22,20 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.mapstruct.ReportingPolicy;
import static io.github.linpeilie.processor.Constants.*; import static io.github.linpeilie.processor.Constants.*;
public class AutoMapperGenerator { public class AutoMapperGenerator {
public void write(AutoMapperMetadata metadata, Writer writer) { public static final String CONVERT_METHOD_NAME = "convert";
public void write(AutoMapperMetadata metadata, final ProcessingEnvironment processingEnv, Writer writer) {
try { try {
JavaFile.builder(metadata.mapperPackage(), createTypeSpec(metadata)).build().writeTo(writer); JavaFile.builder(metadata.mapperPackage(), createTypeSpec(processingEnv, metadata)).build().writeTo(writer);
} catch (IOException e) { } catch (IOException e) {
throw new UncheckedIOException(e); throw new UncheckedIOException(e);
} catch (Exception e) { } catch (Exception e) {
@ -39,36 +43,70 @@ public class AutoMapperGenerator {
} }
} }
private TypeSpec createTypeSpec(AutoMapperMetadata metadata) { private TypeSpec createTypeSpec(ProcessingEnvironment processingEnv, AutoMapperMetadata metadata) {
ParameterizedTypeName converterName = ParameterizedTypeName converterName =
ParameterizedTypeName.get(metadata.getSuperClass(), metadata.getSuperGenerics()); ParameterizedTypeName.get(metadata.getSuperClass(), metadata.getSuperGenerics());
final ClassName targetClassName = metadata.getTargetClassName();
TypeSpec.Builder builder = TypeSpec.interfaceBuilder(metadata.mapperName()) TypeSpec.Builder builder = TypeSpec.interfaceBuilder(metadata.mapperName())
.addSuperinterface(converterName) .addSuperinterface(converterName)
.addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.PUBLIC)
.addAnnotation(buildGeneratedMapperAnnotationSpec(metadata)); .addAnnotation(buildGeneratedMapperAnnotationSpec(metadata));
if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) {
final ParameterSpec source = ParameterSpec.builder(metadata.getSourceClassName(), "source").build(); final ParameterSpec source = ParameterSpec.builder(metadata.getSourceClassName(), "source").build();
final ParameterSpec target = ParameterSpec.builder(metadata.getTargetClassName(), "target") final ParameterSpec target = ParameterSpec.builder(targetClassName, "target")
.addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build()) .addAnnotation(AnnotationSpec.builder(ClassName.get("org.mapstruct", "MappingTarget")).build())
.build(); .build();
if (metadata.getFieldMappingList() != null && !metadata.getFieldMappingList().isEmpty()) {
builder.addMethod(addConvertMethodSpec(Collections.singletonList(source), metadata.getFieldMappingList(), builder.addMethod(addConvertMethodSpec(Collections.singletonList(source), metadata.getFieldMappingList(),
metadata.getTargetClassName())); targetClassName));
builder.addMethod(addConvertMethodSpec(Arrays.asList(source, target), metadata.getFieldMappingList(),
metadata.getTargetClassName()));
} }
boolean targetIsImmutable = classIsImmutable(processingEnv, targetClassName);
if (targetIsImmutable) {
builder.addMethod(addEmptyConvertMethodForImmutableEntity(source, target, targetClassName));
} else {
builder.addMethod(addConvertMethodSpec(Arrays.asList(source, target), metadata.getFieldMappingList(),
targetClassName));
}
return builder.build(); return builder.build();
} }
private MethodSpec addEmptyConvertMethodForImmutableEntity(ParameterSpec source,
ParameterSpec target,
ClassName targetClassName) {
return MethodSpec.methodBuilder(CONVERT_METHOD_NAME)
.addModifiers(Modifier.PUBLIC, Modifier.DEFAULT)
.addParameter(source)
.addParameter(target)
.returns(targetClassName)
.addCode("return target;")
.build();
}
private boolean classIsImmutable(ProcessingEnvironment processingEnv, ClassName className) {
final TypeElement targetElement = processingEnv.getElementUtils()
.getTypeElement(className.packageName() + "." + className.simpleName());
if (targetElement != null) {
return targetElement.getAnnotation(ImmutableEntity.class) != null;
}
return false;
}
private MethodSpec addConvertMethodSpec(List<ParameterSpec> parameterSpecs, private MethodSpec addConvertMethodSpec(List<ParameterSpec> parameterSpecs,
List<AutoMappingMetadata> autoMappingMetadataList, List<AutoMappingMetadata> autoMappingMetadataList,
ClassName target) { ClassName target) {
return MethodSpec.methodBuilder("convert") final MethodSpec.Builder methodSpecBuilder = MethodSpec.methodBuilder(CONVERT_METHOD_NAME)
.addParameters(parameterSpecs) .addParameters(parameterSpecs)
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
.addAnnotations(buildMappingAnnotations(autoMappingMetadataList)) .returns(target);
.returns(target) if (CollectionUtil.isNotEmpty(autoMappingMetadataList)) {
.build(); methodSpecBuilder.addAnnotations(buildMappingAnnotations(autoMappingMetadataList));
}
return methodSpecBuilder.build();
} }
private List<AnnotationSpec> buildMappingAnnotations(final List<AutoMappingMetadata> autoMappingMetadataList) { private List<AnnotationSpec> buildMappingAnnotations(final List<AutoMappingMetadata> autoMappingMetadataList) {

View File

@ -0,0 +1,13 @@
package io.github.linpeilie.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface ImmutableEntity {
}

View File

@ -17,7 +17,7 @@
</modules> </modules>
<properties> <properties>
<mapstruct-plus.version>1.3.1</mapstruct-plus.version> <mapstruct-plus.version>1.3.2-SNAPSHOT</mapstruct-plus.version>
<maven.compiler.source>8</maven.compiler.source> <maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target> <maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>