1
+ package io .leangen .graphql .metadata .execution ;
2
+
3
+ import io .leangen .graphql .util .ClassUtils ;
4
+
5
+ import java .lang .invoke .*;
6
+ import java .lang .reflect .AnnotatedType ;
7
+ import java .lang .reflect .Method ;
8
+ import java .lang .reflect .Parameter ;
9
+ import java .util .Optional ;
10
+ import java .util .function .Function ;
11
+
12
+ /**
13
+ * Created by soumik.dutta on 9/21/24.
14
+ */
15
+ public class LambdaInvoker extends Executable <Method > {
16
+ private static final Parameter [] NO_PARAMETERS = {};
17
+ private static final AnnotatedType [] NO_ANNOTATED_TYPES = {};
18
+ final Function <Object , Object > lambdaGetter ;
19
+ private final AnnotatedType returnType ;
20
+
21
+
22
+ public LambdaInvoker (final Method resolverMethod , final AnnotatedType enclosingType , final boolean useSetAccessible ) throws Exception {
23
+ this .delegate = resolverMethod ;
24
+ this .returnType = resolveReturnType (enclosingType );
25
+ final Optional <Function <Object , Object >> getter = createGetter (resolverMethod , useSetAccessible );
26
+ if (getter .isEmpty ()) {
27
+ throw new Exception ("Cannot create a lambda getter for " + resolverMethod .getName ());
28
+ }
29
+
30
+ this .lambdaGetter = getter .get ();
31
+ }
32
+
33
+ public static Optional <Function <Object , Object >> createGetter (final Method method , final boolean useSetAccessible ) throws Exception {
34
+ if (method != null ) {
35
+ if (method .getParameterCount () > 0 ) {
36
+ throw new Exception (method .getName () + " requires more than one argument" );
37
+ }
38
+
39
+ try {
40
+ method .setAccessible (useSetAccessible );
41
+ MethodHandles .Lookup lookupMe = MethodHandles .lookup ();
42
+ MethodHandles .Lookup lookup = MethodHandles .privateLookupIn (method .getDeclaringClass (), lookupMe );
43
+ MethodHandle virtualMethodHandle = lookup .unreflect (method );
44
+
45
+ CallSite site = LambdaMetafactory .metafactory (lookup , "apply" , MethodType .methodType (Function .class ),
46
+ MethodType .methodType (Object .class , Object .class ), virtualMethodHandle ,
47
+ MethodType .methodType (method .getReturnType (), method .getDeclaringClass ()));
48
+
49
+ @ SuppressWarnings ("unchecked" ) Function <Object , Object > getterFunction = (Function <Object , Object >) site .getTarget ()
50
+ .invokeExact ();
51
+ return Optional .of (getterFunction );
52
+ } catch (Throwable e ) {
53
+ //
54
+ // if we cant make a dynamic lambda here, then we give up and let the old property fetching code do its thing
55
+ // this can happen on runtimes such as GraalVM native where LambdaMetafactory is not supported
56
+ // and will throw something like :
57
+ //
58
+ // com.oracle.svm.core.jdk.UnsupportedFeatureError: Defining hidden classes at runtime is not supported.
59
+ // at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:89)
60
+ }
61
+ }
62
+ return Optional .empty ();
63
+ }
64
+
65
+ @ Override
66
+ public Object execute (final Object target , final Object [] args ) {
67
+ return lambdaGetter .apply (target );
68
+ }
69
+
70
+ @ Override
71
+ final public AnnotatedType getReturnType () {
72
+ return returnType ;
73
+ }
74
+
75
+ private AnnotatedType resolveReturnType (final AnnotatedType enclosingType ) {
76
+ return ClassUtils .getReturnType (delegate , enclosingType );
77
+ }
78
+
79
+
80
+ @ Override
81
+ final public int getParameterCount () {
82
+ return 0 ;
83
+ }
84
+
85
+ @ Override
86
+ final public AnnotatedType [] getAnnotatedParameterTypes () {
87
+ return NO_ANNOTATED_TYPES ;
88
+ }
89
+
90
+ @ Override
91
+ final public Parameter [] getParameters () {
92
+ return NO_PARAMETERS ;
93
+ }
94
+ }
0 commit comments