Skip to content

Commit d54d070

Browse files
committed
#10 allow custom implementation names
1 parent 33ad138 commit d54d070

5 files changed

Lines changed: 129 additions & 3 deletions

File tree

api/src/main/java/org/mapstruct/tools/gem/GemDefinition.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,14 @@
2525
* @return the annotation for which a Gem should be generated
2626
*/
2727
Class<?> value();
28+
29+
/**
30+
* Specifies the name of the implementation class. The {@code <CLASS_NAME>} will be replaced by the
31+
* interface/abstract class name.
32+
* <p>
33+
* Defaults to postfixing the name with {@code Gem}: {@code <CLASS_NAME>Impl}
34+
*
35+
* @return The implementation name.
36+
*/
37+
String implementationName() default "<CLASS_NAME>";
2838
}

processor/src/main/java/org/mapstruct/tools/gem/processor/GemInfo.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ public class GemInfo {
2626
private final List<GemValueInfo> gemValueInfos;
2727
private final Element[] originatingElements;
2828

29-
public GemInfo(String gemPackageName, String annotationName, String annotationFqn,
29+
public GemInfo(String gemPackageName, String gemName, String annotationName, String annotationFqn,
3030
List<GemValueInfo> gemValueInfos, Element... originatingElements) {
3131
this.gemPackageName = gemPackageName;
32-
this.gemName = annotationName + "Gem";
32+
this.gemName = gemName;
3333
this.annotationName = annotationName;
3434
this.annotationFqn = annotationFqn;
3535
this.gemValueInfos = gemValueInfos;

processor/src/main/java/org/mapstruct/tools/gem/processor/GemProcessor.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ private void addGemInfo(AnnotationMirror gemDefinitionMirror, Element definingEl
9191

9292
// create gem info
9393
DeclaredType gemDeclaredType = util.getAnnotationValue( gemDefinitionMirror, "value", DeclaredType.class );
94+
String annotationName = util.getSimpleName( gemDeclaredType );
95+
String gemName = getGemName( gemDefinitionMirror, annotationName );
9496
PackageElement pkg = processingEnv.getElementUtils().getPackageOf( definingElement );
95-
String gemName = util.getSimpleName( gemDeclaredType );
9697
String gemFqn = util.getFullyQualifiedName( gemDeclaredType );
9798
String gemPackage = pkg.getQualifiedName().toString();
9899

@@ -104,6 +105,7 @@ private void addGemInfo(AnnotationMirror gemDefinitionMirror, Element definingEl
104105
GemInfo gemInfo = new GemInfo(
105106
gemPackage,
106107
gemName,
108+
annotationName,
107109
gemFqn,
108110
gemValueInfos,
109111
definingElement,
@@ -112,6 +114,14 @@ private void addGemInfo(AnnotationMirror gemDefinitionMirror, Element definingEl
112114
gemInfos.add( gemInfo );
113115
}
114116

117+
private String getGemName(AnnotationMirror gemDefinitionMirror, String annotationName) {
118+
String implementationName = util.getAnnotationValue( gemDefinitionMirror, "implementationName", String.class );
119+
if ( implementationName != null ) {
120+
return implementationName.replace( "<CLASS_NAME>", annotationName );
121+
}
122+
return annotationName + "Gem";
123+
}
124+
115125
private void postProcessGemInfo() {
116126
for ( GemInfo gemInfo : gemInfos ) {
117127
for ( GemValueInfo gemValueInfo : gemInfo.getGemValueInfos() ) {

processor/src/test/java/org/mapstruct/tools/gem/processor/ProcessorTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ private void compile(Processor processor, JavaFileObject... compilationUnits) th
7474

7575

7676
assertGeneratedFileContent( "BuilderGem", generatedDir );
77+
assertGeneratedFileContent( "CustomBuilderGem", generatedDir );
7778
assertGeneratedFileContent( "SomeAnnotationGem", generatedDir );
7879
assertGeneratedFileContent( "SomeAnnotationsGem", generatedDir );
7980
assertGeneratedFileContent( "SomeArrayAnnotationGem", generatedDir );
@@ -129,6 +130,7 @@ private String getSource() {
129130
"@GemDefinition(value = SomeAnnotations.class)\n" +
130131
"@GemDefinition(value = SomeArrayAnnotation.class)\n" +
131132
"@GemDefinition(value = Builder.class)\n" +
133+
"@GemDefinition(value = Builder.class, implementationName = \"Custom<CLASS_NAME>Gem\")\n" +
132134
"public class GemGenerator {\n" +
133135
"}";
134136
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package org.mapstruct.tools.gem.processor;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import javax.lang.model.element.AnnotationMirror;
9+
import javax.lang.model.element.AnnotationValue;
10+
import javax.lang.model.element.Element;
11+
import javax.lang.model.element.ElementKind;
12+
import javax.lang.model.element.ExecutableElement;
13+
import javax.lang.model.element.TypeElement;
14+
import javax.lang.model.element.VariableElement;
15+
import javax.lang.model.type.TypeMirror;
16+
import javax.lang.model.util.AbstractAnnotationValueVisitor8;
17+
import javax.lang.model.util.ElementFilter;
18+
import org.mapstruct.tools.gem.Gem;
19+
import org.mapstruct.tools.gem.GemValue;
20+
21+
22+
public class CustomBuilderGem implements Gem {
23+
24+
private final AnnotationMirror mirror;
25+
26+
private CustomBuilderGem( BuilderImpl builder ) {
27+
mirror = builder.mirror;
28+
}
29+
30+
@Override
31+
public AnnotationMirror mirror( ) {
32+
return mirror;
33+
}
34+
35+
@Override
36+
public boolean isValid( ) {
37+
return true;
38+
}
39+
40+
public static CustomBuilderGem instanceOn(Element element) {
41+
return build( element, new BuilderImpl() );
42+
}
43+
44+
public static CustomBuilderGem instanceOn(AnnotationMirror mirror ) {
45+
return build( mirror, new BuilderImpl() );
46+
}
47+
48+
public static <T> T build(Element element, Builder_<T> builder) {
49+
AnnotationMirror mirror = element.getAnnotationMirrors().stream()
50+
.filter( a -> "org.mapstruct.tools.gem.test.Builder".contentEquals( ( ( TypeElement )a.getAnnotationType().asElement() ).getQualifiedName() ) )
51+
.findAny()
52+
.orElse( null );
53+
return build( mirror, builder );
54+
}
55+
56+
public static <T> T build(AnnotationMirror mirror, Builder_<T> builder ) {
57+
58+
// return fast
59+
if ( mirror == null || builder == null ) {
60+
return null;
61+
}
62+
builder.setMirror( mirror );
63+
return builder.build();
64+
}
65+
66+
/**
67+
* A builder that can be implemented by the user to define custom logic e.g. in the
68+
* build method, prior to creating the annotation gem.
69+
*/
70+
public interface Builder_<T> {
71+
72+
/**
73+
* Sets the annotation mirror
74+
*
75+
* @param mirror the mirror which this gem represents
76+
*
77+
* @return the {@link Builder_} for this gem, representing {@link CustomBuilderGem}
78+
*/
79+
Builder_<T> setMirror( AnnotationMirror mirror );
80+
81+
/**
82+
* The build method can be overriden in a custom custom implementation, which allows
83+
* the user to define his own custom validation on the annotation.
84+
*
85+
* @return the representation of the annotation
86+
*/
87+
T build();
88+
}
89+
90+
private static class BuilderImpl implements Builder_<CustomBuilderGem> {
91+
92+
private AnnotationMirror mirror;
93+
94+
public Builder_<CustomBuilderGem> setMirror( AnnotationMirror mirror ) {
95+
this.mirror = mirror;
96+
return this;
97+
}
98+
99+
public CustomBuilderGem build() {
100+
return new CustomBuilderGem( this );
101+
}
102+
}
103+
104+
}

0 commit comments

Comments
 (0)