@@ -0,0 +1,3220 @@
+package net.fushizen.invokedynamic.proxy;%0A%0Aimport org.junit.Test;%0A%0Aimport java.lang.invoke.*;%0Aimport java.lang.reflect.InvocationHandler;%0Aimport java.lang.reflect.Method;%0Aimport java.util.concurrent.CountDownLatch;%0A%0Aimport static org.junit.Assert.assertEquals;%0A%0A/**%0A * Example of how to implement the classic Java Proxy on top of invokedynamic-proxy%0A */%0Apublic class ProxyProxyTest %7B%0A    public interface Interface %7B%0A        public void foo();%0A        public void bar();%0A    %7D%0A%0A    public static abstract class ProxyBase %7B%0A        private InvocationHandler invocationHandler;%0A%0A        public void $$init(InvocationHandler handler) %7B%0A            this.invocationHandler = handler;%0A        %7D%0A%0A        public Object $$invoke(Method method, Object%5B%5D args) throws Throwable %7B%0A            return invocationHandler.invoke(this, method, args);%0A        %7D%0A    %7D%0A%0A    private static CallSite bindProxyCall(MethodHandles.Lookup lookup, String name, MethodType type, MethodHandle superMethod) throws Throwable %7B%0A        if (name.equals(%22$$init%22)) %7B%0A            return new ConstantCallSite(superMethod.asType(type));%0A        %7D%0A%0A        Class%3C?%3E proxyType = type.parameterType(0);%0A        Method m = findMethod(proxyType, name, type.dropParameterTypes(0, 1));%0A%0A        MethodHandle invoker = lookup.findSpecial(%0A                ProxyBase.class,%0A                %22$$invoke%22,%0A                MethodType.methodType(Object.class, Method.class, Object%5B%5D.class),%0A                proxyType%0A                );%0A        invoker = MethodHandles.insertArguments(invoker, 1, m);%0A        invoker = invoker.asVarargsCollector(Object%5B%5D.class);%0A        invoker = invoker.asType(type);%0A%0A        return new ConstantCallSite(invoker);%0A    %7D%0A%0A    private static Method findMethod(Class%3C?%3E proxyType, String name, MethodType type) throws Throwable %7B%0A        try %7B%0A            return proxyType.getMethod(name, type.parameterArray());%0A        %7D catch (NoSuchMethodException e) %7B%0A            // continue%0A        %7D%0A%0A        Method m;%0A        if (proxyType.getSuperclass() != null && proxyType != Object.class) %7B%0A            m = findMethod(proxyType.getSuperclass(), name, type);%0A            if (m != null) return m;%0A        %7D%0A%0A        for (Class%3C?%3E iface : proxyType.getInterfaces()) %7B%0A            m = findMethod(iface, name, type);%0A            if (m != null) return m;%0A        %7D%0A%0A        return null;%0A    %7D%0A%0A    @Test%0A    public void testProxyInvocation() throws Exception %7B%0A        DynamicProxy proxy = DynamicProxy.builder()%0A                .withInterfaces(Interface.class)%0A                .withSuperclass(ProxyBase.class)%0A                .withInvocationHandler(ProxyProxyTest::bindProxyCall)%0A                .build();%0A        // Cache the proxy object! Constructing a new one is extremely expensive%0A%0A        CountDownLatch latch = new CountDownLatch(1);%0A        InvocationHandler handler = (proxyInstance, method, args) -%3E %7B%0A            if (!method.getName().equals(%22foo%22)) throw new UnsupportedOperationException();%0A            latch.countDown();%0A%0A            return null;%0A        %7D;%0A%0A        Interface obj = (Interface)proxy.supplier().get();%0A        ((ProxyBase)obj).$$init(handler);%0A%0A        obj.foo();%0A%0A        assertEquals(0, latch.getCount());%0A    %7D%0A%7D%0A

Add a demo implementing Proxy on top of invokedynamic-proxy