2
2
3
3
import static io .javaoperatorsdk .operator .ControllerUtils .CONTROLLERS_RESOURCE_PATH ;
4
4
import static io .javaoperatorsdk .operator .ControllerUtils .DONEABLES_RESOURCE_PATH ;
5
+ import static javax .lang .model .type .TypeKind .DECLARED ;
6
+ import static javax .lang .model .type .TypeKind .TYPEVAR ;
5
7
6
8
import com .google .auto .service .AutoService ;
7
- import com .squareup .javapoet .*;
9
+ import com .squareup .javapoet .ClassName ;
10
+ import com .squareup .javapoet .JavaFile ;
11
+ import com .squareup .javapoet .MethodSpec ;
12
+ import com .squareup .javapoet .ParameterizedTypeName ;
13
+ import com .squareup .javapoet .TypeName ;
14
+ import com .squareup .javapoet .TypeSpec ;
8
15
import io .fabric8 .kubernetes .api .builder .Function ;
9
16
import io .fabric8 .kubernetes .client .CustomResourceDoneable ;
10
17
import io .javaoperatorsdk .operator .api .ResourceController ;
14
21
import java .util .List ;
15
22
import java .util .Set ;
16
23
import java .util .stream .Collectors ;
17
- import javax .annotation .processing .*;
24
+ import java .util .stream .IntStream ;
25
+ import javax .annotation .processing .AbstractProcessor ;
26
+ import javax .annotation .processing .ProcessingEnvironment ;
27
+ import javax .annotation .processing .Processor ;
28
+ import javax .annotation .processing .RoundEnvironment ;
29
+ import javax .annotation .processing .SupportedAnnotationTypes ;
30
+ import javax .annotation .processing .SupportedSourceVersion ;
18
31
import javax .lang .model .SourceVersion ;
19
- import javax .lang .model .element .*;
32
+ import javax .lang .model .element .Element ;
33
+ import javax .lang .model .element .ElementKind ;
34
+ import javax .lang .model .element .Modifier ;
35
+ import javax .lang .model .element .PackageElement ;
36
+ import javax .lang .model .element .TypeElement ;
37
+ import javax .lang .model .element .TypeParameterElement ;
20
38
import javax .lang .model .type .DeclaredType ;
21
39
import javax .lang .model .type .TypeKind ;
22
40
import javax .lang .model .type .TypeMirror ;
41
+ import javax .lang .model .type .TypeVariable ;
23
42
import javax .tools .Diagnostic ;
24
43
import javax .tools .JavaFileObject ;
25
44
26
45
@ SupportedAnnotationTypes ("io.javaoperatorsdk.operator.api.Controller" )
27
46
@ SupportedSourceVersion (SourceVersion .RELEASE_8 )
28
47
@ AutoService (Processor .class )
29
48
public class ControllerAnnotationProcessor extends AbstractProcessor {
49
+
30
50
private AccumulativeMappingWriter controllersResourceWriter ;
31
51
private AccumulativeMappingWriter doneablesResourceWriter ;
32
52
private Set <String > generatedDoneableClassFiles = new HashSet <>();
@@ -63,10 +83,13 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
63
83
64
84
private void generateDoneableClass (TypeElement controllerClassSymbol ) {
65
85
try {
86
+ System .out .println (controllerClassSymbol .toString ());
66
87
final TypeMirror resourceType = findResourceType (controllerClassSymbol );
88
+ System .out .println ("the resource type is " + resourceType );
67
89
68
90
TypeElement customerResourceTypeElement =
69
91
processingEnv .getElementUtils ().getTypeElement (resourceType .toString ());
92
+ System .out .println ("the customerResourceTypeElement is " + customerResourceTypeElement );
70
93
71
94
final String doneableClassName = customerResourceTypeElement .getSimpleName () + "Doneable" ;
72
95
final String destinationClassFileName =
@@ -124,34 +147,24 @@ private void generateDoneableClass(TypeElement controllerClassSymbol) {
124
147
125
148
private TypeMirror findResourceType (TypeElement controllerClassSymbol ) throws Exception {
126
149
try {
127
- final DeclaredType controllerType =
128
- collectAllInterfaces (controllerClassSymbol ).stream ()
129
- .filter (i -> i .toString ().startsWith (ResourceController .class .getCanonicalName ()))
130
- .findFirst ()
131
- .orElseThrow (
132
- () ->
133
- new Exception (
134
- "ResourceController is not implemented by "
135
- + controllerClassSymbol .toString ()));
136
- return controllerType .getTypeArguments ().get (0 );
150
+ final var chain = findChain ((DeclaredType ) controllerClassSymbol .asType ());
151
+ final var customResourceClass = getCustomResourceClass (chain );
152
+ return customResourceClass ;
137
153
} catch (Exception e ) {
138
154
e .printStackTrace ();
139
155
return null ;
140
156
}
141
157
}
142
158
143
- private List <DeclaredType > collectAllInterfaces (TypeElement element ) {
159
+ private List <TypeMirror > collectAllInterfaces (TypeElement element ) {
144
160
try {
145
- List <DeclaredType > interfaces =
146
- new ArrayList <>(element .getInterfaces ())
147
- .stream ().map (t -> (DeclaredType ) t ).collect (Collectors .toList ());
161
+ List <TypeMirror > interfaces = new ArrayList <>(element .getInterfaces ());
162
+ interfaces .add (element .getSuperclass ());
148
163
TypeElement superclass = ((TypeElement ) ((DeclaredType ) element .getSuperclass ()).asElement ());
149
164
while (superclass .getSuperclass ().getKind () != TypeKind .NONE ) {
150
- interfaces .addAll (
151
- superclass .getInterfaces ().stream ()
152
- .map (t -> (DeclaredType ) t )
153
- .collect (Collectors .toList ()));
165
+ interfaces .addAll (superclass .getInterfaces ());
154
166
superclass = ((TypeElement ) ((DeclaredType ) superclass .getSuperclass ()).asElement ());
167
+ interfaces .add (element .getSuperclass ());
155
168
}
156
169
return interfaces ;
157
170
} catch (Exception e ) {
@@ -166,4 +179,115 @@ private String makeQualifiedClassName(String packageName, String className) {
166
179
}
167
180
return packageName + "." + className ;
168
181
}
182
+
183
+ private List <DeclaredType > findChain (DeclaredType declaredType ) {
184
+ final var resourceControllerType =
185
+ processingEnv
186
+ .getTypeUtils ()
187
+ .getDeclaredType (
188
+ processingEnv
189
+ .getElementUtils ()
190
+ .getTypeElement (ResourceController .class .getCanonicalName ()),
191
+ processingEnv .getTypeUtils ().getWildcardType (null , null ));
192
+ final var result = new ArrayList <DeclaredType >();
193
+ result .add (declaredType );
194
+ var superElement = ((TypeElement ) ((DeclaredType ) declaredType ).asElement ());
195
+ var superclass = (DeclaredType ) superElement .getSuperclass ();
196
+ boolean interfaceFound = false ;
197
+ final var matchingInterfaces =
198
+ superElement .getInterfaces ().stream ()
199
+ .filter (
200
+ intface ->
201
+ processingEnv .getTypeUtils ().isAssignable (intface , resourceControllerType ))
202
+ .map (i -> (DeclaredType ) i )
203
+ .collect (Collectors .toList ());
204
+ if (!matchingInterfaces .isEmpty ()) {
205
+ result .addAll (matchingInterfaces );
206
+ interfaceFound = true ;
207
+ }
208
+
209
+ while (superclass .getKind () != TypeKind .NONE ) {
210
+ if (interfaceFound ) {
211
+ final var lastFoundInterface = result .get (result .size () - 1 );
212
+ final var marchingInterfaces =
213
+ ((TypeElement ) lastFoundInterface .asElement ())
214
+ .getInterfaces ().stream ()
215
+ .filter (
216
+ intface ->
217
+ processingEnv
218
+ .getTypeUtils ()
219
+ .isAssignable (intface , resourceControllerType ))
220
+ .map (i -> (DeclaredType ) i )
221
+ .collect (Collectors .toList ());
222
+
223
+ if (marchingInterfaces .size () > 0 ) {
224
+ result .addAll (marchingInterfaces );
225
+ continue ;
226
+ } else {
227
+ break ;
228
+ }
229
+ }
230
+
231
+ if (processingEnv .getTypeUtils ().isAssignable (superclass , resourceControllerType )) {
232
+ result .add (superclass );
233
+ }
234
+
235
+ superElement = (TypeElement ) superclass .asElement ();
236
+ final var matchedInterfaces =
237
+ superElement .getInterfaces ().stream ()
238
+ .filter (
239
+ intface ->
240
+ processingEnv .getTypeUtils ().isAssignable (intface , resourceControllerType ))
241
+ .map (i -> (DeclaredType ) i )
242
+ .collect (Collectors .toList ());
243
+ if (matchedInterfaces .size () > 0 ) {
244
+ result .addAll (matchedInterfaces );
245
+ interfaceFound = true ;
246
+ continue ;
247
+ }
248
+
249
+ if (superElement .getSuperclass ().getKind () == TypeKind .NONE ) {
250
+ break ;
251
+ }
252
+ superclass = (DeclaredType ) superElement .getSuperclass ();
253
+ }
254
+
255
+ return result ;
256
+ }
257
+
258
+ private TypeMirror getCustomResourceClass (List <DeclaredType > chain ) {
259
+ var lastIndex = chain .size () - 1 ;
260
+ String typeName ;
261
+ final List <? extends TypeMirror > typeArguments = (chain .get (lastIndex )).getTypeArguments ();
262
+ if (typeArguments .get (0 ).getKind () == TYPEVAR ) {
263
+ typeName = ((TypeVariable ) typeArguments .get (0 )).asElement ().getSimpleName ().toString ();
264
+ } else if (typeArguments .get (0 ).getKind () == DECLARED ) {
265
+ return typeArguments .get (0 );
266
+ } else {
267
+ typeName = "" ;
268
+ }
269
+
270
+ while (lastIndex > 0 ) {
271
+ lastIndex -= 1 ;
272
+ final List <? extends TypeMirror > tArguments = (chain .get (lastIndex )).getTypeArguments ();
273
+ final List <? extends TypeParameterElement > typeParameters =
274
+ ((TypeElement ) ((chain .get (lastIndex )).asElement ())).getTypeParameters ();
275
+ final String tName = typeName ;
276
+ final var typeIndex =
277
+ IntStream .range (0 , typeParameters .size ())
278
+ .filter (i -> typeParameters .get (i ).getSimpleName ().toString ().equals (tName ))
279
+ .findFirst ()
280
+ .getAsInt ();
281
+
282
+ final TypeMirror matchedType = tArguments .get (typeIndex );
283
+ if (matchedType .getKind () == TYPEVAR ) {
284
+ typeName = ((TypeVariable ) matchedType ).asElement ().getSimpleName ().toString ();
285
+ } else if (matchedType .getKind () == DECLARED ) {
286
+ return matchedType ;
287
+ } else {
288
+ typeName = "" ;
289
+ }
290
+ }
291
+ return null ;
292
+ }
169
293
}
0 commit comments