001 package railo.runtime.reflection; 002 003 import java.lang.reflect.Constructor; 004 import java.lang.reflect.Field; 005 import java.lang.reflect.InvocationTargetException; 006 import java.lang.reflect.Method; 007 008 import railo.commons.lang.StringUtil; 009 import railo.runtime.exp.PageException; 010 import railo.runtime.op.Caster; 011 import railo.runtime.reflection.pairs.ConstructorParameterPair; 012 import railo.runtime.reflection.pairs.MethodParameterPair; 013 import railo.runtime.type.ObjectWrap; 014 015 /** 016 * To invoke a Object on different ways 017 */ 018 public final class Invoker { 019 020 private static Method[] lastMethods; 021 private static Class lastClass; 022 023 024 /** 025 * @param clazz 026 * @param parameters 027 * @return new Instance 028 * @throws NoSuchMethodException 029 * @throws IllegalArgumentException 030 * @throws InstantiationException 031 * @throws IllegalAccessException 032 * @throws InvocationTargetException 033 */ 034 public static Object newInstance(Class clazz, Object[] parameters) throws NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { 035 ConstructorParameterPair pair= 036 getConstructorParameterPairIgnoreCase(clazz, parameters); 037 return pair.getConstructor().newInstance(pair.getParameters()); 038 } 039 040 041 /** 042 * search the matching constructor to defined parameter list, also translate parameters for matching 043 * @param clazz class to get constructo from 044 * @param parameters parameter for the constructor 045 * @return Constructor parameter pair 046 * @throws NoSuchMethodException 047 */ 048 public static ConstructorParameterPair getConstructorParameterPairIgnoreCase(Class clazz, Object[] parameters) throws NoSuchMethodException { 049 // set all values 050 //Class objectClass=object.getClass(); 051 if(parameters==null)parameters=new Object[0]; 052 053 // set parameter classes 054 Class[] parameterClasses=new Class[parameters.length]; 055 for(int i=0;i<parameters.length;i++) { 056 parameterClasses[i]=parameters[i].getClass(); 057 } 058 059 // search right method 060 Constructor[] constructor=clazz.getConstructors(); 061 for(int mode=0;mode<2;mode++) { 062 outer: for(int i=0;i<constructor.length;i++) { 063 Constructor c=constructor[i]; 064 065 066 Class[] paramTrg=c.getParameterTypes(); 067 // Same Parameter count 068 if(parameterClasses.length==paramTrg.length) { 069 for(int y=0;y<parameterClasses.length;y++) { 070 if(mode==0 && parameterClasses[y]!=primitiveToWrapperType(paramTrg[y])) { 071 continue outer; 072 } 073 else if(mode==1) { 074 Object o=compareClasses(parameters[y], paramTrg[y]); 075 if(o==null)continue outer; 076 077 parameters[y]=o; 078 parameterClasses[y]=o.getClass(); 079 080 } 081 } 082 return new ConstructorParameterPair(c,parameters); 083 } 084 085 } 086 } 087 088 // Exeception 089 String parameter=""; 090 for(int i=0;i<parameterClasses.length;i++) { 091 if(i!=0) parameter+=", "; 092 parameter+=parameterClasses[i].getName(); 093 } 094 throw new NoSuchMethodException("class constructor "+clazz.getName()+"("+parameter+") doesn't exist"); 095 } 096 097 098 099 100 /** 101 * call of a method from given object 102 * @param object object to call method from 103 * @param methodName name of the method to call 104 * @param parameters parameter for method 105 * @return return value of the method 106 * @throws SecurityException 107 * @throws NoSuchMethodException 108 * @throws IllegalArgumentException 109 * @throws IllegalAccessException 110 * @throws InvocationTargetException 111 */ 112 public static Object callMethod(Object object, String methodName, Object[] parameters) throws NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { 113 MethodParameterPair pair= 114 getMethodParameterPairIgnoreCase(object.getClass(), methodName, parameters); 115 116 117 return pair.getMethod().invoke(object,pair.getParameters()); 118 } 119 120 /** 121 * search the matching method to defined Method Name, also translate parameters for matching 122 * @param objectClass class object where searching method from 123 * @param methodName name of the method to search 124 * @param parameters whished parameter list 125 * @return pair with method matching and parameterlist matching 126 * @throws NoSuchMethodException 127 */ 128 public static MethodParameterPair getMethodParameterPairIgnoreCase(Class objectClass, String methodName, Object[] parameters) throws NoSuchMethodException { 129 // set all values 130 if(parameters==null)parameters=new Object[0]; 131 132 // set parameter classes 133 Class[] parameterClasses=new Class[parameters.length]; 134 for(int i=0;i<parameters.length;i++) { 135 parameterClasses[i]=parameters[i].getClass(); 136 } 137 138 // search right method 139 Method[] methods=null; 140 141 if(lastClass!=null && lastClass.equals(objectClass)) { 142 methods=lastMethods; 143 } 144 else { 145 methods=objectClass.getDeclaredMethods(); 146 } 147 148 lastClass=objectClass; 149 lastMethods=methods; 150 //Method[] methods=objectClass.getMethods(); 151 //Method[] methods=objectClass.getDeclaredMethods(); 152 153 //methods=objectClass.getDeclaredMethods(); 154 for(int mode=0;mode<2;mode++) { 155 outer: for(int i=0;i<methods.length;i++) { 156 Method method=methods[i]; 157 // Same Name 158 if(method.getName().equalsIgnoreCase(methodName)) { 159 Class[] paramTrg=method.getParameterTypes(); 160 // Same Parameter count 161 if(parameterClasses.length==paramTrg.length) { 162 //if(parameterClasses.length==0)return m; 163 for(int y=0;y<parameterClasses.length;y++) { 164 165 if(mode==0 && parameterClasses[y]!=primitiveToWrapperType(paramTrg[y])) { 166 continue outer; 167 } 168 else if(mode==1) { 169 Object o=compareClasses(parameters[y], paramTrg[y]); 170 171 if(o==null) { 172 continue outer; 173 } 174 parameters[y]=o; 175 parameterClasses[y]=o.getClass(); 176 177 } 178 //if(parameterClasses.length-1==y) return m; 179 } 180 181 return new MethodParameterPair(method,parameters); 182 } 183 } 184 } 185 } 186 187 // Exeception 188 String parameter=""; 189 for(int i=0;i<parameterClasses.length;i++) { 190 if(i!=0) parameter+=", "; 191 parameter+=parameterClasses[i].getName(); 192 } 193 throw new NoSuchMethodException("method "+methodName+"("+parameter+") doesn't exist in class "+objectClass.getName()); 194 195 } 196 197 /** 198 * compare parameter with whished parameter class and convert parameter to whished type 199 * @param parameter parameter to compare 200 * @param trgClass whished type of the parameter 201 * @return converted parameter (to whished type) or null 202 */ 203 private static Object compareClasses(Object parameter, Class trgClass) { 204 Class srcClass=parameter.getClass(); 205 trgClass=primitiveToWrapperType(trgClass); 206 try { 207 if(parameter instanceof ObjectWrap) 208 parameter=((ObjectWrap)parameter).getEmbededObject(); 209 210 // parameter is already ok 211 212 if(srcClass==trgClass) return parameter; 213 214 else if (instaceOf(srcClass,trgClass)) { 215 return parameter; 216 } 217 else if (trgClass.getName().equals("java.lang.String")) { 218 return Caster.toString(parameter); 219 } 220 else if (trgClass.getName().equals("java.lang.Boolean")) { 221 return Caster.toBoolean(parameter); 222 } 223 else if (trgClass.getName().equals("java.lang.Byte")) { 224 return new Byte( Caster.toString(parameter)); 225 } 226 else if (trgClass.getName().equals("java.lang.Character")) { 227 String str = Caster.toString(parameter); 228 if(str.length()==1) return new Character(str.toCharArray()[0]); 229 return null; 230 } 231 else if (trgClass.getName().equals("java.lang.Short")) { 232 return Short.valueOf((short) Caster.toIntValue(parameter)); 233 } 234 else if (trgClass.getName().equals("java.lang.Integer")) { 235 return Integer.valueOf(Caster.toIntValue(parameter)); 236 } 237 else if (trgClass.getName().equals("java.lang.Long")) { 238 return Long.valueOf((long)Caster.toDoubleValue(parameter)); 239 } 240 else if (trgClass.getName().equals("java.lang.Float")) { 241 return Float.valueOf((float)Caster.toDoubleValue(parameter)); 242 } 243 else if (trgClass.getName().equals("java.lang.Double")) { 244 return Caster.toDouble(parameter); 245 } 246 } 247 catch (PageException e) { 248 return null; 249 } 250 251 return null; 252 } 253 254 /** 255 * @param srcClass 256 * @param trgClass 257 * @return is instance of or not 258 */ 259 private static boolean instaceOf(Class srcClass, Class trgClass) { 260 while(srcClass!=null) { 261 if(srcClass==trgClass) return true; 262 srcClass=primitiveToWrapperType(srcClass.getSuperclass()); 263 } 264 return false; 265 } 266 267 268 /** 269 * cast a primitive type class definition to his object reference type 270 * @param clazz class object to check and convert if it is of primitive type 271 * @return object reference class object 272 */ 273 private static Class primitiveToWrapperType(Class clazz) { 274 // boolean, byte, char, short, int, long, float, and double 275 if(clazz==null) return null; 276 else if(clazz.isPrimitive()) { 277 if(clazz.getName().equals("boolean"))return Boolean.class; 278 else if(clazz.getName().equals("byte"))return Byte.class; 279 else if(clazz.getName().equals("char"))return Character.class; 280 else if(clazz.getName().equals("short"))return Short.class; 281 else if(clazz.getName().equals("int"))return Integer.class; 282 else if(clazz.getName().equals("long"))return Long.class; 283 else if(clazz.getName().equals("float"))return Float.class; 284 else if(clazz.getName().equals("double"))return Double.class; 285 } 286 return clazz; 287 } 288 289 /** 290 * to invoke a getter Method of a Object 291 * @param o Object to invoke method from 292 * @param prop Name of the Method without get 293 * @return return Value of the getter Method 294 * @throws SecurityException 295 * @throws NoSuchMethodException 296 * @throws IllegalArgumentException 297 * @throws IllegalAccessException 298 * @throws InvocationTargetException 299 */ 300 public static Object callGetter(Object o, String prop) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { 301 prop="get"+prop; 302 Class c=o.getClass(); 303 Method m=getMethodParameterPairIgnoreCase(c, prop, null).getMethod(); 304 305 //Method m=getMethodIgnoreCase(c,prop,null); 306 if(m.getReturnType().getName().equals("void")) 307 throw new NoSuchMethodException("invalid return Type, method ["+m.getName()+"] can't have return type void"); 308 return m.invoke(o,null); 309 } 310 311 /** 312 * to invoke a setter Method of a Object 313 * @param o Object to invoke method from 314 * @param prop Name of the Method without get 315 * @param value Value to set to the Method 316 * @throws SecurityException 317 * @throws NoSuchMethodException 318 * @throws IllegalArgumentException 319 * @throws IllegalAccessException 320 * @throws InvocationTargetException 321 */ 322 public static void callSetter(Object o, String prop,Object value) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { 323 prop="set"+StringUtil.ucFirst(prop); 324 Class c=o.getClass(); 325 //Class[] cArg=new Class[]{value.getClass()}; 326 Object[] oArg=new Object[]{value}; 327 MethodParameterPair mp = getMethodParameterPairIgnoreCase(c, prop, oArg); 328 //Method m=getMethodIgnoreCase(c,prop,cArg); 329 if(!mp.getMethod().getReturnType().getName().equals("void")) 330 throw new NoSuchMethodException("invalid return Type, method ["+mp.getMethod().getName()+"] must have return type void, now ["+mp.getMethod().getReturnType().getName()+"]"); 331 mp.getMethod().invoke(o,mp.getParameters()); 332 } 333 334 /** 335 * to get a visible Property of a object 336 * @param o Object to invoke 337 * @param prop property to call 338 * @return property value 339 * @throws NoSuchFieldException 340 * @throws IllegalArgumentException 341 * @throws IllegalAccessException 342 */ 343 public static Object getProperty(Object o, String prop) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { 344 Field f=getFieldIgnoreCase(o.getClass(),prop); 345 return f.get(o); 346 } 347 348 /** 349 * assign a value to a visible property of a object 350 * @param o Object to assign value to his property 351 * @param prop name of property 352 * @param value Value to assign 353 * @throws IllegalArgumentException 354 * @throws IllegalAccessException 355 * @throws NoSuchFieldException 356 */ 357 public static void setProperty(Object o, String prop,Object value) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException { 358 getFieldIgnoreCase(o.getClass(),prop).set(o,value); 359 } 360 361 /** 362 * same like method getField from Class but ignore case from field name 363 * @param c class to search the field 364 * @param name name to search 365 * @return Matching Field 366 * @throws NoSuchFieldException 367 */ 368 public static Field getFieldIgnoreCase(Class c, String name) throws NoSuchFieldException { 369 Field[] fields=c.getFields(); 370 for(int i=0;i<fields.length;i++) { 371 Field f=fields[i]; 372 // Same Name 373 if(f.getName().equalsIgnoreCase(name)) { 374 return f; 375 } 376 } 377 throw new NoSuchFieldException("Field doesn't exist"); 378 } 379 380 /** 381 * call of a static method of a Class 382 * @param staticClass class how contains method to invoke 383 * @param methodName method name to invoke 384 * @param values Arguments for the Method 385 * @return return value from method 386 * @throws PageException 387 */ 388 public static Object callStaticMethod(Class staticClass, String methodName, Object[] values) throws PageException { 389 if(values==null)values=new Object[0]; 390 391 392 393 394 MethodParameterPair mp; 395 try { 396 mp = getMethodParameterPairIgnoreCase(staticClass, methodName, values); 397 } 398 catch (NoSuchMethodException e) { 399 throw Caster.toPageException(e); 400 } 401 402 try { 403 return mp.getMethod().invoke(null,mp.getParameters()); 404 } 405 catch (InvocationTargetException e) { 406 Throwable target = e.getTargetException(); 407 if(target instanceof PageException) throw (PageException)target; 408 throw Caster.toPageException(e.getTargetException()); 409 } 410 catch (Exception e) { 411 throw Caster.toPageException(e); 412 } 413 } 414 } 415