/********************************************************************* Copyright 2014 the Flapi authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ********************************************************************/ package unquietcode.tools.flapi.runtime; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; public final class Helpers { private Helpers() { } @SuppressWarnings("unchecked") public static <T> T beanProxyHelper(Class<T> helper, final Object bean) { if (!helper.isInterface()) { throw new IllegalArgumentException("only helper interfaces are allowed"); } return (T) Proxy.newProxyInstance(helper.getClassLoader(), new Class[]{helper}, new InvocationHandler() { private final Map<String, Method> methodMap = new HashMap<String, Method>(); public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { OriginalMethod originalMethod = method.getAnnotation(OriginalMethod.class); final String actualMethodName; // is it a transformed method? if (originalMethod != null) { // check if it is the final generated method first if (originalMethod.value().equals(OriginalMethod.DEFAULT_NONE)) { return bean; } // use the original method name actualMethodName = originalMethod.value(); } else { // use the current method name by default actualMethodName = method.getName(); } // look up the method Method actualMethod = getMethod(actualMethodName, method.getParameterTypes()); return actualMethod.invoke(bean, args); } private Method getMethod(String methodName, Class[] parameterTypes) { Method actualMethod = methodMap.get(methodName); if (actualMethod != null) { return actualMethod; } // find the method try { actualMethod = bean.getClass().getMethod(methodName, parameterTypes); } catch (NoSuchMethodException ex) { // fail throw new IllegalStateException("method not found"); } methodMap.put(methodName, actualMethod); return actualMethod; } }); } public interface Invoker<In> { void call(AtomicReference<In> in); } public static <T> T invoke(Invoker<T> invoker) { AtomicReference<T> reference = new AtomicReference<>(); try { invoker.call(reference); } catch (Exception ex) { throw new RuntimeException(ex); } return reference.get(); } }