22
33import static io .javaoperatorsdk .operator .ControllerUtils .CONTROLLERS_RESOURCE_PATH ;
44import 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 ;
57
68import 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 ;
815import io .fabric8 .kubernetes .api .builder .Function ;
916import io .fabric8 .kubernetes .client .CustomResourceDoneable ;
1017import io .javaoperatorsdk .operator .api .ResourceController ;
1421import java .util .List ;
1522import java .util .Set ;
1623import 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 ;
1831import 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 ;
2038import javax .lang .model .type .DeclaredType ;
2139import javax .lang .model .type .TypeKind ;
2240import javax .lang .model .type .TypeMirror ;
41+ import javax .lang .model .type .TypeVariable ;
2342import javax .tools .Diagnostic ;
2443import javax .tools .JavaFileObject ;
2544
2645@ SupportedAnnotationTypes ("io.javaoperatorsdk.operator.api.Controller" )
2746@ SupportedSourceVersion (SourceVersion .RELEASE_8 )
2847@ AutoService (Processor .class )
2948public class ControllerAnnotationProcessor extends AbstractProcessor {
49+
3050 private AccumulativeMappingWriter controllersResourceWriter ;
3151 private AccumulativeMappingWriter doneablesResourceWriter ;
3252 private Set <String > generatedDoneableClassFiles = new HashSet <>();
@@ -63,10 +83,13 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
6383
6484 private void generateDoneableClass (TypeElement controllerClassSymbol ) {
6585 try {
86+ System .out .println (controllerClassSymbol .toString ());
6687 final TypeMirror resourceType = findResourceType (controllerClassSymbol );
88+ System .out .println ("the resource type is " + resourceType );
6789
6890 TypeElement customerResourceTypeElement =
6991 processingEnv .getElementUtils ().getTypeElement (resourceType .toString ());
92+ System .out .println ("the customerResourceTypeElement is " + customerResourceTypeElement );
7093
7194 final String doneableClassName = customerResourceTypeElement .getSimpleName () + "Doneable" ;
7295 final String destinationClassFileName =
@@ -124,34 +147,24 @@ private void generateDoneableClass(TypeElement controllerClassSymbol) {
124147
125148 private TypeMirror findResourceType (TypeElement controllerClassSymbol ) throws Exception {
126149 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 ;
137153 } catch (Exception e ) {
138154 e .printStackTrace ();
139155 return null ;
140156 }
141157 }
142158
143- private List <DeclaredType > collectAllInterfaces (TypeElement element ) {
159+ private List <TypeMirror > collectAllInterfaces (TypeElement element ) {
144160 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 ());
148163 TypeElement superclass = ((TypeElement ) ((DeclaredType ) element .getSuperclass ()).asElement ());
149164 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 ());
154166 superclass = ((TypeElement ) ((DeclaredType ) superclass .getSuperclass ()).asElement ());
167+ interfaces .add (element .getSuperclass ());
155168 }
156169 return interfaces ;
157170 } catch (Exception e ) {
@@ -166,4 +179,115 @@ private String makeQualifiedClassName(String packageName, String className) {
166179 }
167180 return packageName + "." + className ;
168181 }
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+ }
169293}
0 commit comments