1919import java .lang .invoke .MethodHandles ;
2020import java .lang .invoke .MethodHandles .Lookup ;
2121import java .lang .invoke .MethodType ;
22- import java .lang .reflect .Constructor ;
2322import java .lang .reflect .Method ;
2423import java .lang .reflect .Modifier ;
2524import java .util .Map ;
2827import org .aopalliance .intercept .MethodInterceptor ;
2928import org .aopalliance .intercept .MethodInvocation ;
3029import org .springframework .aop .ProxyMethodInvocation ;
31- import org .springframework .data .util .Lazy ;
3230import org .springframework .lang .Nullable ;
3331import org .springframework .util .ConcurrentReferenceHashMap ;
3432import org .springframework .util .ConcurrentReferenceHashMap .ReferenceType ;
4442 */
4543public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor {
4644
47- private final MethodHandleLookup methodHandleLookup = MethodHandleLookup . getMethodHandleLookup ();
45+ private static final Lookup LOOKUP = MethodHandles . lookup ();
4846 private final Map <Method , MethodHandle > methodHandleCache = new ConcurrentReferenceHashMap <>(10 , ReferenceType .WEAK );
4947
5048 /**
@@ -64,7 +62,7 @@ public static boolean hasDefaultMethods(Class<?> interfaceClass) {
6462
6563 @ Nullable
6664 @ Override
67- public Object invoke (@ SuppressWarnings ( "null" ) MethodInvocation invocation ) throws Throwable {
65+ public Object invoke (MethodInvocation invocation ) throws Throwable {
6866
6967 Method method = invocation .getMethod ();
7068
@@ -84,161 +82,28 @@ private MethodHandle getMethodHandle(Method method) throws Exception {
8482
8583 if (handle == null ) {
8684
87- handle = methodHandleLookup . lookup (method );
85+ handle = lookup (method );
8886 methodHandleCache .put (method , handle );
8987 }
9088
9189 return handle ;
9290 }
9391
9492 /**
95- * Strategies for {@link MethodHandle} lookup .
93+ * Lookup a {@link MethodHandle} given {@link Method} to look up .
9694 *
97- * @since 2.0
95+ * @param method must not be {@literal null}.
96+ * @return the method handle.
97+ * @throws ReflectiveOperationException
9898 */
99- enum MethodHandleLookup {
99+ private static MethodHandle lookup ( Method method ) throws ReflectiveOperationException {
100100
101- /**
102- * Encapsulated {@link MethodHandle} lookup working on Java 9.
103- */
104- ENCAPSULATED {
101+ Lookup lookup = MethodHandles .privateLookupIn (method .getDeclaringClass (), LOOKUP );
102+ MethodType methodType = MethodType .methodType (method .getReturnType (), method .getParameterTypes ());
103+ Class <?> declaringClass = method .getDeclaringClass ();
105104
106- private final @ Nullable Method privateLookupIn = ReflectionUtils .findMethod (MethodHandles .class ,
107- "privateLookupIn" , Class .class , Lookup .class );
108-
109- @ Override
110- MethodHandle lookup (Method method ) throws ReflectiveOperationException {
111-
112- if (privateLookupIn == null ) {
113- throw new IllegalStateException ("Could not obtain MethodHandles.privateLookupIn" );
114- }
115-
116- return doLookup (method , getLookup (method .getDeclaringClass (), privateLookupIn ));
117- }
118-
119- @ Override
120- boolean isAvailable () {
121- return privateLookupIn != null ;
122- }
123-
124- private Lookup getLookup (Class <?> declaringClass , Method privateLookupIn ) {
125-
126- Lookup lookup = MethodHandles .lookup ();
127-
128- try {
129- return (Lookup ) privateLookupIn .invoke (MethodHandles .class , declaringClass , lookup );
130- } catch (ReflectiveOperationException e ) {
131- return lookup ;
132- }
133- }
134- },
135-
136- /**
137- * Open (via reflection construction of {@link MethodHandles.Lookup}) method handle lookup. Works with Java 8 and
138- * with Java 9 permitting illegal access.
139- */
140- OPEN {
141-
142- private final Lazy <Constructor <Lookup >> constructor = Lazy .of (MethodHandleLookup ::getLookupConstructor );
143-
144- @ Override
145- MethodHandle lookup (Method method ) throws ReflectiveOperationException {
146-
147- if (!isAvailable ()) {
148- throw new IllegalStateException ("Could not obtain MethodHandles.lookup constructor" );
149- }
150-
151- Constructor <Lookup > constructor = this .constructor .get ();
152-
153- return constructor .newInstance (method .getDeclaringClass ()).unreflectSpecial (method , method .getDeclaringClass ());
154- }
155-
156- @ Override
157- boolean isAvailable () {
158- return constructor .orElse (null ) != null ;
159- }
160- },
161-
162- /**
163- * Fallback {@link MethodHandle} lookup using {@link MethodHandles#lookup() public lookup}.
164- *
165- * @since 2.1
166- */
167- FALLBACK {
168-
169- @ Override
170- MethodHandle lookup (Method method ) throws ReflectiveOperationException {
171- return doLookup (method , MethodHandles .lookup ());
172- }
173-
174- @ Override
175- boolean isAvailable () {
176- return true ;
177- }
178- };
179-
180- private static MethodHandle doLookup (Method method , Lookup lookup )
181- throws NoSuchMethodException , IllegalAccessException {
182-
183- MethodType methodType = MethodType .methodType (method .getReturnType (), method .getParameterTypes ());
184-
185- if (Modifier .isStatic (method .getModifiers ())) {
186- return lookup .findStatic (method .getDeclaringClass (), method .getName (), methodType );
187- }
188-
189- return lookup .findSpecial (method .getDeclaringClass (), method .getName (), methodType , method .getDeclaringClass ());
190- }
191-
192- /**
193- * Lookup a {@link MethodHandle} given {@link Method} to look up.
194- *
195- * @param method must not be {@literal null}.
196- * @return the method handle.
197- * @throws ReflectiveOperationException
198- */
199- abstract MethodHandle lookup (Method method ) throws ReflectiveOperationException ;
200-
201- /**
202- * @return {@literal true} if the lookup is available.
203- */
204- abstract boolean isAvailable ();
205-
206- /**
207- * Obtain the first available {@link MethodHandleLookup}.
208- *
209- * @return the {@link MethodHandleLookup}
210- * @throws IllegalStateException if no {@link MethodHandleLookup} is available.
211- */
212- public static MethodHandleLookup getMethodHandleLookup () {
213-
214- for (MethodHandleLookup it : MethodHandleLookup .values ()) {
215-
216- if (it .isAvailable ()) {
217- return it ;
218- }
219- }
220-
221- throw new IllegalStateException ("No MethodHandleLookup available" );
222- }
223-
224- @ Nullable
225- private static Constructor <Lookup > getLookupConstructor () {
226-
227- try {
228-
229- Constructor <Lookup > constructor = Lookup .class .getDeclaredConstructor (Class .class );
230- ReflectionUtils .makeAccessible (constructor );
231-
232- return constructor ;
233- } catch (Exception ex ) {
234-
235- // this is the signal that we are on Java 9 (encapsulated) and can't use the accessible constructor approach.
236- if (ex .getClass ().getName ().equals ("java.lang.reflect.InaccessibleObjectException" )) {
237- return null ;
238- }
239-
240- throw new IllegalStateException (ex );
241- }
242- }
105+ return Modifier .isStatic (method .getModifiers ())
106+ ? lookup .findStatic (declaringClass , method .getName (), methodType )
107+ : lookup .findSpecial (declaringClass , method .getName (), methodType , declaringClass );
243108 }
244109}
0 commit comments