11
11
import org .elasticsearch .common .util .CollectionUtils ;
12
12
13
13
import java .lang .invoke .MethodHandle ;
14
+ import java .util .ArrayList ;
15
+ import java .util .Arrays ;
16
+ import java .util .HashSet ;
17
+ import java .util .List ;
14
18
import java .util .Map ;
15
19
import java .util .Objects ;
16
20
import java .util .Set ;
@@ -27,6 +31,7 @@ public final class PainlessLookup {
27
31
private final Map <String , Class <?>> javaClassNamesToClasses ;
28
32
private final Map <String , Class <?>> canonicalClassNamesToClasses ;
29
33
private final Map <Class <?>, PainlessClass > classesToPainlessClasses ;
34
+ private final Map <Class <?>, Set <Class <?>>> classesToDirectSubClasses ;
30
35
31
36
private final Map <String , PainlessMethod > painlessMethodKeysToImportedPainlessMethods ;
32
37
private final Map <String , PainlessClassBinding > painlessMethodKeysToPainlessClassBindings ;
@@ -36,13 +41,15 @@ public final class PainlessLookup {
36
41
Map <String , Class <?>> javaClassNamesToClasses ,
37
42
Map <String , Class <?>> canonicalClassNamesToClasses ,
38
43
Map <Class <?>, PainlessClass > classesToPainlessClasses ,
44
+ Map <Class <?>, Set <Class <?>>> classesToDirectSubClasses ,
39
45
Map <String , PainlessMethod > painlessMethodKeysToImportedPainlessMethods ,
40
46
Map <String , PainlessClassBinding > painlessMethodKeysToPainlessClassBindings ,
41
47
Map <String , PainlessInstanceBinding > painlessMethodKeysToPainlessInstanceBindings ) {
42
48
43
49
Objects .requireNonNull (javaClassNamesToClasses );
44
50
Objects .requireNonNull (canonicalClassNamesToClasses );
45
51
Objects .requireNonNull (classesToPainlessClasses );
52
+ Objects .requireNonNull (classesToDirectSubClasses );
46
53
47
54
Objects .requireNonNull (painlessMethodKeysToImportedPainlessMethods );
48
55
Objects .requireNonNull (painlessMethodKeysToPainlessClassBindings );
@@ -51,6 +58,7 @@ public final class PainlessLookup {
51
58
this .javaClassNamesToClasses = javaClassNamesToClasses ;
52
59
this .canonicalClassNamesToClasses = CollectionUtils .copyMap (canonicalClassNamesToClasses );
53
60
this .classesToPainlessClasses = CollectionUtils .copyMap (classesToPainlessClasses );
61
+ this .classesToDirectSubClasses = CollectionUtils .copyMap (classesToDirectSubClasses );
54
62
55
63
this .painlessMethodKeysToImportedPainlessMethods = CollectionUtils .copyMap (painlessMethodKeysToImportedPainlessMethods );
56
64
this .painlessMethodKeysToPainlessClassBindings = CollectionUtils .copyMap (painlessMethodKeysToPainlessClassBindings );
@@ -77,6 +85,10 @@ public Set<Class<?>> getClasses() {
77
85
return classesToPainlessClasses .keySet ();
78
86
}
79
87
88
+ public Set <Class <?>> getDirectSubClasses (Class <?> superClass ) {
89
+ return classesToDirectSubClasses .get (superClass );
90
+ }
91
+
80
92
public Set <String > getImportedPainlessMethodsKeys () {
81
93
return painlessMethodKeysToImportedPainlessMethods .keySet ();
82
94
}
@@ -144,16 +156,12 @@ public PainlessMethod lookupPainlessMethod(Class<?> targetClass, boolean isStati
144
156
targetClass = typeToBoxedType (targetClass );
145
157
}
146
158
147
- PainlessClass targetPainlessClass = classesToPainlessClasses .get (targetClass );
148
159
String painlessMethodKey = buildPainlessMethodKey (methodName , methodArity );
160
+ Function <PainlessClass , PainlessMethod > objectLookup = isStatic ?
161
+ targetPainlessClass -> targetPainlessClass .staticMethods .get (painlessMethodKey ) :
162
+ targetPainlessClass -> targetPainlessClass .methods .get (painlessMethodKey );
149
163
150
- if (targetPainlessClass == null ) {
151
- return null ;
152
- }
153
-
154
- return isStatic ?
155
- targetPainlessClass .staticMethods .get (painlessMethodKey ) :
156
- targetPainlessClass .methods .get (painlessMethodKey );
164
+ return lookupPainlessObject (targetClass , objectLookup );
157
165
}
158
166
159
167
public PainlessField lookupPainlessField (String targetCanonicalClassName , boolean isStatic , String fieldName ) {
@@ -172,22 +180,12 @@ public PainlessField lookupPainlessField(Class<?> targetClass, boolean isStatic,
172
180
Objects .requireNonNull (targetClass );
173
181
Objects .requireNonNull (fieldName );
174
182
175
- PainlessClass targetPainlessClass = classesToPainlessClasses .get (targetClass );
176
183
String painlessFieldKey = buildPainlessFieldKey (fieldName );
184
+ Function <PainlessClass , PainlessField > objectLookup = isStatic ?
185
+ targetPainlessClass -> targetPainlessClass .staticFields .get (painlessFieldKey ) :
186
+ targetPainlessClass -> targetPainlessClass .fields .get (painlessFieldKey );
177
187
178
- if (targetPainlessClass == null ) {
179
- return null ;
180
- }
181
-
182
- PainlessField painlessField = isStatic ?
183
- targetPainlessClass .staticFields .get (painlessFieldKey ) :
184
- targetPainlessClass .fields .get (painlessFieldKey );
185
-
186
- if (painlessField == null ) {
187
- return null ;
188
- }
189
-
190
- return painlessField ;
188
+ return lookupPainlessObject (targetClass , objectLookup );
191
189
}
192
190
193
191
public PainlessMethod lookupImportedPainlessMethod (String methodName , int arity ) {
@@ -232,7 +230,7 @@ public PainlessMethod lookupRuntimePainlessMethod(Class<?> originalTargetClass,
232
230
Function <PainlessClass , PainlessMethod > objectLookup =
233
231
targetPainlessClass -> targetPainlessClass .runtimeMethods .get (painlessMethodKey );
234
232
235
- return lookupRuntimePainlessObject (originalTargetClass , objectLookup );
233
+ return lookupPainlessObject (originalTargetClass , objectLookup );
236
234
}
237
235
238
236
public MethodHandle lookupRuntimeGetterMethodHandle (Class <?> originalTargetClass , String getterName ) {
@@ -241,7 +239,7 @@ public MethodHandle lookupRuntimeGetterMethodHandle(Class<?> originalTargetClass
241
239
242
240
Function <PainlessClass , MethodHandle > objectLookup = targetPainlessClass -> targetPainlessClass .getterMethodHandles .get (getterName );
243
241
244
- return lookupRuntimePainlessObject (originalTargetClass , objectLookup );
242
+ return lookupPainlessObject (originalTargetClass , objectLookup );
245
243
}
246
244
247
245
public MethodHandle lookupRuntimeSetterMethodHandle (Class <?> originalTargetClass , String setterName ) {
@@ -250,10 +248,13 @@ public MethodHandle lookupRuntimeSetterMethodHandle(Class<?> originalTargetClass
250
248
251
249
Function <PainlessClass , MethodHandle > objectLookup = targetPainlessClass -> targetPainlessClass .setterMethodHandles .get (setterName );
252
250
253
- return lookupRuntimePainlessObject (originalTargetClass , objectLookup );
251
+ return lookupPainlessObject (originalTargetClass , objectLookup );
254
252
}
255
253
256
- private <T > T lookupRuntimePainlessObject (Class <?> originalTargetClass , Function <PainlessClass , T > objectLookup ) {
254
+ private <T > T lookupPainlessObject (Class <?> originalTargetClass , Function <PainlessClass , T > objectLookup ) {
255
+ Objects .requireNonNull (originalTargetClass );
256
+ Objects .requireNonNull (objectLookup );
257
+
257
258
Class <?> currentTargetClass = originalTargetClass ;
258
259
259
260
while (currentTargetClass != null ) {
@@ -270,17 +271,38 @@ private <T> T lookupRuntimePainlessObject(Class<?> originalTargetClass, Function
270
271
currentTargetClass = currentTargetClass .getSuperclass ();
271
272
}
272
273
274
+ if (originalTargetClass .isInterface ()) {
275
+ PainlessClass targetPainlessClass = classesToPainlessClasses .get (Object .class );
276
+
277
+ if (targetPainlessClass != null ) {
278
+ T painlessObject = objectLookup .apply (targetPainlessClass );
279
+
280
+ if (painlessObject != null ) {
281
+ return painlessObject ;
282
+ }
283
+ }
284
+ }
285
+
273
286
currentTargetClass = originalTargetClass ;
287
+ Set <Class <?>> resolvedInterfaces = new HashSet <>();
274
288
275
289
while (currentTargetClass != null ) {
276
- for (Class <?> targetInterface : currentTargetClass .getInterfaces ()) {
277
- PainlessClass targetPainlessClass = classesToPainlessClasses .get (targetInterface );
290
+ List <Class <?>> targetInterfaces = new ArrayList <>(Arrays .asList (currentTargetClass .getInterfaces ()));
291
+
292
+ while (targetInterfaces .isEmpty () == false ) {
293
+ Class <?> targetInterface = targetInterfaces .remove (0 );
294
+
295
+ if (resolvedInterfaces .add (targetInterface )) {
296
+ PainlessClass targetPainlessClass = classesToPainlessClasses .get (targetInterface );
297
+
298
+ if (targetPainlessClass != null ) {
299
+ T painlessObject = objectLookup .apply (targetPainlessClass );
278
300
279
- if (targetPainlessClass != null ) {
280
- T painlessObject = objectLookup .apply (targetPainlessClass );
301
+ if (painlessObject != null ) {
302
+ return painlessObject ;
303
+ }
281
304
282
- if (painlessObject != null ) {
283
- return painlessObject ;
305
+ targetInterfaces .addAll (Arrays .asList (targetInterface .getInterfaces ()));
284
306
}
285
307
}
286
308
}
0 commit comments