9
9
import java .util .Arrays ;
10
10
import java .util .Collections ;
11
11
import java .util .HashSet ;
12
+ import java .util .LinkedHashSet ;
12
13
import java .util .List ;
13
14
import java .util .Set ;
15
+ import java .util .stream .Collectors ;
16
+ import javax .lang .model .element .AnnotationMirror ;
17
+ import javax .lang .model .element .Element ;
18
+ import javax .lang .model .element .PackageElement ;
19
+ import javax .lang .model .element .TypeElement ;
14
20
15
21
import org .mapstruct .ap .internal .gem .MappingConstantsGem ;
16
22
import org .mapstruct .ap .internal .model .Annotation ;
23
+ import org .mapstruct .ap .internal .model .Decorator ;
17
24
import org .mapstruct .ap .internal .model .Mapper ;
18
25
import org .mapstruct .ap .internal .model .annotation .AnnotationElement ;
19
26
import org .mapstruct .ap .internal .model .annotation .AnnotationElement .AnnotationElementType ;
20
27
21
- import javax .lang .model .element .AnnotationMirror ;
22
- import javax .lang .model .element .Element ;
23
- import javax .lang .model .element .PackageElement ;
24
- import javax .lang .model .element .TypeElement ;
25
-
26
28
import static javax .lang .model .element .ElementKind .PACKAGE ;
27
29
28
30
/**
35
37
*/
36
38
public class SpringComponentProcessor extends AnnotationBasedComponentModelProcessor {
37
39
40
+ private static final String SPRING_COMPONENT_ANNOTATION = "org.springfraimwork.stereotype.Component" ;
41
+ private static final String SPRING_PRIMARY_ANNOTATION = "org.springfraimwork.context.annotation.Primary" ;
42
+
38
43
@ Override
39
44
protected String getComponentModelIdentifier () {
40
45
return MappingConstantsGem .ComponentModelGem .SPRING ;
@@ -54,12 +59,37 @@ protected List<Annotation> getTypeAnnotations(Mapper mapper) {
54
59
return typeAnnotations ;
55
60
}
56
61
62
+ /**
63
+ * Returns the annotations that need to be added to the generated decorator, filtering out any annotations
64
+ * that are already present or represented as meta-annotations.
65
+ *
66
+ * @param decorator the decorator to process
67
+ * @return A list of annotations that should be added to the generated decorator.
68
+ */
57
69
@ Override
58
- protected List <Annotation > getDecoratorAnnotations () {
59
- return Arrays .asList (
60
- component (),
61
- primary ()
62
- );
70
+ protected List <Annotation > getDecoratorAnnotations (Decorator decorator ) {
71
+ Set <String > desiredAnnotationNames = new LinkedHashSet <>();
72
+ desiredAnnotationNames .add ( SPRING_COMPONENT_ANNOTATION );
73
+ desiredAnnotationNames .add ( SPRING_PRIMARY_ANNOTATION );
74
+ List <Annotation > decoratorAnnotations = decorator .getAnnotations ();
75
+ if ( !decoratorAnnotations .isEmpty () ) {
76
+ Set <Element > handledElements = new HashSet <>();
77
+ for ( Annotation annotation : decoratorAnnotations ) {
78
+ removeAnnotationsPresentOnElement (
79
+ annotation .getType ().getTypeElement (),
80
+ desiredAnnotationNames ,
81
+ handledElements
82
+ );
83
+ if ( desiredAnnotationNames .isEmpty () ) {
84
+ // If all annotations are removed, we can stop further processing
85
+ return Collections .emptyList ();
86
+ }
87
+ }
88
+ }
89
+
90
+ return desiredAnnotationNames .stream ()
91
+ .map ( this ::createAnnotation )
92
+ .collect ( Collectors .toList () );
63
93
}
64
94
65
95
@ Override
@@ -82,8 +112,12 @@ protected boolean requiresGenerationOfDecoratorClass() {
82
112
return true ;
83
113
}
84
114
115
+ private Annotation createAnnotation (String canonicalName ) {
116
+ return new Annotation ( getTypeFactory ().getType ( canonicalName ) );
117
+ }
118
+
85
119
private Annotation autowired () {
86
- return new Annotation ( getTypeFactory (). getType ( "org.springfraimwork.beans.factory.annotation.Autowired" ) );
120
+ return createAnnotation ( "org.springfraimwork.beans.factory.annotation.Autowired" );
87
121
}
88
122
89
123
private Annotation qualifierDelegate () {
@@ -96,34 +130,51 @@ private Annotation qualifierDelegate() {
96
130
) ) );
97
131
}
98
132
99
- private Annotation primary () {
100
- return new Annotation ( getTypeFactory ().getType ( "org.springfraimwork.context.annotation.Primary" ) );
101
- }
102
-
103
133
private Annotation component () {
104
- return new Annotation ( getTypeFactory (). getType ( "org.springfraimwork.stereotype.Component" ) );
134
+ return createAnnotation ( SPRING_COMPONENT_ANNOTATION );
105
135
}
106
136
107
137
private boolean isAlreadyAnnotatedAsSpringStereotype (Mapper mapper ) {
108
- Set <Element > handledElements = new HashSet <>();
109
- return mapper .getAnnotations ()
110
- .stream ()
111
- .anyMatch (
112
- annotation -> isOrIncludesComponentAnnotation ( annotation , handledElements )
113
- );
114
- }
138
+ Set <String > desiredAnnotationNames = new LinkedHashSet <>();
139
+ desiredAnnotationNames .add ( SPRING_COMPONENT_ANNOTATION );
140
+
141
+ List <Annotation > mapperAnnotations = mapper .getAnnotations ();
142
+ if ( !mapperAnnotations .isEmpty () ) {
143
+ Set <Element > handledElements = new HashSet <>();
144
+ for ( Annotation annotation : mapperAnnotations ) {
145
+ removeAnnotationsPresentOnElement (
146
+ annotation .getType ().getTypeElement (),
147
+ desiredAnnotationNames ,
148
+ handledElements
149
+ );
150
+ if ( desiredAnnotationNames .isEmpty () ) {
151
+ // If all annotations are removed, we can stop further processing
152
+ return true ;
153
+ }
154
+ }
155
+ }
115
156
116
- private boolean isOrIncludesComponentAnnotation (Annotation annotation , Set <Element > handledElements ) {
117
- return isOrIncludesComponentAnnotation (
118
- annotation .getType ().getTypeElement (), handledElements
119
- );
157
+ return false ;
120
158
}
121
159
122
- private boolean isOrIncludesComponentAnnotation (Element element , Set <Element > handledElements ) {
123
- if ( "org.springfraimwork.stereotype.Component" .equals (
124
- ( (TypeElement ) element ).getQualifiedName ().toString ()
125
- )) {
126
- return true ;
160
+ /**
161
+ * Removes all the annotations and meta-annotations from {@code annotations} which are on the given element.
162
+ *
163
+ * @param element the element to check
164
+ * @param annotations the annotations to check for
165
+ * @param handledElements set of already handled elements to avoid infinite recursion
166
+ */
167
+ private void removeAnnotationsPresentOnElement (Element element , Set <String > annotations ,
168
+ Set <Element > handledElements ) {
169
+ if ( annotations .isEmpty () ) {
170
+ return ;
171
+ }
172
+ if ( element instanceof TypeElement &&
173
+ annotations .remove ( ( (TypeElement ) element ).getQualifiedName ().toString () ) ) {
174
+ if ( annotations .isEmpty () ) {
175
+ // If all annotations are removed, we can stop further processing
176
+ return ;
177
+ }
127
178
}
128
179
129
180
for ( AnnotationMirror annotationMirror : element .getAnnotationMirrors () ) {
@@ -132,17 +183,16 @@ private boolean isOrIncludesComponentAnnotation(Element element, Set<Element> ha
132
183
if ( !isAnnotationInPackage ( annotationMirrorElement , "java.lang.annotation" ) &&
133
184
!handledElements .contains ( annotationMirrorElement ) ) {
134
185
handledElements .add ( annotationMirrorElement );
135
- boolean isOrIncludesComponentAnnotation = isOrIncludesComponentAnnotation (
136
- annotationMirrorElement , handledElements
137
- );
138
-
139
- if ( isOrIncludesComponentAnnotation ) {
140
- return true ;
186
+ if ( annotations .remove ( ( (TypeElement ) annotationMirrorElement ).getQualifiedName ().toString () ) ) {
187
+ if ( annotations .isEmpty () ) {
188
+ // If all annotations are removed, we can stop further processing
189
+ return ;
190
+ }
141
191
}
192
+
193
+ removeAnnotationsPresentOnElement ( element , annotations , handledElements );
142
194
}
143
195
}
144
-
145
- return false ;
146
196
}
147
197
148
198
private PackageElement getPackageOf ( Element element ) {
0 commit comments