001package org.jadira.reflection.access.invokedynamic;
002
003import java.lang.invoke.CallSite;
004import java.lang.invoke.MethodHandle;
005import java.lang.invoke.MethodType;
006import java.lang.reflect.Method;
007
008import org.dynalang.dynalink.DefaultBootstrapper;
009import org.jadira.reflection.access.api.MethodAccess;
010
011public class InvokeDynamicMethodAccess<C> implements MethodAccess<C> {
012
013        private String methodName;
014        
015        private Method method;
016        private Class<C> declaringClass;
017        private Class<?> returnType;
018
019        CallSite methodCallSite;
020        
021        MethodHandle mh;
022        
023        @SuppressWarnings("unchecked")
024        private InvokeDynamicMethodAccess(Method m) {
025                
026                this.methodName = m.getName();
027                
028                this.declaringClass = (Class<C>) m.getDeclaringClass(); 
029                this.method = m;
030
031                this.returnType = (Class<?>) m.getReturnType();
032                
033                methodCallSite = DefaultBootstrapper.publicBootstrap(null, "dyn:getMethod:" + methodName, MethodType.methodType(returnType, declaringClass, method.getParameterTypes()));       
034                mh = methodCallSite.dynamicInvoker();           
035        }
036        
037        public static <C> InvokeDynamicMethodAccess<C> get(Method m) {
038                
039                return new InvokeDynamicMethodAccess<C>(m);
040        }
041        
042        @Override
043        public Class<C> declaringClass() {
044                return declaringClass;
045        }
046
047        @Override
048        public Class<?> returnClass() {
049                return returnType;
050        }
051
052        @Override
053        public Method method() {
054                return method;
055        }
056        
057        @Override
058        public Object invoke(Object target, Object... args) throws IllegalArgumentException {
059                
060            try {
061            return mh.invokeExact(target, args);
062        } catch (Throwable e) {
063            throw new IllegalArgumentException("Problem invoking {" + method.getName() + "} of object {"
064                    + System.identityHashCode(target) + "}: " + e.getMessage(), e);
065        }
066        }
067}