Skip to content

Instantly share code, notes, and snippets.

@lukaseder
Created March 28, 2018 09:56
Show Gist options
  • Save lukaseder/f47f5a0d156bf7b80b67da9d14422d4a to your computer and use it in GitHub Desktop.
Save lukaseder/f47f5a0d156bf7b80b67da9d14422d4a to your computer and use it in GitHub Desktop.
Correct Reflective Access to Interface Default Methods in Java 8, 9, 10
// Compile on JDK 9 or 10 with javac -source 1.8 -target 1.8 CallDefaultMethodThroughReflection.java
// Blog post here: https://blog.jooq.org/2018/03/28/correct-reflective-access-to-interface-default-methods-in-java-8-9-10
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface PrivateInaccessible {
default void quack() {
System.out.println(" -> PrivateInaccessible.quack()");
}
}
public class CallDefaultMethodThroughReflection {
interface PrivateAccessible {
default void quack() {
System.out.println(" -> PrivateAccessible.quack()");
}
}
public static void main(String[] args) {
System.out.println("PrivateAccessible");
System.out.println("-----------------");
System.out.println();
proxy(PrivateAccessible.class).quack();
System.out.println();
System.out.println("PrivateInaccessible");
System.out.println("-------------------");
System.out.println();
proxy(PrivateInaccessible.class).quack();
}
private static void quack(Lookup lookup, Class<?> type, Object proxy) {
System.out.println("Lookup.in(type).unreflectSpecial(...)");
try {
lookup.in(type)
.unreflectSpecial(type.getMethod("quack"), type)
.bindTo(proxy)
.invokeWithArguments();
}
catch (Throwable e) {
System.out.println(" -> " + e.getClass() + ": " + e.getMessage());
}
System.out.println("Lookup.findSpecial(...)");
try {
lookup.findSpecial(type, "quack", MethodType.methodType(void.class, new Class[0]), type)
.bindTo(proxy)
.invokeWithArguments();
}
catch (Throwable e) {
System.out.println(" -> " + e.getClass() + ": " + e.getMessage());
}
}
@SuppressWarnings("unchecked")
private static <T> T proxy(Class<T> type) {
return (T) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[] { type },
(Object proxy, Method method, Object[] arguments) -> {
System.out.println("MethodHandles.lookup()");
quack(MethodHandles.lookup(), type, proxy);
try {
System.out.println();
System.out.println("Lookup(Class)");
Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class);
constructor.setAccessible(true);
constructor.newInstance(type);
quack(constructor.newInstance(type), type, proxy);
}
catch (Exception e) {
System.out.println(" -> " + e.getClass() + ": " + e.getMessage());
}
try {
System.out.println();
System.out.println("MethodHandles.privateLookupIn()");
quack(MethodHandles.privateLookupIn(type, MethodHandles.lookup()), type, proxy);
}
catch (Error e) {
System.out.println(" -> " + e.getClass() + ": " + e.getMessage());
}
return null;
}
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment