java.lang.reflect.Proxy and default methods - via MethodHandles

Peter Levart peter.levart at marand.si
Mon Sep 10 10:20:39 PDT 2012


A nice way for InvocationHandler to access super default methods on interfaces implemented by dynamic proxy class could be to add new (default) method to InvocationHandler:


public interface InvocationHandler
{
    void init(MethodHandles.Lookup proxyLookup) default {}

    Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}


 ...this default method is a no-op, but can be overriden by new implementations.

Now imagine we have the following interface:

    public interface A
    {
        void m() default
        {
            ...
        }
    }


For this interface we would like to create a dynamic proxy that would be equivalent to the following class:

    class Aimpl implements A
    {
        public void m()
        {
            System.out.println("before");
            A.super.m();
            System.out.println("after");
        }
    }


The InvocationHandler implementation for such dynamic proxy could look like this:

    class Ahandler implements InvocationHandler
    {
        private MethodHandle superA_m;

        @Override
        public void init(MethodHandles.Lookup proxyLookup)
        {
            try
            {
                superA_m = proxyLookup.findSpecial(A.class, "m", MethodType.methodType(void.class, new Class[0]), proxyLookup.lookupClass());
            }
            catch (NoSuchMethodException | IllegalAccessException e)
            {
                throw new AssertionError(e.getMessage(), e);
            }
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
        {
            System.out.println("before");
            superA_m.invoke((A)proxy);
            System.out.println("after");
            return null;
        }
    }


I was about to implement such experimental proxy factory, but unfortunately the MethodHandles.Lookup.findSpecial() is not taking into account yet the fact that interfaces can have non-abstract methods, as it throws:

Caused by: java.lang.IllegalAccessException: caller class must be a subclass below the method: defaultmeth.Test$A.m()void, from class defaultmeth.Test$Aproxy
	at java.lang.invoke.MemberName.makeAccessException(MemberName.java:507)
	at java.lang.invoke.MethodHandles$Lookup.restrictReceiver(MethodHandles.java:1228)
	at java.lang.invoke.MethodHandles$Lookup.accessSpecial(MethodHandles.java:758)
	at java.lang.invoke.MethodHandles$Lookup.findSpecial(MethodHandles.java:752)

...although Aproxy is a class implementing interface A...

Maybe also a kind of "resolveSpecial" method is needed on Lookup to simplify the search for super method on an interface...


Regards, Peter




More information about the lambda-dev mailing list