1
1
package io .javaoperatorsdk .operator .api .config .dependent ;
2
2
3
+ import java .lang .annotation .Annotation ;
3
4
import java .util .HashMap ;
4
5
import java .util .Map ;
5
6
@@ -14,7 +15,10 @@ public class DependentResourceConfigurationResolver {
14
15
15
16
private DependentResourceConfigurationResolver () {}
16
17
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 <>();
18
22
19
23
public static <C extends ControllerConfiguration <? extends HasMetadata >> void configure (
20
24
DependentResource dependentResource , DependentResourceSpec spec , C parentConfiguration ) {
@@ -38,39 +42,140 @@ public static <C extends ControllerConfiguration<? extends HasMetadata>> Object
38
42
}
39
43
40
44
// 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 )) {
45
90
configured = currentClass .getAnnotation (Configured .class );
46
91
if (configured != null ) {
92
+ result = new ConfiguredClassPair (configured , currentClass );
47
93
break ;
48
94
}
49
- currentClass = currentClass .getSuperclass ();
95
+ currentClass = ( Class <? extends DependentResource >) currentClass .getSuperclass ();
50
96
}
97
+ return result ;
98
+ }
51
99
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 );
52
131
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" );
54
135
}
136
+
55
137
// 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 );
61
148
}
62
149
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 ;
72
163
}
73
- return converter ;
74
164
}
75
165
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
+ }
76
181
}
0 commit comments