11package io .javaoperatorsdk .operator .api .config .dependent ;
22
3+ import java .lang .annotation .Annotation ;
34import java .util .HashMap ;
45import java .util .Map ;
56
@@ -14,7 +15,10 @@ public class DependentResourceConfigurationResolver {
1415
1516 private DependentResourceConfigurationResolver () {}
1617
17- private static final Map <Class , ConfigurationConverter > converters = new HashMap <>();
18+ private static final Map <Class <? extends DependentResource >, ConverterAnnotationPair > converters =
19+ new HashMap <>();
20+ private static final Map <Class <? extends ConfigurationConverter >, ConfigurationConverter > knownConverters =
21+ new HashMap <>();
1822
1923 public static <C extends ControllerConfiguration <? extends HasMetadata >> void configure (
2024 DependentResource dependentResource , DependentResourceSpec spec , C parentConfiguration ) {
@@ -38,39 +42,140 @@ public static <C extends ControllerConfiguration<? extends HasMetadata>> Object
3842 }
3943
4044 // find Configured-annotated class if it exists
41- final var dependentResourceClass = spec .getDependentResourceClass ();
42- Class <?> currentClass = dependentResourceClass ;
43- Configured configured = null ;
44- while (!Object .class .equals (currentClass )) {
45+ return extractConfigurationFromConfigured (spec .getDependentResourceClass (),
46+ parentConfiguration );
47+ }
48+
49+ public static <C extends ControllerConfiguration <? extends HasMetadata >> Object extractConfigurationFromConfigured (
50+ Class <? extends DependentResource > dependentResourceClass , C parentConfiguration ) {
51+ var converterAnnotationPair = converters .get (dependentResourceClass );
52+
53+ Annotation configAnnotation ;
54+ if (converterAnnotationPair == null ) {
55+ var configuredClassPair = getConfigured (dependentResourceClass );
56+ if (configuredClassPair == null ) {
57+ return null ;
58+ }
59+
60+ // check if we already have a converter registered for the found Configured annotated class
61+ converterAnnotationPair = converters .get (configuredClassPair .annotatedClass );
62+ if (converterAnnotationPair == null ) {
63+ final var configured = configuredClassPair .configured ;
64+ converterAnnotationPair =
65+ getOrCreateConverter (dependentResourceClass , parentConfiguration ,
66+ configured .converter (),
67+ configured .by ());
68+ } else {
69+ // only register the converter pair for this dependent resource class as well
70+ converters .put (dependentResourceClass , converterAnnotationPair );
71+ }
72+ }
73+
74+ // find the associated configuration annotation
75+ configAnnotation =
76+ dependentResourceClass .getAnnotation (converterAnnotationPair .annotationClass );
77+ final var converter = converterAnnotationPair .converter ;
78+
79+ // always called even if the annotation is null so that implementations can provide default
80+ // values
81+ return converter .configFrom (configAnnotation , parentConfiguration , dependentResourceClass );
82+ }
83+
84+ private static ConfiguredClassPair getConfigured (
85+ Class <? extends DependentResource > dependentResourceClass ) {
86+ Class <? extends DependentResource > currentClass = dependentResourceClass ;
87+ Configured configured ;
88+ ConfiguredClassPair result = null ;
89+ while (DependentResource .class .isAssignableFrom (currentClass )) {
4590 configured = currentClass .getAnnotation (Configured .class );
4691 if (configured != null ) {
92+ result = new ConfiguredClassPair (configured , currentClass );
4793 break ;
4894 }
49- currentClass = currentClass .getSuperclass ();
95+ currentClass = ( Class <? extends DependentResource >) currentClass .getSuperclass ();
5096 }
97+ return result ;
98+ }
5199
100+ private static <C extends ControllerConfiguration <? extends HasMetadata >> ConverterAnnotationPair getOrCreateConverter (
101+ Class <? extends DependentResource > dependentResourceClass , C parentConfiguration ,
102+ Class <? extends ConfigurationConverter > converterClass ,
103+ Class <? extends Annotation > annotationClass ) {
104+ var converterPair = converters .get (dependentResourceClass );
105+ if (converterPair == null ) {
106+ // only instantiate a new converter if we haven't done so already for this converter type
107+ var converter = knownConverters .get (converterClass );
108+ if (converter == null ) {
109+ converter = Utils .instantiate (converterClass ,
110+ ConfigurationConverter .class ,
111+ Utils .contextFor (parentConfiguration , dependentResourceClass , Configured .class ));
112+ knownConverters .put (converterClass , converter );
113+ }
114+ // record dependent class - converter association for faster future retrieval
115+ converterPair = new ConverterAnnotationPair (converter , annotationClass );
116+ converters .put (dependentResourceClass , converterPair );
117+ }
118+ return converterPair ;
119+ }
120+
121+ static ConfigurationConverter getConverter (
122+ Class <? extends DependentResource > dependentResourceClass ) {
123+ final var converterAnnotationPair = converters .get (dependentResourceClass );
124+ return converterAnnotationPair != null ? converterAnnotationPair .converter : null ;
125+ }
126+
127+ @ SuppressWarnings ("unused" )
128+ public static void registerConverter (Class <? extends DependentResource > dependentResourceClass ,
129+ ConfigurationConverter converter ) {
130+ var configured = getConfigured (dependentResourceClass );
52131 if (configured == null ) {
53- return null ;
132+ throw new IllegalArgumentException ("There is no @" + Configured .class .getSimpleName ()
133+ + " annotation on " + dependentResourceClass .getName ()
134+ + " or its superclasses and thus doesn't need to be associated with a converter" );
54135 }
136+
55137 // find the associated configuration annotation
56- final var configAnnotation = dependentResourceClass .getAnnotation (configured .by ());
57- final var converter = getConverter (dependentResourceClass , parentConfiguration , configured );
58- // always called even if the annotation is null so that implementations can provide default
59- // values
60- return converter .configFrom (configAnnotation , parentConfiguration , dependentResourceClass );
138+ final var toRegister = new ConverterAnnotationPair (converter , configured .configured .by ());
139+ final Class <? extends ConfigurationConverter > converterClass = converter .getClass ();
140+ converters .put (dependentResourceClass , toRegister );
141+
142+ // also register the Configured-annotated class if not the one we're registering
143+ if (!dependentResourceClass .equals (configured .annotatedClass )) {
144+ converters .put (configured .annotatedClass , toRegister );
145+ }
146+
147+ knownConverters .put (converterClass , converter );
61148 }
62149
63- static <C extends ControllerConfiguration <? extends HasMetadata >> ConfigurationConverter getConverter (
64- Class <? extends DependentResource > dependentResourceClass , C parentConfiguration ,
65- Configured configured ) {
66- var converter = converters .get (dependentResourceClass );
67- if (converter == null ) {
68- converter = Utils .instantiate (configured .converter (),
69- ConfigurationConverter .class ,
70- Utils .contextFor (parentConfiguration , dependentResourceClass , Configured .class ));
71- converters .put (dependentResourceClass , converter );
150+ private static class ConfiguredClassPair {
151+ private final Configured configured ;
152+ private final Class <? extends DependentResource > annotatedClass ;
153+
154+ private ConfiguredClassPair (Configured configured ,
155+ Class <? extends DependentResource > annotatedClass ) {
156+ this .configured = configured ;
157+ this .annotatedClass = annotatedClass ;
158+ }
159+
160+ @ Override
161+ public String toString () {
162+ return annotatedClass .getName () + " -> " + configured ;
72163 }
73- return converter ;
74164 }
75165
166+ private static class ConverterAnnotationPair {
167+ private final ConfigurationConverter converter ;
168+ private final Class <? extends Annotation > annotationClass ;
169+
170+ private ConverterAnnotationPair (ConfigurationConverter converter ,
171+ Class <? extends Annotation > annotationClass ) {
172+ this .converter = converter ;
173+ this .annotationClass = annotationClass ;
174+ }
175+
176+ @ Override
177+ public String toString () {
178+ return converter .toString () + " -> " + annotationClass .getName ();
179+ }
180+ }
76181}
0 commit comments