Skip to content

Commit 022d89c

Browse files
committed
WIP: Set up test case
1 parent 3e7b83f commit 022d89c

File tree

5 files changed

+117
-68
lines changed

5 files changed

+117
-68
lines changed

build.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ subprojects {
3333
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.1'
3434
}
3535

36-
compileJava {
37-
sourceCompatibility '1.8'
38-
targetCompatibility '1.8'
36+
java {
37+
toolchain {
38+
languageVersion.set(JavaLanguageVersion.of(8))
39+
}
3940
}
4041

4142
test {
@@ -58,6 +59,6 @@ subprojects {
5859
}
5960

6061
wrapper {
61-
gradleVersion = '6.7.1'
62+
gradleVersion = '6.8'
6263
}
6364

extensions/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ apply plugin: "signing"
33

44
dependencies {
55
implementation project(":annotations")
6-
implementation 'com.squareup:javapoet:1.12.1'
6+
implementation 'com.squareup:javapoet:1.13.0'
77
implementation 'org.apache.commons:commons-lang3:3.10'
88

99
testImplementation 'org.mapstruct:mapstruct:1.4.0.Final'
10-
testImplementation 'org.assertj:assertj-core:3.15.0'
10+
testImplementation 'org.assertj:assertj-core:3.18.1'
1111
testImplementation 'commons-io:commons-io:2.6'
12-
testImplementation 'com.google.guava:guava:28.2-jre'
13-
testImplementation 'org.mockito:mockito-junit-jupiter:3.3.3'
12+
testImplementation 'com.google.guava:guava:30.1-jre'
13+
testImplementation 'org.mockito:mockito-junit-jupiter:3.7.0'
1414
testImplementation 'org.springframework:spring-core:5.0.0.RELEASE'
1515
}
1616

extensions/src/main/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessor.java

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,11 @@
11
package org.mapstruct.extensions.spring.converter;
22

3-
import static java.util.stream.Collectors.toList;
4-
import static javax.lang.model.element.ElementKind.METHOD;
5-
import static javax.lang.model.element.Modifier.PUBLIC;
6-
import static javax.lang.model.type.TypeKind.DECLARED;
7-
import static javax.tools.Diagnostic.Kind.ERROR;
8-
93
import com.squareup.javapoet.ClassName;
10-
import java.io.IOException;
11-
import java.io.Writer;
12-
import java.time.Clock;
13-
import java.util.List;
14-
import java.util.Objects;
15-
import java.util.Optional;
16-
import java.util.Set;
17-
import java.util.concurrent.atomic.AtomicReference;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.apache.commons.lang3.tuple.MutablePair;
6+
import org.apache.commons.lang3.tuple.Pair;
7+
import org.mapstruct.extensions.spring.SpringMapperConfig;
8+
189
import javax.annotation.processing.AbstractProcessor;
1910
import javax.annotation.processing.RoundEnvironment;
2011
import javax.annotation.processing.SupportedAnnotationTypes;
@@ -25,10 +16,16 @@
2516
import javax.lang.model.type.DeclaredType;
2617
import javax.lang.model.type.TypeMirror;
2718
import javax.lang.model.util.Types;
28-
import org.apache.commons.lang3.StringUtils;
29-
import org.apache.commons.lang3.tuple.MutablePair;
30-
import org.apache.commons.lang3.tuple.Pair;
31-
import org.mapstruct.extensions.spring.SpringMapperConfig;
19+
import java.io.IOException;
20+
import java.io.Writer;
21+
import java.time.Clock;
22+
import java.util.*;
23+
24+
import static java.util.stream.Collectors.toList;
25+
import static javax.lang.model.element.ElementKind.METHOD;
26+
import static javax.lang.model.element.Modifier.PUBLIC;
27+
import static javax.lang.model.type.TypeKind.DECLARED;
28+
import static javax.tools.Diagnostic.Kind.ERROR;
3229

3330
@SupportedAnnotationTypes({
3431
ConverterMapperProcessor.MAPPER,
@@ -38,7 +35,8 @@ public class ConverterMapperProcessor extends AbstractProcessor {
3835
protected static final String MAPPER = "org.mapstruct.Mapper";
3936
protected static final String SPRING_MAPPER_CONFIG =
4037
"org.mapstruct.extensions.spring.SpringMapperConfig";
41-
protected static final String SPRING_CONVERTER_FULL_NAME = "org.springframework.core.convert.converter.Converter";
38+
protected static final String SPRING_CONVERTER_FULL_NAME =
39+
"org.springframework.core.convert.converter.Converter";
4240

4341
private final ConversionServiceAdapterGenerator adapterGenerator;
4442

@@ -66,22 +64,26 @@ public boolean process(
6664
ClassName.get(adapterPackageAndClass.getLeft(), adapterPackageAndClass.getRight()));
6765
descriptor.setConversionServiceBeanName(getConversionServiceName(annotations, roundEnv));
6866
annotations.stream()
69-
.filter(annotation -> MAPPER.contentEquals(annotation.getQualifiedName()))
67+
.filter(this::isMapperAnnotation)
7068
.forEach(
7169
annotation ->
7270
processMapperAnnotation(roundEnv, descriptor, adapterPackageAndClass, annotation));
7371
return false;
7472
}
7573

74+
private boolean isMapperAnnotation(TypeElement annotation) {
75+
return MAPPER.contentEquals(annotation.getQualifiedName());
76+
}
77+
7678
private void processMapperAnnotation(
7779
final RoundEnvironment roundEnv,
7880
final ConversionServiceAdapterDescriptor descriptor,
7981
final Pair<String, String> adapterPackageAndClass,
8082
final TypeElement annotation) {
8183
final List<Pair<ClassName, ClassName>> fromToMappings =
8284
roundEnv.getElementsAnnotatedWith(annotation).stream()
83-
.filter(mapper -> mapper.asType().getKind() == DECLARED)
84-
.filter(mapper -> getConverterSupertype(mapper).isPresent())
85+
.filter(this::isKindDeclared)
86+
.filter(this::hasConverterSupertype)
8587
.map(this::toConvertMethod)
8688
.filter(Objects::nonNull)
8789
.map(ExecutableElement.class::cast)
@@ -91,14 +93,22 @@ private void processMapperAnnotation(
9193
writeAdapterClassFile(descriptor, adapterPackageAndClass);
9294
}
9395

96+
private boolean hasConverterSupertype(Element mapper) {
97+
return getConverterSupertype(mapper).isPresent();
98+
}
99+
100+
private boolean isKindDeclared(Element mapper) {
101+
return mapper.asType().getKind() == DECLARED;
102+
}
103+
94104
private Pair<ClassName, ClassName> toFromToMapping(final ExecutableElement convert) {
95105
return Pair.of(
96106
(ClassName)
97107
convert.getParameters().stream()
98108
.map(Element::asType)
99109
.map(ClassName::get)
100110
.findFirst()
101-
.get(),
111+
.orElseThrow(NoSuchElementException::new),
102112
(ClassName) ClassName.get(convert.getReturnType()));
103113
}
104114

@@ -169,20 +179,23 @@ private void updateFromDeclaration(
169179
}
170180

171181
private String getConversionServiceName(
172-
final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
173-
AtomicReference<String> beanName = new AtomicReference<>();
174-
for (final TypeElement annotation : annotations) {
175-
if (SPRING_MAPPER_CONFIG.contentEquals(annotation.getQualifiedName())) {
176-
roundEnv
177-
.getElementsAnnotatedWith(annotation)
178-
.stream().findFirst()
179-
.ifPresent(element -> {
180-
final SpringMapperConfig springMapperConfig = element.getAnnotation(SpringMapperConfig.class);
181-
beanName.set(springMapperConfig.conversionServiceBeanName());
182-
});
183-
}
184-
}
185-
return beanName.get();
182+
final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
183+
return annotations.stream()
184+
.filter(annotation -> SPRING_MAPPER_CONFIG.contentEquals(annotation.getQualifiedName()))
185+
.findFirst()
186+
.flatMap(annotation -> findFirstElementAnnotatedWith(roundEnv, annotation))
187+
.map(this::toSpringMapperConfig)
188+
.map(SpringMapperConfig::conversionServiceBeanName)
189+
.orElse(null);
190+
}
191+
192+
private Optional<? extends Element> findFirstElementAnnotatedWith(
193+
final RoundEnvironment roundEnv, final TypeElement annotation) {
194+
return roundEnv.getElementsAnnotatedWith(annotation).stream().findFirst();
195+
}
196+
197+
private SpringMapperConfig toSpringMapperConfig(final Element element) {
198+
return element.getAnnotation(SpringMapperConfig.class);
186199
}
187200

188201
private Optional<? extends TypeMirror> getConverterSupertype(final Element mapper) {

extensions/src/test/java/org/mapstruct/extensions/spring/converter/ConverterMapperProcessorTest.java

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ static void setupCommonSourceFiles() {
7373
.skipJavaLangImports(true)
7474
.build()
7575
.toJavaFileObject(),
76+
JavaFile.builder(PACKAGE_NAME, buildModelClassTypeSpec("Wheel"))
77+
.skipJavaLangImports(true)
78+
.build()
79+
.toJavaFileObject(),
80+
JavaFile.builder(PACKAGE_NAME, buildModelClassTypeSpec("WheelDto"))
81+
.skipJavaLangImports(true)
82+
.build()
83+
.toJavaFileObject(),
7684
JavaFile.builder("javax.annotation", buildGeneratedAnnotationTypeSpec())
7785
.skipJavaLangImports(true)
7886
.build()
@@ -84,18 +92,17 @@ static void setupCommonSourceFiles() {
8492
.build()
8593
.toJavaFileObject(),
8694
JavaFile.builder(
87-
"org.springframework.beans.factory.annotation",
88-
buildAnnotationWithValueTypeSpec("Qualifier"))
89-
.skipJavaLangImports(true)
90-
.build()
91-
.toJavaFileObject(),
95+
"org.springframework.beans.factory.annotation",
96+
buildAnnotationWithValueTypeSpec("Qualifier"))
97+
.skipJavaLangImports(true)
98+
.build()
99+
.toJavaFileObject(),
92100
JavaFile.builder(
93101
"org.springframework.stereotype", buildSimpleAnnotationTypeSpec("Component"))
94102
.skipJavaLangImports(true)
95103
.build()
96104
.toJavaFileObject(),
97-
JavaFile.builder(
98-
PACKAGE_NAME, buildConfigClass("MyMappingConfig"))
105+
JavaFile.builder(PACKAGE_NAME, buildConfigClass("MyMappingConfig"))
99106
.skipJavaLangImports(true)
100107
.build()
101108
.toJavaFileObject());
@@ -106,15 +113,14 @@ private static TypeSpec buildSimpleAnnotationTypeSpec(final String anotationName
106113
}
107114

108115
private static TypeSpec buildAnnotationWithValueTypeSpec(final String anotationName) {
109-
return TypeSpec
110-
.annotationBuilder(anotationName)
111-
.addMethod(
112-
MethodSpec.methodBuilder("value")
113-
.returns(String.class)
114-
.addModifiers(PUBLIC, ABSTRACT)
115-
.build())
116-
.addModifiers(PUBLIC)
117-
.build();
116+
return TypeSpec.annotationBuilder(anotationName)
117+
.addMethod(
118+
MethodSpec.methodBuilder("value")
119+
.returns(String.class)
120+
.addModifiers(PUBLIC, ABSTRACT)
121+
.build())
122+
.addModifiers(PUBLIC)
123+
.build();
118124
}
119125

120126
private static TypeSpec buildGeneratedAnnotationTypeSpec() {
@@ -136,7 +142,7 @@ private static TypeSpec buildGeneratedAnnotationTypeSpec() {
136142
private static TypeSpec buildModelClassTypeSpec(final String className) {
137143
final FieldSpec makeField = FieldSpec.builder(String.class, "make", PRIVATE).build();
138144
final ParameterSpec makeParameter = ParameterSpec.builder(String.class, "make", FINAL).build();
139-
return TypeSpec.classBuilder(className)
145+
return TypeSpec.classBuilder(className).addTypeVariable(TypeVariableName.get("W", ))
140146
.addModifiers(PUBLIC)
141147
.addField(makeField)
142148
.addMethod(
@@ -154,12 +160,13 @@ private static TypeSpec buildModelClassTypeSpec(final String className) {
154160

155161
private static TypeSpec buildConfigClass(final String className) {
156162
return TypeSpec.interfaceBuilder(className)
157-
.addModifiers(PUBLIC)
158-
.addAnnotation(AnnotationSpec.builder(
163+
.addModifiers(PUBLIC)
164+
.addAnnotation(
165+
AnnotationSpec.builder(
159166
ClassName.get("org.mapstruct.extensions.spring", "SpringMapperConfig"))
160-
.addMember("conversionServiceBeanName", "$S", "myConversionService")
161-
.build())
162-
.build();
167+
.addMember("conversionServiceBeanName", "$S", "myConversionService")
168+
.build())
169+
.build();
163170
}
164171

165172
@Test
@@ -175,6 +182,34 @@ void shouldCompileSimpleConverterMapper() throws IOException {
175182
then(compileResult).isTrue();
176183
}
177184

185+
@Test
186+
void shouldCompileConverterMapperWithGenericSourceType() throws IOException {
187+
// Given
188+
final JavaFile mapperFile =
189+
JavaFile.builder(PACKAGE_NAME, converterMapperWithGenericSourceTypeBuilder().build())
190+
.build();
191+
192+
// When
193+
final boolean compileResult = compile(mapperFile.toJavaFileObject());
194+
195+
// Then
196+
then(compileResult).isTrue();
197+
}
198+
199+
@Test
200+
void shouldCompileConverterMapperWithGenericTargetType() throws IOException {
201+
// Given
202+
final JavaFile mapperFile =
203+
JavaFile.builder(PACKAGE_NAME, converterMapperWithGenericTargetTypeBuilder().build())
204+
.build();
205+
206+
// When
207+
final boolean compileResult = compile(mapperFile.toJavaFileObject());
208+
209+
// Then
210+
then(compileResult).isTrue();
211+
}
212+
178213
private static TypeSpec.Builder converterMapperBuilder() {
179214
return plainCarMapperBuilder()
180215
.addSuperinterface(
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)