解决 MapAdapterConvert 告警问题;
feature: 适配 solon
This commit is contained in:
linpeilie 2023-05-23 18:04:56 +08:00
parent 957d139d6b
commit 899636e41d
12 changed files with 216 additions and 61 deletions

View File

@ -56,7 +56,7 @@ public class User {
```xml ```xml
<properties> <properties>
<mapstruct-plus.version>1.2.4</mapstruct-plus.version> <mapstruct-plus.version>1.2.5</mapstruct-plus.version>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>

View File

@ -52,14 +52,14 @@ copyright: false
<dependency> <dependency>
<groupId>io.github.linpeilie</groupId> <groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId> <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>1.2.4</version> <version>1.2.5</version>
</dependency> </dependency>
``` ```
- gradle - gradle
```groovy ```groovy
implementation group: 'io.github.linpeilie', name: 'mapstruct-plus-spring-boot-starter', version: '1.2.4' implementation group: 'io.github.linpeilie', name: 'mapstruct-plus-spring-boot-starter', version: '1.2.5'
``` ```
## 更新日志 ## 更新日志

View File

@ -18,7 +18,7 @@
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<mapstruct.version>1.5.1.Final</mapstruct.version> <mapstruct.version>1.5.1.Final</mapstruct.version>
<mapstruct-plus.version>1.2.3</mapstruct-plus.version> <mapstruct-plus.version>1.2.5</mapstruct-plus.version>
<lombok.version>1.18.22</lombok.version> <lombok.version>1.18.22</lombok.version>
</properties> </properties>

View File

@ -1,9 +1,12 @@
package io.github.linpeilie.processor; package io.github.linpeilie.processor;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile; import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec;
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata; import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
import java.io.IOException; import java.io.IOException;
@ -39,11 +42,24 @@ public abstract class AbstractAdapterMapperGenerator {
return AutoMapperProperties.getAdapterPackage(); return AutoMapperProperties.getAdapterPackage();
} }
private TypeName wrapperTypeName(TypeName source) {
if (source.isPrimitive() || source.isBoxedPrimitive()) {
return source;
}
if ("java.util.Map".contentEquals(source.toString())) {
return ParameterizedTypeName.get((ClassName) source,
ClassName.get("java.lang", "String"),
ClassName.get("java.lang", "Object"));
}
return source;
}
protected MethodSpec buildProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata) { protected MethodSpec buildProxyMethod(AbstractAdapterMethodMetadata adapterMethodMetadata) {
CodeBlock targetCode = adapterMethodMetadata.isStatic() ? CodeBlock.of("return $T.$N($N);", CodeBlock targetCode = adapterMethodMetadata.isStatic() ? CodeBlock.of("return $T.$N($N);",
adapterMethodMetadata.getMapper(), adapterMethodMetadata.getMapperMethodName(), adapterMethodMetadata.getMapper(), adapterMethodMetadata.getMapperMethodName(),
"param") : proxyMethodTarget(adapterMethodMetadata); "param") : proxyMethodTarget(adapterMethodMetadata);
ParameterSpec parameterSpec = ParameterSpec.builder(adapterMethodMetadata.getSource(), "param").build(); ParameterSpec parameterSpec = ParameterSpec.builder(
wrapperTypeName(adapterMethodMetadata.getSource()), "param").build();
return MethodSpec.methodBuilder(adapterMethodMetadata.getMethodName()) return MethodSpec.methodBuilder(adapterMethodMetadata.getMethodName())
.addModifiers(Modifier.PUBLIC) .addModifiers(Modifier.PUBLIC)
.addParameter(parameterSpec) .addParameter(parameterSpec)

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeName;
import io.github.linpeilie.ComponentModelConstant;
import io.github.linpeilie.annotations.AutoEnumMapper; import io.github.linpeilie.annotations.AutoEnumMapper;
import io.github.linpeilie.annotations.AutoMapMapper; import io.github.linpeilie.annotations.AutoMapMapper;
import io.github.linpeilie.annotations.AutoMapper; import io.github.linpeilie.annotations.AutoMapper;
@ -18,6 +19,7 @@ import io.github.linpeilie.processor.generator.AutoEnumMapperGenerator;
import io.github.linpeilie.processor.generator.AutoMapperGenerator; import io.github.linpeilie.processor.generator.AutoMapperGenerator;
import io.github.linpeilie.processor.generator.DefaultAdapterMapperGenerator; import io.github.linpeilie.processor.generator.DefaultAdapterMapperGenerator;
import io.github.linpeilie.processor.generator.MapperConfigGenerator; 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.generator.SpringAdapterMapperGenerator;
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata; import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
import io.github.linpeilie.processor.metadata.AdapterEnumMethodMetadata; import io.github.linpeilie.processor.metadata.AdapterEnumMethodMetadata;
@ -71,6 +73,8 @@ public class AutoMapperProcessor extends AbstractProcessor {
private static final ClassName MAPPING_DEFAULT_TARGET = ClassName.get("io.github.linpeilie", "DefaultMapping"); private static final ClassName MAPPING_DEFAULT_TARGET = ClassName.get("io.github.linpeilie", "DefaultMapping");
protected static final String DEFAULT_COMPONENT_MODEL = "mapstruct.defaultComponentModel";
private final AutoMapperGenerator mapperGenerator; private final AutoMapperGenerator mapperGenerator;
private AbstractAdapterMapperGenerator adapterMapperGenerator; private AbstractAdapterMapperGenerator adapterMapperGenerator;
@ -133,9 +137,16 @@ public class AutoMapperProcessor extends AbstractProcessor {
refreshProperties(annotations, roundEnv); refreshProperties(annotations, roundEnv);
// 根据配置生成适配类生成器 // 根据配置生成适配类生成器
this.adapterMapperGenerator = AutoMapperProperties.getComponentModel() switch (AutoMapperProperties.getComponentModel()) {
.contentEquals( case MappingConstants.ComponentModel.SPRING:
MappingConstants.ComponentModel.SPRING) ? new SpringAdapterMapperGenerator() : new DefaultAdapterMapperGenerator(); this.adapterMapperGenerator = new SpringAdapterMapperGenerator();
break;
case ComponentModelConstant.SOLON:
this.adapterMapperGenerator = new SolonAdapterMapperGenerator();
break;
default:
this.adapterMapperGenerator = new DefaultAdapterMapperGenerator();
}
// AutoMapMapper // AutoMapMapper
annotations.stream() annotations.stream()
@ -301,7 +312,8 @@ public class AutoMapperProcessor extends AbstractProcessor {
AutoMapperProperties.setUnmappedSourcePolicy(mapperConfig.unmappedSourcePolicy()); AutoMapperProperties.setUnmappedSourcePolicy(mapperConfig.unmappedSourcePolicy());
AutoMapperProperties.setUnmappedTargetPolicy(mapperConfig.unmappedTargetPolicy()); AutoMapperProperties.setUnmappedTargetPolicy(mapperConfig.unmappedTargetPolicy());
AutoMapperProperties.setNullValueMappingStrategy(mapperConfig.nullValueMappingStrategy()); AutoMapperProperties.setNullValueMappingStrategy(mapperConfig.nullValueMappingStrategy());
AutoMapperProperties.setNullValuePropertyMappingStrategy(mapperConfig.nullValuePropertyMappingStrategy()); AutoMapperProperties.setNullValuePropertyMappingStrategy(
mapperConfig.nullValuePropertyMappingStrategy());
AutoMapperProperties.setBuildMethod(mapperConfig.builder().buildMethod()); AutoMapperProperties.setBuildMethod(mapperConfig.builder().buildMethod());
AutoMapperProperties.setDisableBuilder(mapperConfig.builder().disableBuilder()); AutoMapperProperties.setDisableBuilder(mapperConfig.builder().disableBuilder());
if (StrUtil.isNotEmpty(mapperConfig.adapterPackage())) { if (StrUtil.isNotEmpty(mapperConfig.adapterPackage())) {
@ -314,16 +326,20 @@ public class AutoMapperProcessor extends AbstractProcessor {
AutoMapperProperties.setMapAdapterClassName(mapperConfig.mapAdapterClassName()); AutoMapperProperties.setMapAdapterClassName(mapperConfig.mapAdapterClassName());
} }
}); });
// 构建参数
String componentModel = processingEnv.getOptions().get(DEFAULT_COMPONENT_MODEL);
AutoMapperProperties.setComponentModel(componentModel);
annotations.stream() annotations.stream()
.filter(this::isComponentModelConfigAnnotation) .filter(this::isComponentModelConfigAnnotation)
.findFirst() .findFirst()
.flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream().findFirst()) .flatMap(annotation -> roundEnv.getElementsAnnotatedWith(annotation).stream().findFirst())
.ifPresent(element -> { .ifPresent(element -> {
if (StrUtil.isEmpty(componentModel)) {
final ComponentModelConfig componentModelConfig = element.getAnnotation(ComponentModelConfig.class); final ComponentModelConfig componentModelConfig = element.getAnnotation(ComponentModelConfig.class);
String componentModel = StringUtils.isEmpty( String componentModelByAnnotation = componentModelConfig.componentModel();
componentModelConfig.componentModel()) ? "default" : componentModelConfig.componentModel(); AutoMapperProperties.setComponentModel(componentModelByAnnotation);
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "component model " + componentModel); }
AutoMapperProperties.setComponentModel(componentModel);
}); });
} }

View File

@ -0,0 +1,58 @@
package io.github.linpeilie.processor.generator;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.FieldSpec;
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 abstract AnnotationSpec componentAnnotation();
protected abstract List<AnnotationSpec> injectAnnotations();
@Override
protected TypeSpec createTypeSpec(final Collection<AbstractAdapterMethodMetadata> adapterMethods,
final String adapterClassName) {
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)));
adapterMethods.forEach(adapterMethod -> adapterBuilder
.addMethod(buildProxyMethod(adapterMethod)));
return adapterBuilder.build();
}
private FieldSpec buildMapperField(ClassName mapper) {
return FieldSpec.builder(mapper, firstWordToLower(mapper.simpleName()), Modifier.PRIVATE)
.addAnnotations(injectAnnotations())
.build();
}
private String firstWordToLower(String str) {
return str.substring(0, 1).toLowerCase() + str.substring(1);
}
@Override
protected CodeBlock proxyMethodTarget(AbstractAdapterMethodMetadata adapterMethodMetadata) {
return CodeBlock.builder()
.add("return $N.$N($N);", firstWordToLower(adapterMethodMetadata.getMapper().simpleName()),
adapterMethodMetadata.getMapperMethodName(),
"param")
.build();
}
}

View File

@ -0,0 +1,30 @@
package io.github.linpeilie.processor.generator;
import cn.hutool.core.collection.CollectionUtil;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
import java.util.Collection;
import java.util.List;
public class SolonAdapterMapperGenerator extends IocAdapterMapperGenerator {
private AnnotationSpec component() {
return AnnotationSpec.builder(ClassName.get("org.noear.solon.annotation", "Component"))
.build();
}
private AnnotationSpec inject() {
return AnnotationSpec.builder(ClassName.get("org.noear.solon.annotation", "Inject"))
.build();
}
@Override
protected AnnotationSpec componentAnnotation() {
return component();
}
@Override
protected List<AnnotationSpec> injectAnnotations() {
return CollectionUtil.newArrayList(inject());
}
}

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 com.squareup.javapoet.AnnotationSpec; import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.CodeBlock;
@ -10,63 +11,37 @@ import com.squareup.javapoet.TypeSpec;
import io.github.linpeilie.processor.AbstractAdapterMapperGenerator; import io.github.linpeilie.processor.AbstractAdapterMapperGenerator;
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata; import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
public class SpringAdapterMapperGenerator extends AbstractAdapterMapperGenerator { public class SpringAdapterMapperGenerator extends IocAdapterMapperGenerator {
@Override private AnnotationSpec component() {
protected TypeSpec createTypeSpec(Collection<AbstractAdapterMethodMetadata> adapterMethods, String adapterClassName) { return AnnotationSpec
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(ClassName.get(adapterPackage(), adapterClassName)) .builder(ClassName.get("org.springframework.stereotype", "Component"))
.addModifiers(Modifier.PUBLIC) .build();
.addAnnotation(ClassName.get("org.springframework.stereotype", "Component"));
adapterMethods.stream()
.filter(adapterMethodMetadata -> !adapterMethodMetadata.isStatic())
.map(AbstractAdapterMethodMetadata::getMapper)
.distinct()
.forEach(mapper -> adapterBuilder.addField(buildMapperField(mapper))
.addMethod(buildMapperSetterMethod(mapper)));
adapterMethods.forEach(adapterMethod -> adapterBuilder
.addMethod(buildProxyMethod(adapterMethod)));
return adapterBuilder.build();
} }
private FieldSpec buildMapperField(ClassName mapper) { private AnnotationSpec autowired() {
return FieldSpec.builder(mapper, firstWordToLower(mapper.simpleName()), Modifier.PRIVATE).build(); return AnnotationSpec
.builder(ClassName.get("org.springframework.beans", "Autowired"))
.build();
} }
private String firstWordToLower(String str) { private AnnotationSpec lazy() {
return str.substring(0, 1).toLowerCase() + str.substring(1); return AnnotationSpec
.builder(ClassName.get("org.springframework.context.annotation", "Lazy"))
.build();
} }
@Override @Override
protected CodeBlock proxyMethodTarget(AbstractAdapterMethodMetadata adapterMethodMetadata) { protected AnnotationSpec componentAnnotation() {
return CodeBlock.builder() return component();
.add("return $N.$N($N);", firstWordToLower(adapterMethodMetadata.getMapper().simpleName()),
adapterMethodMetadata.getMapperMethodName(),
"param")
.build();
} }
private MethodSpec buildMapperSetterMethod(ClassName mapper) { @Override
ParameterSpec parameterSpec = buildMapperSetterParameter(mapper); protected List<AnnotationSpec> injectAnnotations() {
return MethodSpec.methodBuilder("set" + mapper.simpleName()) return CollectionUtil.newArrayList(autowired(), lazy());
.addModifiers(Modifier.PUBLIC)
.addParameter(parameterSpec)
.addAnnotation(
AnnotationSpec.builder(ClassName.get("org.springframework.beans.factory.annotation", "Autowired"))
.build())
.addStatement("this.$N = $N", buildMapperField(mapper), parameterSpec)
.build();
}
private ParameterSpec buildMapperSetterParameter(ClassName mapper) {
return ParameterSpec.builder(mapper, firstWordToLower(mapper.simpleName()))
.addAnnotation(
AnnotationSpec.builder(ClassName.get("org.springframework.context.annotation", "Lazy")).build())
.build();
} }
} }

View File

@ -0,0 +1,39 @@
package io.github.linpeilie.processor.solon;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import io.github.linpeilie.ComponentModelConstant;
import java.util.List;
import org.mapstruct.ap.internal.model.Annotation;
import org.mapstruct.ap.internal.model.Mapper;
import org.mapstruct.ap.internal.processor.AnnotationBasedComponentModelProcessor;
public class SolonComponentProcessor extends AnnotationBasedComponentModelProcessor {
@Override
protected String getComponentModelIdentifier() {
return ComponentModelConstant.SOLON;
}
@Override
protected List<Annotation> getTypeAnnotations(final Mapper mapper) {
return CollectionUtil.newArrayList(component());
}
private Annotation component() {
return new Annotation(getTypeFactory().getType("org.noear.solon.annotation.Component"));
}
private Annotation inject() {
return new Annotation(getTypeFactory().getType("org.noear.solon.annotation.Inject"));
}
@Override
protected List<Annotation> getMapperReferenceAnnotations() {
return CollectionUtil.newArrayList(inject());
}
@Override
protected boolean requiresGenerationOfDecoratorClass() {
return true;
}
}

View File

@ -0,0 +1,14 @@
# Copyright MapStruct Authors.
#
# Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
org.mapstruct.ap.internal.processor.CdiComponentProcessor
org.mapstruct.ap.internal.processor.JakartaCdiComponentProcessor
org.mapstruct.ap.internal.processor.Jsr330ComponentProcessor
org.mapstruct.ap.internal.processor.JakartaComponentProcessor
org.mapstruct.ap.internal.processor.MapperCreationProcessor
org.mapstruct.ap.internal.processor.MapperRenderingProcessor
org.mapstruct.ap.internal.processor.MethodRetrievalProcessor
org.mapstruct.ap.internal.processor.SpringComponentProcessor
org.mapstruct.ap.internal.processor.MapperServiceProcessor
io.github.linpeilie.processor.solon.SolonComponentProcessor

View File

@ -0,0 +1,7 @@
package io.github.linpeilie;
public interface ComponentModelConstant {
String SOLON = "solon";
}

View File

@ -17,7 +17,7 @@
</modules> </modules>
<properties> <properties>
<mapstruct-plus.version>1.2.4</mapstruct-plus.version> <mapstruct-plus.version>1.2.5</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>