private static MethodHandles.Lookup privateLookupIn(Class clazz) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException { try { // Java 9+ has privateLookupIn method on MethodHandles, but since we are shipping and using Java 8 // we need to access it via reflection. This is preferred way because it's Java 9+ public api and is // likely to not change final Method privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); return (MethodHandles.Lookup) privateLookupIn.invoke(null, clazz, MethodHandles.lookup()); } catch (NoSuchMethodException e) { // In Java 8 we first do standard lookupIn class final MethodHandles.Lookup lookupIn = MethodHandles.lookup().in(clazz); // and then we mark it as trusted for private lookup via reflection on private field final Field modes = MethodHandles.Lookup.class.getDeclaredField("allowedModes"); modes.setAccessible(true); modes.setInt(lookupIn, -1); // -1 == TRUSTED return lookupIn; } } }
@Override public MethodHandle getMethodHandle(String methodName, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class<?> shadowWindowClass; try { shadowWindowClass = type.returnType().getClassLoader().loadClass(ShadowWindow.class.getName()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return lookup.in(type.returnType()).findStatic(shadowWindowClass, "create", type); } }
@Override public MethodHandle getMethodHandle(String methodName, MethodType type) throws NoSuchMethodException, IllegalAccessException { Class<?> shadowWindowClass; try { shadowWindowClass = type.returnType().getClassLoader().loadClass(ShadowWindow.class.getName()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return lookup.in(type.returnType()).findStatic(shadowWindowClass, "create", type); } }
public CallSite bootstrap(Class<?> cl) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { ClassLoader classLoader = cl.getClassLoader(); ClassLoader bootstrapCL = classLoader; Class<?> bootstrapClass = Class.forName(getBootstrap().methodClass().replace('/', '.'), false, bootstrapCL); MethodType bt = makeMethodType( bootstrapCL, bootstrap.methodType()); Method bootstrap = bootstrapClass.getMethod(this.bootstrap.methodName(), bt.parameterList().toArray(new Class[ bt.parameterCount() ])); Object[] args = new Object[ bt.parameterCount() ]; Lookup myLookup = MethodHandles.lookup().in(cl); Field impl_lookup = Lookup.class.getDeclaredField("IMPL_LOOKUP"); // get the required field via reflections impl_lookup.setAccessible(true); // set it accessible Lookup lutrusted = (Lookup) impl_lookup.get(myLookup); // get the value of IMPL_LOOKUP from the Lookup instance and save it in a new Lookup object args[0] = lutrusted; args[1] = getMethodName(); args[2] = makeMethodType(classLoader, getMethodSignature()); for(int i = 3; i < bt.parameterCount(); i++) { args[i] = getBootstrap().callArgument(bootstrapCL,i-3); } bootstrap.setAccessible(true); System.err.println(cl + " : " + bootstrap); return (CallSite) bootstrap.invoke(null, args); }
@Nullable @Override public Object invoke(@Nonnull Object proxy, @Nonnull Method method, @Nullable Object[] args) throws Throwable { for (MethodHandler methodHandler : methodHandlers) { if (methodHandler.canHandle(method)) { return methodHandler.handle(proxy, method, args); } } if (areDefaultMethodsSupported) { if (method.isDefault()) { MethodHandle methodHandle = MethodHandles.lookup() .in(method.getDeclaringClass()) .unreflectSpecial(method, method.getDeclaringClass()) .bindTo(proxy); if (null == args) { return methodHandle.invoke(); } else { return methodHandle.invoke(args); } } } throw new UnsupportedOperationException(method.toString()); }
@Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if (VersionFinder.JAVA_MAJOR_VERSION == 8) { final Constructor<Lookup> constructor = Lookup.class .getDeclaredConstructor(Class.class); constructor.setAccessible(true); constructor.newInstance(cls).in(cls).unreflectSpecial(method, cls).bindTo(proxy) .invokeWithArguments(); } else { // N.B. in testing, this didn't work... MethodHandles .lookup().findSpecial(cls, methodName, MethodType.methodType(returnType, new Class[0]), cls) .bindTo(proxy).invokeWithArguments(); } return null; } });
public CallSite bootstrap(Class<?> cl) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { ClassLoader classLoader = cl.getClassLoader(); ClassLoader bootstrapCL = classLoader; Class<?> bootstrapClass = Class.forName(getBootstrap().methodClass().replace('/', '.'), false, bootstrapCL); MethodType bt = makeMethodType( bootstrapCL, bootstrap.methodType()); Method bootstrap = bootstrapClass.getMethod(this.bootstrap.methodName(), bt.parameterList().toArray(new Class[ bt.parameterCount() ])); Object[] args = new Object[ bt.parameterCount() ]; Lookup myLookup = MethodHandles.lookup().in(cl); Field impl_lookup = Lookup.class.getDeclaredField("IMPL_LOOKUP"); // get the required field via reflections impl_lookup.setAccessible(true); // set it accessible Lookup lutrusted = (Lookup) impl_lookup.get(myLookup); // get the value of IMPL_LOOKUP from the Lookup instance and save it in a new Lookup object args[0] = lutrusted; args[1] = getMethodName(); args[2] = makeMethodType(classLoader, getMethodSignature()); for(int i = 3; i < bt.parameterCount(); i++) { args[i] = getBootstrap().callArgument(bootstrapCL,i-3); } bootstrap.setAccessible(true); System.err.println(cl + " : " + bootstrap); return (CallSite) bootstrap.invoke(null, args); }
@Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if (VersionFinder.JAVA_MAJOR_VERSION == 8) { final Constructor<Lookup> constructor = Lookup.class .getDeclaredConstructor(Class.class); constructor.setAccessible(true); constructor.newInstance(cls).in(cls).unreflectSpecial(method, cls).bindTo(proxy) .invokeWithArguments(); } else { // N.B. in testing, this didn't work... MethodHandles .lookup().findSpecial(cls, methodName, MethodType.methodType(returnType, new Class[0]), cls) .bindTo(proxy).invokeWithArguments(); } return null; } });
private static MethodHandle lookupSpecial(Method method) { final Class<?> declaringClass = method.getDeclaringClass(); MethodHandles.Lookup lookup = MethodHandles.publicLookup() .in(declaringClass); return tryReflection(() -> { final Field f = MethodHandles.Lookup.class.getDeclaredField("allowedModes"); final int modifiers = f.getModifiers(); if (Modifier.isFinal(modifiers)) { final Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(f, modifiers & ~Modifier.FINAL); f.setAccessible(true); f.set(lookup, MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE); } return lookup.unreflectSpecial(method, declaringClass); }); }
public static MethodHandles.Lookup of(final Class<?> declaringClass) { try { if (PRIVATE_LOOKUP != null) { return MethodHandles.Lookup.class .cast(PRIVATE_LOOKUP.invoke(null, declaringClass, MethodHandles.lookup())); } return LOOKUP.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE).in(declaringClass); } catch (final IllegalAccessException | InstantiationException e) { throw new IllegalArgumentException(e); } catch (final InvocationTargetException e) { throw toRuntimeException(e); } } }
private static MethodHandle getNativeMethodHandle(Class<?> lookupClass, String methodName) { MethodLookup lookup = new MethodLookup(MethodHandles.publicLookup().in(lookupClass)); Method m = findMethod(lookup, methodName); if (m == null) { return null; } MethodHandle mh; try { mh = lookup.getLookup().unreflect(m); } catch (IllegalAccessException e) { throw new IllegalArgumentException(); } return adaptNativeMethodHandle(mh); }
public static <T> T createLambda(Method method, MethodHandles.Lookup lookup, Class<T> interfaceClass, String signatatureName, boolean createSpecial) throws Throwable { if (method.isAccessible()){ lookup = lookup.in(method.getDeclaringClass()); setAccessible(lookup); } return privateCreateLambda(method, lookup, interfaceClass, signatatureName, createSpecial); }
@SuppressWarnings("WeakerAccess") MethodHandle methodHandleForProxy(Object proxy, Method m) { try { Class<?> declaringClass = m.getDeclaringClass(); final MethodHandles.Lookup lookup = PRIVATE_LOOKUP.get(declaringClass); return lookup .in(declaringClass) .unreflectSpecial(m, declaringClass) .bindTo(proxy); } catch (IllegalAccessException e) { throw new AssertionError(e); } }
private static <T> T create(Method method, Class<T> interfaceClass, String signatureName, boolean invokeSpecial) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup().in(method.getDeclaringClass()); setAccessible(lookup); return createLambda(method, lookup, interfaceClass, signatureName, invokeSpecial); }
@SuppressWarnings("WeakerAccess") MethodHandle methodHandleForProxy(Object proxy, Method m) { try { Class<?> declaringClass = m.getDeclaringClass(); final MethodHandles.Lookup lookup = PRIVATE_LOOKUP.get(declaringClass); return lookup .in(declaringClass) .unreflectSpecial(m, declaringClass) .bindTo(proxy); } catch (IllegalAccessException e) { throw new AssertionError(e); } }
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable { Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class .getDeclaredConstructor(Class.class); constructor.setAccessible(true); return constructor.newInstance(method.getDeclaringClass()) .in(method.getDeclaringClass()) .unreflectSpecial(method, method.getDeclaringClass()) .bindTo(proxy) .invokeWithArguments(args); } }
static Object getFallback(Method fallbackMethod, ExecutionContextWithInvocationContext ctx) throws IllegalAccessException, InstantiationException, IllegalArgumentException, InvocationTargetException, Throwable { // This should work in Java 8 Class<?> declaringClazz = fallbackMethod.getDeclaringClass(); Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class); constructor.setAccessible(true); return constructor.newInstance(declaringClazz).in(declaringClazz).unreflectSpecial(fallbackMethod, declaringClazz).bindTo(ctx.getTarget()) .invokeWithArguments(ctx.getParameters()); }
@SuppressWarnings("unchecked") public static <T> T createLambda(Object instance, Method instanceMethod, Class<?> functionalIntfCls) { try { Lookup lookup = LOOKUP.in(instanceMethod.getDeclaringClass()); allowedModesField.set(lookup, ALL_MODES); Method intfMethod = findAbstractMethod(functionalIntfCls); MethodHandle methodHandle = lookup.unreflect(instanceMethod); MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes()); MethodType instanceMethodType = MethodType .methodType(instanceMethod.getReturnType(), instanceMethod.getParameterTypes()); CallSite callSite = LambdaMetafactory.metafactory( lookup, intfMethod.getName(), MethodType.methodType(functionalIntfCls, instance.getClass()), intfMethodType, methodHandle, instanceMethodType); return (T) callSite.getTarget().bindTo(instance).invoke(); } catch (Throwable e) { throw new IllegalStateException("Failed to create lambda from " + instanceMethod, e); } }
@SuppressWarnings("unchecked") public static <T> T createLambda(Method instanceMethod, Class<?> functionalIntfCls) { try { Lookup lookup = LOOKUP.in(instanceMethod.getDeclaringClass()); allowedModesField.set(lookup, ALL_MODES); Method intfMethod = findAbstractMethod(functionalIntfCls); MethodHandle methodHandle = lookup.unreflect(instanceMethod); MethodType intfMethodType = MethodType.methodType(intfMethod.getReturnType(), intfMethod.getParameterTypes()); MethodType instanceMethodType = methodHandle.type(); CallSite callSite = LambdaMetafactory.metafactory( lookup, intfMethod.getName(), MethodType.methodType(functionalIntfCls), intfMethodType, methodHandle, instanceMethodType); return (T) callSite.getTarget().invoke(); } catch (Throwable e) { throw new IllegalStateException("Failed to create lambda from " + instanceMethod, e); } }
import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ReflectiveDefaultMethodCallExample { static interface Hello { default String hello() { return "Hello"; } } public static void main(String[] args) throws Throwable{ Hello target = //new Hello(){}; (Hello)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{Hello.class}, (Object proxy, Method method, Object[] arguments) -> null); Method method = Hello.class.getMethod("hello"); Object result = MethodHandles.lookup() .in(method.getDeclaringClass()) .unreflectSpecial(method,method.getDeclaringClass()) .bindTo(target) .invokeWithArguments(); System.out.println(result); //Hello } }