| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.myfaces.extensions.scripting.core.common.util; |
| |
| import org.apache.myfaces.extensions.scripting.core.api.WeavingContext; |
| |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * @author Werner Punz (latest modification by $Author$) |
| * @version $Revision$ $Date$ |
| */ |
| |
| public class ReflectUtil |
| { |
| |
| static final Logger _logger = Logger.getLogger(ReflectUtil.class.getName()); |
| |
| public static Object instantiate(String clazz, Object... varargs) |
| { |
| return instantiate(ClassUtils.forName(clazz), varargs); |
| } |
| |
| /** |
| * A simplified instantiation over reflection |
| * |
| * @param clazz the class to be instantiated |
| * @param varargs the instantiation parameters |
| * @return the instantiated object |
| */ |
| public static Object instantiate(Class clazz, Object... varargs) |
| { |
| Class[] classes = new Class[varargs.length]; |
| for (int cnt = 0; cnt < varargs.length; cnt++) |
| { |
| |
| if (varargs[cnt] instanceof Cast) |
| { |
| classes[cnt] = ((Cast) varargs[cnt]).getClazz(); |
| varargs[cnt] = ((Cast) varargs[cnt]).getValue(); |
| } else |
| { |
| classes[cnt] = varargs[cnt].getClass(); |
| } |
| } |
| |
| try |
| { |
| Constructor constr = clazz.getConstructor(classes); |
| return constr.newInstance(varargs); |
| } |
| catch (NoSuchMethodException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (InvocationTargetException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (IllegalAccessException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (InstantiationException e) |
| { |
| throw new RuntimeException(e); |
| } |
| }/*this is mostly just a helper to bypass a groovy bug in a more |
| * complex delegation environment. Groovy throws a classcast |
| * exception wrongly, delegating the instantiation code to java |
| * fixes that |
| * */ |
| |
| public static Object newObject(Class clazz) throws IllegalAccessException, InstantiationException |
| { |
| return clazz.newInstance(); |
| } |
| |
| /** |
| * Generic execute method which simplifies the reflection api |
| * down to a usable system |
| * |
| * @param obj the target object the method has to be executed upon |
| * @param methodName the method name |
| * @param varargs the arguments which have to be passed to the method |
| * @return the return value of the method |
| */ |
| public static Object executeStaticMethod(Class obj, String methodName, Object... varargs) |
| { |
| |
| Collection<Method> methods = getMethods(obj, methodName, varargs.length); |
| |
| Object retVal = handleStaticMethod(obj, methodName, methods, varargs); |
| if (!methodNotFound(retVal)) |
| { |
| return retVal; |
| } |
| |
| methods = getAllMethods(obj, methodName, varargs.length); |
| retVal = handleStaticMethod(obj, methodName, methods, varargs); |
| if (!methodNotFound(retVal)) |
| { |
| return retVal; |
| } |
| |
| throw new RuntimeException("Static Method of :" + methodName + " from class " + obj.getClass().getName() + " not found"); |
| |
| } |
| |
| public static void setField(Object obj, String fieldName, Object value, boolean protectedField) |
| { |
| try |
| { |
| Field f = null; |
| try |
| { |
| f = obj.getClass().getDeclaredField(fieldName); |
| } |
| catch (NoSuchFieldException e) |
| { |
| f = obj.getClass().getField(fieldName); |
| } |
| |
| f.setAccessible(protectedField); |
| f.set(obj, value); |
| |
| } |
| catch (NoSuchFieldException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (IllegalAccessException e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static Object getField(Object obj, String fieldName, boolean protectedField) |
| { |
| try |
| { |
| Field f = null; |
| try |
| { |
| f = obj.getClass().getDeclaredField(fieldName); |
| } |
| catch (NoSuchFieldException e) |
| { |
| f = obj.getClass().getField(fieldName); |
| } |
| f.setAccessible(protectedField); |
| return f.get(obj); |
| } |
| catch (NoSuchFieldException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (IllegalAccessException e) |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| public static Collection<Method> getAllMethods(Class clazz, String methodName, int varargLength) |
| { |
| ArrayList<Method> retVal = new ArrayList<Method>(30); |
| while (clazz != null) |
| { |
| for (Method m : clazz.getDeclaredMethods()) |
| { |
| if (m.getParameterTypes().length == varargLength && m.getName().equals(methodName)) |
| { |
| retVal.add(m); |
| } |
| } |
| clazz = clazz.getSuperclass(); |
| } |
| |
| return retVal; |
| } |
| |
| public static Collection<Method> getMethods(Class clazz, String methodName, int varargLength) |
| { |
| ArrayList<Method> retVal = new ArrayList<Method>(30); |
| for (Method m : clazz.getDeclaredMethods()) |
| { |
| if (m.getParameterTypes().length == varargLength && m.getName().equals(methodName)) |
| { |
| retVal.add(m); |
| } |
| } |
| |
| return retVal; |
| } |
| |
| /** |
| * Generic execute method which simplifies the reflection api |
| * down to a usable system |
| * |
| * @param obj the target object the method has to be executed upon |
| * @param methodName the method name |
| * @param varargs the arguments which have to be passed to the method |
| * @return the return value of the method |
| * @throws RuntimeException a generic runtime exception in case of a failure |
| * we use unmanaged exceptions here to get a behavior similar to scripting |
| * language execution where failures can happen but method executions |
| * should not enforce exception handling |
| */ |
| public static Object executeMethod(Object obj, String methodName, Object... varargs) |
| { |
| |
| Collection<Method> methods; |
| //if we have an invocationHandler here we |
| //can work over the generic invoke interface |
| //That way we can cover more dynamic stuff |
| //our reload invocation handler is treated differently here |
| |
| if (obj instanceof InvocationHandler) |
| { |
| InvocationHandler objToInvoke = (InvocationHandler) obj; |
| |
| Object realTarget = WeavingContext.getInstance().getDelegateFromProxy(objToInvoke); |
| |
| //first we try only the public because they are the most likely ones |
| //to be accessed |
| methods = getMethods(realTarget.getClass(), methodName, varargs.length); |
| Object retVal = handleInvHandlerMethod(objToInvoke, methodName, methods, varargs); |
| if (!methodNotFound(retVal)) |
| { |
| return retVal; |
| } |
| //if not we try all of them until we have a match |
| methods = getAllMethods(realTarget.getClass(), methodName, varargs.length); |
| retVal = handleInvHandlerMethod(objToInvoke, methodName, methods, varargs); |
| if (!(methodNotFound(retVal))) |
| { |
| return retVal; |
| } |
| |
| throw new RuntimeException("Method of :" + methodName + " from class " + obj.getClass().getName() + " not found"); |
| } |
| |
| Class clazz = obj.getClass(); |
| |
| //first we try only the public because they are the most likely ones |
| //to be accessed |
| methods = getMethods(clazz, methodName, varargs.length); |
| Object retVal = handleObjMethod(obj, methodName, methods, varargs); |
| if (!methodNotFound(retVal)) |
| { |
| return retVal; |
| } |
| |
| //if not we try all of them until we have a match |
| methods = getAllMethods(clazz, methodName, varargs.length); |
| retVal = handleObjMethod(obj, methodName, methods, varargs); |
| if (!methodNotFound(retVal)) |
| { |
| return retVal; |
| } |
| |
| throw new RuntimeException("Method of :" + methodName + " from class " + obj.getClass().getName() + " not found"); |
| } |
| |
| /** |
| * special marker class which is a special return value indicating |
| * that not method has been found which can be executed |
| */ |
| static class _MethodNotFound |
| { |
| } |
| |
| /** |
| * check if the return value is a method not found return val which |
| * indicates we have to follow the next workflow step |
| * |
| * @param retVal the retVal which has to be investigated |
| * @return true if the retVal is instance of _MethodNotFound false otherwise |
| */ |
| private static boolean methodNotFound(Object retVal) |
| { |
| return retVal instanceof _MethodNotFound; |
| } |
| |
| /** |
| * executes a method in an invocation handler with a set of |
| * methods which are canidates for execution |
| * |
| * @param objToInvoke the invokee object |
| * @param methodName the method name |
| * @param methods the methods which are under investigation for invoking |
| * @param varargs the list of varargs to be passed to the method |
| * @return the result of the invocation, or an object of type _MethodNotFound otherwise |
| */ |
| static private Object handleInvHandlerMethod(InvocationHandler objToInvoke, String methodName, Collection<Method> methods, Object... varargs) |
| { |
| for (Method m : methods) |
| { |
| if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) |
| { |
| continue; |
| } |
| try |
| { |
| return objToInvoke.invoke(objToInvoke, m, varargs); |
| } |
| catch (Throwable e) |
| { |
| handleException(e); |
| } |
| } |
| return new _MethodNotFound(); |
| } |
| |
| /** |
| * executes a method on an object |
| * |
| * @param objToInvoke the invokee object |
| * @param methodName the method name |
| * @param methods the methods which are under investigation for invoking |
| * @param varargs the list of varargs to be passed to the method |
| * @return the result of the invocation, or an object of type _MethodNotFound otherwise |
| */ |
| static private Object handleObjMethod(Object objToInvoke, String methodName, Collection<Method> methods, Object... varargs) |
| { |
| for (Method m : methods) |
| { |
| if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) |
| { |
| continue; |
| } |
| try |
| { |
| return m.invoke(objToInvoke, varargs); |
| } |
| catch (Throwable e) |
| { |
| handleException(e); |
| } |
| } |
| return new _MethodNotFound(); |
| } |
| |
| /** |
| * executes a static method on a class |
| * |
| * @param objToInvoke the invokee object |
| * @param methodName the method name |
| * @param methods the methods which are under investigation for invoking |
| * @param varargs the list of varargs to be passed to the method |
| * @return the result of the invocation, or an object of type _MethodNotFound otherwise |
| */ |
| static private Object handleStaticMethod(Class objToInvoke, String methodName, Collection<Method> methods, Object... varargs) |
| { |
| for (Method m : methods) |
| { |
| if (!m.getName().equals(methodName) || m.getParameterTypes().length != varargs.length) |
| { |
| continue; |
| } |
| try |
| { |
| return m.invoke(objToInvoke, varargs); |
| } |
| catch (Throwable e) |
| { |
| handleException(e); |
| } |
| } |
| return new _MethodNotFound(); |
| } |
| |
| private static void handleException(Throwable e) |
| { |
| if (e instanceof IllegalAccessException) |
| { |
| if (_logger.isLoggable(Level.FINEST)) |
| { |
| _logger.log(Level.FINEST, "", e); |
| } |
| } else if (e instanceof IllegalArgumentException) |
| { |
| if (_logger.isLoggable(Level.FINEST)) |
| { |
| _logger.log(Level.FINEST, "", e); |
| } |
| } else |
| { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * executes a function method on a target object |
| * |
| * @param obj the target object |
| * @param methodName the method name |
| * @param varargs a list of objects casts or nulls defining the parameter classes and its values |
| * if something occurs on introspection level an unmanaged exception is throw, just like |
| * it would happen in a scripting class |
| * @return the result object for the Method(method) call |
| * @throws RuntimeException an unmanaged runtime exception in case of an introspection error |
| */ |
| public static Object fastExecuteMethod(Object obj, String methodName, Object... varargs) |
| { |
| Class[] classes = new Class[varargs.length]; |
| for (int cnt = 0; cnt < varargs.length; cnt++) |
| { |
| |
| if (varargs[cnt] instanceof Cast) |
| { |
| classes[cnt] = ((Cast) varargs[cnt]).getClazz(); |
| varargs[cnt] = ((Cast) varargs[cnt]).getValue(); |
| } else |
| { |
| classes[cnt] = varargs[cnt].getClass(); |
| } |
| } |
| |
| try |
| { |
| Method m = fastGetMethod(obj, methodName, classes); |
| return m.invoke(obj, varargs); |
| } |
| catch (NoSuchMethodException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (InvocationTargetException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (IllegalAccessException e) |
| { |
| throw new RuntimeException(e); |
| } |
| |
| } |
| |
| /** |
| * faster reflection call |
| * if we know the data types exactly we can |
| * trigger a direct call instead of walking through all methods |
| * note this method only allows to trigger against directly declared methods |
| * it ignores the inheritance hierarchy for faster access |
| * |
| * @param obj the invokee object |
| * @param methodName the metod name |
| * @param classes the parameter type classes |
| * @return the method if found |
| * @throws NoSuchMethodException in case it could not be found |
| */ |
| public static Method fastGetMethod(Object obj, String methodName, Class[] classes) throws NoSuchMethodException |
| { |
| Method m; |
| try |
| { |
| m = obj.getClass().getDeclaredMethod(methodName, classes); |
| } |
| catch (NoSuchMethodException e) |
| { |
| m = obj.getClass().getMethod(methodName, classes); |
| } |
| return m; |
| } |
| |
| /** |
| * executes a function method on a target object |
| * |
| * @param obj the target object |
| * @param methodName the method name |
| * @param varargs a list of objects casts or nulls defining the parameter classes and its values |
| * if something occurs on introspection level an unmanaged exception is throw, just like |
| * it would happen in a scripting class |
| * @return the result object for the Method(method) call |
| * @throws RuntimeException an unmanaged runtime exception in case of an introspection error |
| */ |
| public static Object fastExecuteStaticMethod(Class obj, String methodName, Object... varargs) |
| { |
| Class[] classes = new Class[varargs.length]; |
| for (int cnt = 0; cnt < varargs.length; cnt++) |
| { |
| |
| if (varargs[cnt] instanceof Cast) |
| { |
| classes[cnt] = ((Cast) varargs[cnt]).getClazz(); |
| varargs[cnt] = ((Cast) varargs[cnt]).getValue(); |
| } else |
| { |
| classes[cnt] = varargs[cnt].getClass(); |
| } |
| } |
| |
| try |
| { |
| Method m = fastGetStaticMethod(obj, methodName, classes); |
| return m.invoke(obj, varargs); |
| } |
| catch (NoSuchMethodException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (InvocationTargetException e) |
| { |
| throw new RuntimeException(e); |
| } |
| catch (IllegalAccessException e) |
| { |
| throw new RuntimeException(e); |
| } |
| |
| } |
| |
| public static Method fastGetStaticMethod(Class obj, String methodName, Class[] classes) throws NoSuchMethodException |
| { |
| Method m; |
| try |
| { |
| m = obj.getDeclaredMethod(methodName, classes); |
| } |
| catch (NoSuchMethodException e) |
| { |
| m = obj.getMethod(methodName, classes); |
| } |
| return m; |
| } |
| |
| /** |
| * convenience method which makes the code a little bit more readable |
| * use it in conjunction with static imports |
| * |
| * @param clazz the cast target for the method call |
| * @param value the value object to be used as param |
| * @return a Cast object of the parameters |
| */ |
| public static Cast cast(Class clazz, Object value) |
| { |
| return new Cast(clazz, value); |
| } |
| |
| /** |
| * convenience method which makes the code a little bit more readable |
| * use it in conjunction with static imports |
| * |
| * @param clazz the cast target for the method call |
| * @return a null value Cast object of the parameters |
| */ |
| public static Null nullCast(Class clazz) |
| { |
| return new Null(clazz); |
| } |
| } |