解决 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
<properties>
<mapstruct-plus.version>1.2.4</mapstruct-plus.version>
<mapstruct-plus.version>1.2.5</mapstruct-plus.version>
</properties>
<dependencies>
<dependency>

View File

@ -52,14 +52,14 @@ copyright: false
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>1.2.4</version>
<version>1.2.5</version>
</dependency>
```
- gradle
```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>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>
</properties>

View File

@ -1,9 +1,12 @@
package io.github.linpeilie.processor;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import io.github.linpeilie.processor.metadata.AbstractAdapterMethodMetadata;
import java.io.IOException;
@ -39,11 +42,24 @@ public abstract class AbstractAdapterMapperGenerator {
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) {
CodeBlock targetCode = adapterMethodMetadata.isStatic() ? CodeBlock.of("return $T.$N($N);",
adapterMethodMetadata.getMapper(), adapterMethodMetadata.getMapperMethodName(),
"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())
.addModifiers(Modifier.PUBLIC)
.addParameter(parameterSpec)

View File

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

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;
import cn.hutool.core.collection.CollectionUtil;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
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.metadata.AbstractAdapterMethodMetadata;
import java.util.Collection;
import java.util.List;
import javax.lang.model.element.Modifier;
public class SpringAdapterMapperGenerator extends AbstractAdapterMapperGenerator {
public class SpringAdapterMapperGenerator extends IocAdapterMapperGenerator {
@Override
protected TypeSpec createTypeSpec(Collection<AbstractAdapterMethodMetadata> adapterMethods, String adapterClassName) {
TypeSpec.Builder adapterBuilder = TypeSpec.classBuilder(ClassName.get(adapterPackage(), adapterClassName))
.addModifiers(Modifier.PUBLIC)
.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 AnnotationSpec component() {
return AnnotationSpec
.builder(ClassName.get("org.springframework.stereotype", "Component"))
.build();
}
private FieldSpec buildMapperField(ClassName mapper) {
return FieldSpec.builder(mapper, firstWordToLower(mapper.simpleName()), Modifier.PRIVATE).build();
private AnnotationSpec autowired() {
return AnnotationSpec
.builder(ClassName.get("org.springframework.beans", "Autowired"))
.build();
}
private String firstWordToLower(String str) {
return str.substring(0, 1).toLowerCase() + str.substring(1);
private AnnotationSpec lazy() {
return AnnotationSpec
.builder(ClassName.get("org.springframework.context.annotation", "Lazy"))
.build();
}
@Override
protected CodeBlock proxyMethodTarget(AbstractAdapterMethodMetadata adapterMethodMetadata) {
return CodeBlock.builder()
.add("return $N.$N($N);", firstWordToLower(adapterMethodMetadata.getMapper().simpleName()),
adapterMethodMetadata.getMapperMethodName(),
"param")
.build();
protected AnnotationSpec componentAnnotation() {
return component();
}
private MethodSpec buildMapperSetterMethod(ClassName mapper) {
ParameterSpec parameterSpec = buildMapperSetterParameter(mapper);
return MethodSpec.methodBuilder("set" + mapper.simpleName())
.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();
@Override
protected List<AnnotationSpec> injectAnnotations() {
return CollectionUtil.newArrayList(autowired(), lazy());
}
}

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>
<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.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>