1 package org.jicengine.operation; 2 3 import java.lang.reflect.InvocationTargetException ; 4 import java.lang.reflect.Method ; 5 import java.lang.reflect.Constructor ; 6 import java.lang.reflect.Field ; 7 import java.lang.reflect.Modifier ; 8 import java.util.Map ; 9 import java.util.HashMap ; 10 11 19 20 public class ReflectionUtils { 21 22 private static final String FIELD_CLASS = "class"; 23 24 28 protected static class NoSuchMethodException extends java.lang.NoSuchMethodException { 29 public NoSuchMethodException(Class actorClass, String methodName) 30 { 31 super("Class '" + actorClass.getName() + "' doesn't have a method '" + methodName + "'."); 32 } 33 } 34 35 41 protected static class NoMethodWithSuchParametersException extends java.lang.NoSuchMethodException { 42 public NoMethodWithSuchParametersException(Class actorClass, String methodName, Object [] arguments) 43 { 44 super("Class '" + actorClass.getName() + "' doesn't have a method '" + methodName + " accepting arguments (" + getArgumentTypeList(arguments) + ")"); 45 } 46 } 47 48 54 protected static class NoSuchConstructorException extends java.lang.NoSuchMethodException { 55 public NoSuchConstructorException(Class actorClass, Object [] arguments) 56 { 57 super("Class '" + actorClass.getName() + "' doesn't have constructor accepting arguments (" + getArgumentTypeList(arguments) + ")"); 58 } 59 } 60 61 private static Map objectTypesToPrimitiveTypes = new HashMap (); 62 private static Map primitiveTypesToObjectTypes = new HashMap (); 63 64 private static final int ASSIGNABILITY_DIFFERENT_PARAMETER_COUNTS = -1; 65 private static final int ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS = 0; 66 private static final int ASSIGNABILITY_EXACT_MATCH = 1; 67 68 78 public static boolean isAssignableFrom(Class class1, Class class2) 79 { 80 if( class1.isAssignableFrom(class2) ){ 81 return true; 82 } 83 else { 84 Class primitive = primitiveWrapperToPrimitiveType(class2); 85 if( primitive != null ){ 86 return class1.isAssignableFrom(primitive); 87 } 88 else { 89 return false; 90 } 91 } 92 } 93 94 95 public static void setFieldValue(Object instance, Class ownerClass, String fieldName, Object fieldValue) throws Exception  96 { 97 try { 98 Field field = ownerClass.getField(fieldName); 99 field.set(instance, fieldValue); 100 101 } catch(NoSuchFieldException e) { 102 throw new NoSuchFieldException ("Field '" + fieldName + "' not found in class '" + ownerClass.getName() + "'."); 104 } 105 } 106 107 114 public static Object getFieldValue(Object instance, Class ownerClass, String fieldName) throws Exception  115 { 116 if( instance == null && fieldName.equals(FIELD_CLASS) ){ 117 return ownerClass; 123 } 124 else { 125 try { 126 Field field = ownerClass.getField(fieldName); 127 return field.get(instance); 128 } catch(NoSuchFieldException e) { 129 throw new NoSuchFieldException ("Field '" + fieldName + "' not found in class '" + ownerClass.getName() + "'."); 131 } 132 } 133 } 134 135 protected static Class getActorClass(Object instanceOrClass) 136 { 137 if(instanceOrClass instanceof Class ) { 138 return (Class ) instanceOrClass; 139 } 140 else { 141 return instanceOrClass.getClass(); 142 } 143 } 144 145 178 private static int getParameterAssignabilityLevel(Class [] parameterTypes, Object [] parameters) 179 { 180 if(parameterTypes.length == parameters.length) { 181 183 int assignability = ASSIGNABILITY_EXACT_MATCH; 185 186 for(int i = 0; i < parameterTypes.length; i++) { 187 Class parameterType = parameterTypes[i]; 188 Object parameter = parameters[i]; 189 if(parameter == null) { 190 throw new IllegalArgumentException ("parameter " + (i + 1) + " was null."); 192 } 193 194 Class candidateType = parameter.getClass(); 195 196 if(parameterType.equals(candidateType)) { 197 assignability *= ASSIGNABILITY_EXACT_MATCH; 199 } 200 else if(parameterType.isAssignableFrom(candidateType)) { 201 assignability *= 2; 204 } 205 else if(parameterType.isPrimitive()) { 206 Class correspondingPrimitive = primitiveWrapperToPrimitiveType(candidateType); 208 209 if(correspondingPrimitive != null && correspondingPrimitive.equals(parameterType)) { 213 assignability *= ASSIGNABILITY_EXACT_MATCH; 215 } 216 else { 217 assignability *= ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS; 219 break; 220 } 221 } 222 else { 223 assignability *= ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS; 226 break; 227 } 228 } 229 230 return assignability; 231 } 232 else { 233 return ASSIGNABILITY_DIFFERENT_PARAMETER_COUNTS; 235 } 236 } 237 238 239 254 public static Object invokeMethod(Object actor, String methodName, Object [] arguments) throws java.lang.NoSuchMethodException , IllegalAccessException , IllegalArgumentException , InvocationTargetException  255 { 256 if(actor == null) { 257 throw new NullPointerException ("when calling method '" + methodName + "' (with " + arguments.length + " arguments)"); 258 } 259 else { 260 return invokeMethod(actor, actor.getClass(), methodName, arguments); 261 } 262 } 263 264 public static Object invokeStaticMethod(Class actorClass, String methodName, Object [] arguments) throws java.lang.NoSuchMethodException , IllegalAccessException , IllegalArgumentException , InvocationTargetException  265 { 266 if(actorClass == null) { 267 throw new NullPointerException ("when calling static method '" + methodName + "' (with " + arguments.length + " arguments)"); 268 } 269 else { 270 return invokeMethod(null, actorClass, methodName, arguments); 271 } 272 } 273 274 public static Object instantiate(Class instantiatedClass, Object [] arguments) throws java.lang.NoSuchMethodException , InstantiationException , IllegalAccessException , InvocationTargetException  275 { 276 Constructor constructor = findConstructor(instantiatedClass, arguments); 278 279 try { 281 return constructor.newInstance(arguments); 282 } catch(IllegalArgumentException e) { 283 throw new IllegalArgumentException ("Problems instantiating with constructor '" + constructor + "'"); 284 } 285 } 286 287 private static Constructor findConstructor(Class instantiatedClass, Object [] arguments) throws java.lang.NoSuchMethodException , InstantiationException , IllegalAccessException  288 { 289 Constructor [] constructors = instantiatedClass.getConstructors(); 290 Constructor match = null; 291 int parameterAssignability = ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS; 292 293 for(int i = 0; i < constructors.length; i++) { 294 Constructor candidate = constructors[i]; 295 Class [] parameterTypes = candidate.getParameterTypes(); 296 297 int candidateParameterAssignability = getParameterAssignabilityLevel(parameterTypes, arguments); 298 299 if(candidateParameterAssignability > ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS) { 300 302 if(candidateParameterAssignability == ASSIGNABILITY_EXACT_MATCH) { 303 match = candidate; 305 parameterAssignability = candidateParameterAssignability; 306 break; 307 } 308 else if(parameterAssignability < ASSIGNABILITY_EXACT_MATCH || candidateParameterAssignability < parameterAssignability) { 309 match = candidate; 314 parameterAssignability = candidateParameterAssignability; 315 continue; 316 } 317 } 318 } 319 320 if(match == null) { 321 throw new NoSuchConstructorException(instantiatedClass, arguments); 322 } 323 else { 324 return match; 325 } 326 } 327 328 334 protected static Class primitiveWrapperToPrimitiveType(Class objectClass) 335 { 336 return (Class ) objectTypesToPrimitiveTypes.get(objectClass); 337 } 338 339 343 protected static Class primitiveTypeToWrapperType(Class primitiveType) 344 { 345 return (Class ) primitiveTypesToObjectTypes.get(primitiveType); 346 } 347 348 353 protected static String getArgumentTypeList(Object [] arguments) 354 { 355 String paramString = ""; 356 for(int i = 0; i < arguments.length; i++) { 357 if(arguments[i] == null) { 358 paramString += "" + arguments[i]; 359 } 360 else { 361 paramString += arguments[i].getClass().getName(); 363 } 364 365 if((i + 1) < arguments.length) { 366 paramString += ","; 367 } 368 } 369 return paramString; 370 } 371 372 389 private static Object invokeMethod(Object actor, Class actorClass, String methodName, Object [] arguments) throws java.lang.NoSuchMethodException , IllegalAccessException , IllegalArgumentException , InvocationTargetException  390 { 391 if(methodName == null) { 393 throw new IllegalArgumentException ("Can't invoke a method: method name was null"); 394 } 395 if(arguments == null) { 396 throw new IllegalArgumentException ("Can't invoke a method: arguments[] was null"); 397 } 398 399 if(!Modifier.isPublic(actorClass.getModifiers())) { 400 throw new UnsupportedOperationException ("Class '" + actorClass.getName() + "' is private or protected. only public classes are supported currently."); 403 } 404 405 Method method; 406 407 try { 416 method = actorClass.getMethod(methodName, getTypes(arguments)); 417 } catch (java.lang.NoSuchMethodException e){ 418 method = findMethod(actorClass, methodName, arguments); 419 } 420 421 return method.invoke(actor, arguments); 425 } 426 427 private static Method findMethod(Class actorClass, String methodName, Object [] arguments) throws java.lang.NoSuchMethodException , IllegalAccessException , IllegalArgumentException , InvocationTargetException  428 { 429 Method [] methods = actorClass.getMethods(); 430 Method match = null; 431 int parameterAssignability = ASSIGNABILITY_DIFFERENT_PARAMETER_COUNTS; 432 boolean foundMethodWithTheSameName = false; 433 434 for(int i = 0; i < methods.length; i++) { 435 Method candidate = methods[i]; 436 if(candidate.getName().equals(methodName)) { 437 foundMethodWithTheSameName = true; 439 Class [] parameterTypes = candidate.getParameterTypes(); 440 441 int candidateParameterAssignability = getParameterAssignabilityLevel(parameterTypes, arguments); 442 443 if(candidateParameterAssignability > ASSIGNABILITY_NON_ASSIGNABLE_PARAMETERS) { 444 446 if(candidateParameterAssignability == ASSIGNABILITY_EXACT_MATCH) { 447 match = candidate; 449 parameterAssignability = candidateParameterAssignability; 450 break; 451 } 452 else if(parameterAssignability < ASSIGNABILITY_EXACT_MATCH || candidateParameterAssignability < parameterAssignability) { 453 458 461 match = candidate; 462 parameterAssignability = candidateParameterAssignability; 463 continue; 464 } 465 } 466 } 467 } 468 469 if(match == null) { 470 if(foundMethodWithTheSameName) { 472 throw new NoMethodWithSuchParametersException(actorClass, methodName, arguments); 473 } 474 else { 475 throw new ReflectionUtils.NoSuchMethodException(actorClass, methodName); 476 } 477 } 478 else { 479 return match; 480 } 481 } 482 483 protected static Class [] getTypes(Object [] parameters) 484 { 485 Class [] types = new Class [parameters.length]; 486 for (int i = 0; i < parameters.length; i++) { 487 types[i] = parameters[i].getClass(); 488 } 489 return types; 490 } 491 492 static { 493 objectTypesToPrimitiveTypes.put(Double .class, Double.TYPE); 494 objectTypesToPrimitiveTypes.put(Integer .class, Integer.TYPE); 495 objectTypesToPrimitiveTypes.put(Long .class, Long.TYPE); 496 objectTypesToPrimitiveTypes.put(Character .class, Character.TYPE); 497 objectTypesToPrimitiveTypes.put(Boolean .class, Boolean.TYPE); 498 objectTypesToPrimitiveTypes.put(Byte .class, Byte.TYPE); 499 objectTypesToPrimitiveTypes.put(Float .class, Float.TYPE); 500 objectTypesToPrimitiveTypes.put(Short .class, Short.TYPE); 501 502 primitiveTypesToObjectTypes.put(Double.TYPE, Double .class); 503 primitiveTypesToObjectTypes.put(Integer.TYPE, Integer .class); 504 primitiveTypesToObjectTypes.put(Long.TYPE, Long .class); 505 primitiveTypesToObjectTypes.put(Character.TYPE, Character .class); 506 primitiveTypesToObjectTypes.put(Boolean.TYPE, Boolean .class); 507 primitiveTypesToObjectTypes.put(Byte.TYPE, Byte .class); 508 primitiveTypesToObjectTypes.put(Float.TYPE, Float .class); 509 primitiveTypesToObjectTypes.put(Short.TYPE, Short .class); 510 511 } 512 } 513
| Popular Tags
|