package railo.runtime.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import railo.commons.lang.StringUtil; import railo.runtime.exp.PageException; import railo.runtime.op.Caster; import railo.runtime.reflection.pairs.ConstructorParameterPair; import railo.runtime.reflection.pairs.MethodParameterPair; import railo.runtime.type.ObjectWrap; /** * To invoke a Object on different ways */ public final class Invoker { private static Method[] lastMethods; private static Class lastClass; /** * @param clazz * @param parameters * @return new Instance * @throws NoSuchMethodException * @throws IllegalArgumentException * @throws InstantiationException * @throws IllegalAccessException * @throws InvocationTargetException */ public static Object newInstance(Class clazz, Object[] parameters) throws NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { ConstructorParameterPair pair= getConstructorParameterPairIgnoreCase(clazz, parameters); return pair.getConstructor().newInstance(pair.getParameters()); } /** * search the matching constructor to defined parameter list, also translate parameters for matching * @param clazz class to get constructo from * @param parameters parameter for the constructor * @return Constructor parameter pair * @throws NoSuchMethodException */ public static ConstructorParameterPair getConstructorParameterPairIgnoreCase(Class clazz, Object[] parameters) throws NoSuchMethodException { // set all values //Class objectClass=object.getClass(); if(parameters==null)parameters=new Object[0]; // set parameter classes Class[] parameterClasses=new Class[parameters.length]; for(int i=0;i<parameters.length;i++) { parameterClasses[i]=parameters[i].getClass(); } // search right method Constructor[] constructor=clazz.getConstructors(); for(int mode=0;mode<2;mode++) { outer: for(int i=0;i<constructor.length;i++) { Constructor c=constructor[i]; Class[] paramTrg=c.getParameterTypes(); // Same Parameter count if(parameterClasses.length==paramTrg.length) { for(int y=0;y<parameterClasses.length;y++) { if(mode==0 && parameterClasses[y]!=primitiveToWrapperType(paramTrg[y])) { continue outer; } else if(mode==1) { Object o=compareClasses(parameters[y], paramTrg[y]); if(o==null)continue outer; parameters[y]=o; parameterClasses[y]=o.getClass(); } } return new ConstructorParameterPair(c,parameters); } } } // Exeception String parameter=""; for(int i=0;i<parameterClasses.length;i++) { if(i!=0) parameter+=", "; parameter+=parameterClasses[i].getName(); } throw new NoSuchMethodException("class constructor "+clazz.getName()+"("+parameter+") doesn't exist"); } /** * call of a method from given object * @param object object to call method from * @param methodName name of the method to call * @param parameters parameter for method * @return return value of the method * @throws SecurityException * @throws NoSuchMethodException * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static Object callMethod(Object object, String methodName, Object[] parameters) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { MethodParameterPair pair= getMethodParameterPairIgnoreCase(object.getClass(), methodName, parameters); return pair.getMethod().invoke(object,pair.getParameters()); } /** * search the matching method to defined Method Name, also translate parameters for matching * @param objectClass class object where searching method from * @param methodName name of the method to search * @param parameters whished parameter list * @return pair with method matching and parameterlist matching * @throws NoSuchMethodException */ public static MethodParameterPair getMethodParameterPairIgnoreCase(Class objectClass, String methodName, Object[] parameters) throws NoSuchMethodException { // set all values if(parameters==null)parameters=new Object[0]; // set parameter classes Class[] parameterClasses=new Class[parameters.length]; for(int i=0;i<parameters.length;i++) { parameterClasses[i]=parameters[i].getClass(); } // search right method Method[] methods=null; if(lastClass!=null && lastClass.equals(objectClass)) { methods=lastMethods; } else { methods=objectClass.getDeclaredMethods(); } lastClass=objectClass; lastMethods=methods; //Method[] methods=objectClass.getMethods(); //Method[] methods=objectClass.getDeclaredMethods(); //methods=objectClass.getDeclaredMethods(); for(int mode=0;mode<2;mode++) { outer: for(int i=0;i<methods.length;i++) { Method method=methods[i]; // Same Name if(method.getName().equalsIgnoreCase(methodName)) { Class[] paramTrg=method.getParameterTypes(); // Same Parameter count if(parameterClasses.length==paramTrg.length) { //if(parameterClasses.length==0)return m; for(int y=0;y<parameterClasses.length;y++) { if(mode==0 && parameterClasses[y]!=primitiveToWrapperType(paramTrg[y])) { continue outer; } else if(mode==1) { Object o=compareClasses(parameters[y], paramTrg[y]); if(o==null) { continue outer; } parameters[y]=o; parameterClasses[y]=o.getClass(); } //if(parameterClasses.length-1==y) return m; } return new MethodParameterPair(method,parameters); } } } } // Exeception String parameter=""; for(int i=0;i<parameterClasses.length;i++) { if(i!=0) parameter+=", "; parameter+=parameterClasses[i].getName(); } throw new NoSuchMethodException("method "+methodName+"("+parameter+") doesn't exist in class "+objectClass.getName()); } /** * compare parameter with whished parameter class and convert parameter to whished type * @param parameter parameter to compare * @param trgClass whished type of the parameter * @return converted parameter (to whished type) or null */ private static Object compareClasses(Object parameter, Class trgClass) { Class srcClass=parameter.getClass(); trgClass=primitiveToWrapperType(trgClass); try { if(parameter instanceof ObjectWrap) parameter=((ObjectWrap)parameter).getEmbededObject(); // parameter is already ok if(srcClass==trgClass) return parameter; else if (instaceOf(srcClass,trgClass)) { return parameter; } else if (trgClass.getName().equals("java.lang.String")) { return Caster.toString(parameter); } else if (trgClass.getName().equals("java.lang.Boolean")) { return Caster.toBoolean(parameter); } else if (trgClass.getName().equals("java.lang.Byte")) { return new Byte( Caster.toString(parameter)); } else if (trgClass.getName().equals("java.lang.Character")) { String str = Caster.toString(parameter); if(str.length()==1) return new Character(str.toCharArray()[0]); return null; } else if (trgClass.getName().equals("java.lang.Short")) { return Short.valueOf((short) Caster.toIntValue(parameter)); } else if (trgClass.getName().equals("java.lang.Integer")) { return Integer.valueOf(Caster.toIntValue(parameter)); } else if (trgClass.getName().equals("java.lang.Long")) { return Long.valueOf((long)Caster.toDoubleValue(parameter)); } else if (trgClass.getName().equals("java.lang.Float")) { return Float.valueOf((float)Caster.toDoubleValue(parameter)); } else if (trgClass.getName().equals("java.lang.Double")) { return Caster.toDouble(parameter); } } catch (PageException e) { return null; } return null; } /** * @param srcClass * @param trgClass * @return is instance of or not */ private static boolean instaceOf(Class srcClass, Class trgClass) { while(srcClass!=null) { if(srcClass==trgClass) return true; srcClass=primitiveToWrapperType(srcClass.getSuperclass()); } return false; } /** * cast a primitive type class definition to his object reference type * @param clazz class object to check and convert if it is of primitive type * @return object reference class object */ private static Class primitiveToWrapperType(Class clazz) { // boolean, byte, char, short, int, long, float, and double if(clazz==null) return null; else if(clazz.isPrimitive()) { if(clazz.getName().equals("boolean"))return Boolean.class; else if(clazz.getName().equals("byte"))return Byte.class; else if(clazz.getName().equals("char"))return Character.class; else if(clazz.getName().equals("short"))return Short.class; else if(clazz.getName().equals("int"))return Integer.class; else if(clazz.getName().equals("long"))return Long.class; else if(clazz.getName().equals("float"))return Float.class; else if(clazz.getName().equals("double"))return Double.class; } return clazz; } /** * to invoke a getter Method of a Object * @param o Object to invoke method from * @param prop Name of the Method without get * @return return Value of the getter Method * @throws SecurityException * @throws NoSuchMethodException * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static Object callGetter(Object o, String prop) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { prop="get"+prop; Class c=o.getClass(); Method m=getMethodParameterPairIgnoreCase(c, prop, null).getMethod(); //Method m=getMethodIgnoreCase(c,prop,null); if(m.getReturnType().getName().equals("void")) throw new NoSuchMethodException("invalid return Type, method ["+m.getName()+"] can't have return type void"); return m.invoke(o,null); } /** * to invoke a setter Method of a Object * @param o Object to invoke method from * @param prop Name of the Method without get * @param value Value to set to the Method * @throws SecurityException * @throws NoSuchMethodException * @throws IllegalArgumentException * @throws IllegalAccessException * @throws InvocationTargetException */ public static void callSetter(Object o, String prop,Object value) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { prop="set"+StringUtil.ucFirst(prop); Class c=o.getClass(); //Class[] cArg=new Class[]{value.getClass()}; Object[] oArg=new Object[]{value}; MethodParameterPair mp = getMethodParameterPairIgnoreCase(c, prop, oArg); //Method m=getMethodIgnoreCase(c,prop,cArg); if(!mp.getMethod().getReturnType().getName().equals("void")) throw new NoSuchMethodException("invalid return Type, method ["+mp.getMethod().getName()+"] must have return type void, now ["+mp.getMethod().getReturnType().getName()+"]"); mp.getMethod().invoke(o,mp.getParameters()); } /** * to get a visible Property of a object * @param o Object to invoke * @param prop property to call * @return property value * @throws NoSuchFieldException * @throws IllegalArgumentException * @throws IllegalAccessException */ public static Object getProperty(Object o, String prop) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { Field f=getFieldIgnoreCase(o.getClass(),prop); return f.get(o); } /** * assign a value to a visible property of a object * @param o Object to assign value to his property * @param prop name of property * @param value Value to assign * @throws IllegalArgumentException * @throws IllegalAccessException * @throws NoSuchFieldException */ public static void setProperty(Object o, String prop,Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException { getFieldIgnoreCase(o.getClass(),prop).set(o,value); } /** * same like method getField from Class but ignore case from field name * @param c class to search the field * @param name name to search * @return Matching Field * @throws NoSuchFieldException */ public static Field getFieldIgnoreCase(Class c, String name) throws NoSuchFieldException { Field[] fields=c.getFields(); for(int i=0;i<fields.length;i++) { Field f=fields[i]; // Same Name if(f.getName().equalsIgnoreCase(name)) { return f; } } throw new NoSuchFieldException("Field doesn't exist"); } /** * call of a static method of a Class * @param staticClass class how contains method to invoke * @param methodName method name to invoke * @param values Arguments for the Method * @return return value from method * @throws PageException */ public static Object callStaticMethod(Class staticClass, String methodName, Object[] values) throws PageException { if(values==null)values=new Object[0]; MethodParameterPair mp; try { mp = getMethodParameterPairIgnoreCase(staticClass, methodName, values); } catch (NoSuchMethodException e) { throw Caster.toPageException(e); } try { return mp.getMethod().invoke(null,mp.getParameters()); } catch (InvocationTargetException e) { Throwable target = e.getTargetException(); if(target instanceof PageException) throw (PageException)target; throw Caster.toPageException(e.getTargetException()); } catch (Exception e) { throw Caster.toPageException(e); } } }