From b18989786f76c608d75b9a4a89e3b2e75ba687cc Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 28 Sep 2017 17:21:05 +0200 Subject: [PATCH] DATACMNS-1181 - Adapt MethodHandle lookup of default methods in package-scoped interfaces to changes in Java 9. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now attempt MethodHandle lookup with deep reflection capabilities via MethodHandles.privateLookupIn(…) to properly resolve default interface methods on interfaces with package-protected visibility. This API is only available in Java 9 so we need to rely on reflection. Original pull request: #251. --- ...efaultMethodInvokingMethodInterceptor.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java b/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java index 24e6b4002..29353c27e 100644 --- a/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java +++ b/src/main/java/org/springframework/data/projection/DefaultMethodInvokingMethodInterceptor.java @@ -122,6 +122,9 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor */ ENCAPSULATED { + private final @Nullable Method privateLookupIn = ReflectionUtils.findMethod(MethodHandles.class, + "privateLookupIn", Class.class, Lookup.class); + /* * (non-Javadoc) * @see org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.MethodHandleLookup#lookup(java.lang.reflect.Method) @@ -131,8 +134,8 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor MethodType methodType = MethodType.methodType(method.getReturnType(), method.getParameterTypes()); - return MethodHandles.lookup().findSpecial(method.getDeclaringClass(), method.getName(), methodType, - method.getDeclaringClass()); + return getLookup(method.getDeclaringClass()).findSpecial(method.getDeclaringClass(), method.getName(), + methodType, method.getDeclaringClass()); } /* @@ -143,6 +146,21 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor boolean isAvailable() { return true; } + + private Lookup getLookup(Class declaringClass) { + + Lookup lookup = MethodHandles.lookup(); + + if (privateLookupIn == null) { + return lookup; + } + + try { + return (Lookup) privateLookupIn.invoke(MethodHandles.class, declaringClass, lookup); + } catch (ReflectiveOperationException e) { + return lookup; + } + } }; /**