I've been troubled by similar issues as well when using MethodHandle.Lookup
in JDK 8 - 10, which behave differently. I've blogged about the correct solution here in detail.
This approach works in Java 8
In Java 8, the ideal approach uses a hack that accesses a package-private constructor from Lookup
:
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
interface Duck {
default void quack() {
System.out.println("Quack");
}
}
public class ProxyDemo {
public static void main(String[] a) {
Duck duck = (Duck) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] { Duck.class },
(proxy, method, args) -> {
Constructor<Lookup> constructor = Lookup.class
.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
constructor.newInstance(Duck.class)
.in(Duck.class)
.unreflectSpecial(method, Duck.class)
.bindTo(proxy)
.invokeWithArguments(args);
return null;
}
);
duck.quack();
}
}
This is the only approach that works with both private-accessible and private-inaccessible interfaces. However, the above approach does illegal reflective access to JDK internals, which will no longer work in a future JDK version, or if --illegal-access=deny
is specified on the JVM.
This approach works on Java 9 and 10, but not 8
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Proxy;
interface Duck {
default void quack() {
System.out.println("Quack");
}
}
public class ProxyDemo {
public static void main(String[] a) {
Duck duck = (Duck) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] { Duck.class },
(proxy, method, args) -> {
MethodHandles.lookup()
.findSpecial(
Duck.class,
"quack",
MethodType.methodType(void.class, new Class[0]),
Duck.class)
.bindTo(proxy)
.invokeWithArguments(args);
return null;
}
);
duck.quack();
}
}
Solution
Simply implement both of the above solutions and check if your code is running on JDK 8 or on a later JDK and you'll be fine. Until you're not :)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…