follow-up: adding fallback for 'privateLookupIn' in case of JDK 9+
@@ -160,6 +160,8 @@ public class ClientProxyImpl extends AbstractClient implements
}
private static class WrappedException extends Exception {
+ private static final long serialVersionUID = 1183890106889852917L;
+
final Throwable wrapped;
WrappedException(Throwable wrapped) {
this.wrapped = wrapped;
@@ -177,7 +179,8 @@ public class ClientProxyImpl extends AbstractClient implements
@Override
public Object run() throws Exception {
try {
- final MethodHandles.Lookup lookup = MethodHandles.publicLookup()
+ final MethodHandles.Lookup lookup = MethodHandles
+ .publicLookup()
.in(declaringClass);
// force private access so unreflectSpecial can invoke the interface's default method
@@ -195,9 +198,17 @@ public class ClientProxyImpl extends AbstractClient implements
.bindTo(o)
.invokeWithArguments(params);
} catch (Throwable t) {
+ if (t instanceof IllegalAccessException) {
+ try {
+ return invokeDefaultMethodUsingPrivateLookup(declaringClass, o, m, params);
+ } catch (final NoSuchMethodException ex) {
+ throw new WrappedException(t);
+ }
+ } else {
throw new WrappedException(t);
}
}
+ }
});
} catch (PrivilegedActionException pae) {
Throwable wrapped = pae.getCause();
@@ -208,6 +219,29 @@ public class ClientProxyImpl extends AbstractClient implements
}
}
+ /**
+ * For JDK 9+, we could use MethodHandles.privateLookupIn, which is not
+ * available in JDK 8.
+ */
+ private static Object invokeDefaultMethodUsingPrivateLookup(Class<?> declaringClass, Object o, Method m,
+ Object[] params) throws WrappedException, NoSuchMethodException {
+ try {
+ final Method privateLookup = MethodHandles
+ .class
+ .getDeclaredMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
+
+ return ((MethodHandles.Lookup)privateLookup
+ .invoke(null, declaringClass, MethodHandles.lookup()))
+ .unreflectSpecial(m, declaringClass)
+ .bindTo(o)
+ .invokeWithArguments(params);
+ } catch (NoSuchMethodException t) {
+ throw t;
+ } catch (Throwable t) {
+ throw new WrappedException(t);
+ }
+ }
+
/**
* Updates the current state if Client method is invoked, otherwise
* does the remote invocation or returns a new proxy if subresource
