1 16 17 package org.springframework.beans; 18 19 import java.beans.PropertyDescriptor ; 20 import java.lang.reflect.Constructor ; 21 import java.lang.reflect.InvocationTargetException ; 22 import java.lang.reflect.Method ; 23 import java.lang.reflect.Modifier ; 24 import java.util.Arrays ; 25 import java.util.List ; 26 27 import org.springframework.util.Assert; 28 import org.springframework.util.ClassUtils; 29 import org.springframework.util.StringUtils; 30 31 42 public abstract class BeanUtils { 43 44 54 public static Object instantiateClass(Class clazz) throws BeanInstantiationException { 55 Assert.notNull(clazz, "Class must not be null"); 56 if (clazz.isInterface()) { 57 throw new BeanInstantiationException(clazz, "Specified class is an interface"); 58 } 59 try { 60 return instantiateClass(clazz.getDeclaredConstructor((Class []) null), null); 61 } 62 catch (NoSuchMethodException ex) { 63 throw new BeanInstantiationException(clazz, "No default constructor found", ex); 64 } 65 } 66 67 77 public static Object instantiateClass(Constructor ctor, Object [] args) throws BeanInstantiationException { 78 Assert.notNull(ctor, "Constructor must not be null"); 79 try { 80 if (!Modifier.isPublic(ctor.getModifiers()) || 81 !Modifier.isPublic(ctor.getDeclaringClass().getModifiers())) { 82 ctor.setAccessible(true); 83 } 84 return ctor.newInstance(args); 85 } 86 catch (InstantiationException ex) { 87 throw new BeanInstantiationException(ctor.getDeclaringClass(), 88 "Is it an abstract class?", ex); 89 } 90 catch (IllegalAccessException ex) { 91 throw new BeanInstantiationException(ctor.getDeclaringClass(), 92 "Has the class definition changed? Is the constructor accessible?", ex); 93 } 94 catch (IllegalArgumentException ex) { 95 throw new BeanInstantiationException(ctor.getDeclaringClass(), 96 "Illegal arguments for constructor", ex); 97 } 98 catch (InvocationTargetException ex) { 99 throw new BeanInstantiationException(ctor.getDeclaringClass(), 100 "Constructor threw exception", ex.getTargetException()); 101 } 102 } 103 104 118 public static Method findMethod(Class clazz, String methodName, Class [] paramTypes) { 119 try { 120 return clazz.getMethod(methodName, paramTypes); 121 } 122 catch (NoSuchMethodException ex) { 123 return findDeclaredMethod(clazz, methodName, paramTypes); 124 } 125 } 126 127 138 public static Method findDeclaredMethod(Class clazz, String methodName, Class [] paramTypes) { 139 try { 140 return clazz.getDeclaredMethod(methodName, paramTypes); 141 } 142 catch (NoSuchMethodException ex) { 143 if (clazz.getSuperclass() != null) { 144 return findDeclaredMethod(clazz.getSuperclass(), methodName, paramTypes); 145 } 146 return null; 147 } 148 } 149 150 165 public static Method findMethodWithMinimalParameters(Class clazz, String methodName) 166 throws IllegalArgumentException { 167 168 Method targetMethod = doFindMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName); 169 if (targetMethod == null) { 170 return findDeclaredMethodWithMinimalParameters(clazz, methodName); 171 } 172 return targetMethod; 173 } 174 175 187 public static Method findDeclaredMethodWithMinimalParameters(Class clazz, String methodName) 188 throws IllegalArgumentException { 189 190 Method targetMethod = doFindMethodWithMinimalParameters(clazz.getDeclaredMethods(), methodName); 191 if (targetMethod == null && clazz.getSuperclass() != null) { 192 return findDeclaredMethodWithMinimalParameters(clazz.getSuperclass(), methodName); 193 } 194 return targetMethod; 195 } 196 197 206 private static Method doFindMethodWithMinimalParameters(Method [] methods, String methodName) 207 throws IllegalArgumentException { 208 209 Method targetMethod = null; 210 int numMethodsFoundWithCurrentMinimumArgs = 0; 211 for (int i = 0; i < methods.length; i++) { 212 if (methods[i].getName().equals(methodName)) { 213 int numParams = methods[i].getParameterTypes().length; 214 if (targetMethod == null || 215 numParams < targetMethod.getParameterTypes().length) { 216 targetMethod = methods[i]; 217 numMethodsFoundWithCurrentMinimumArgs = 1; 218 } 219 else { 220 if (targetMethod.getParameterTypes().length == numParams) { 221 numMethodsFoundWithCurrentMinimumArgs++; 223 } 224 } 225 } 226 } 227 if (numMethodsFoundWithCurrentMinimumArgs > 1) { 228 throw new IllegalArgumentException ("Cannot resolve method '" + methodName + 229 "' to a unique method. Attempted to resolve to overloaded method with " + 230 "the least number of parameters, but there were " + 231 numMethodsFoundWithCurrentMinimumArgs + " candidates."); 232 } 233 return targetMethod; 234 } 235 236 251 public static Method resolveSignature(String signature, Class clazz) { 252 Assert.hasText(signature, "'signature' must not be empty"); 253 Assert.notNull(clazz, "Class must not be null"); 254 255 int firstParen = signature.indexOf("("); 256 int lastParen = signature.indexOf(")"); 257 258 if (firstParen > -1 && lastParen == -1) { 259 throw new IllegalArgumentException ("Invalid method signature '" + signature + 260 "': expected closing ')' for args list"); 261 } 262 else if (lastParen > -1 && firstParen == -1) { 263 throw new IllegalArgumentException ("Invalid method signature '" + signature + 264 "': expected opening '(' for args list"); 265 } 266 else if (firstParen == -1 && lastParen == -1) { 267 return findMethodWithMinimalParameters(clazz, signature); 268 } 269 else { 270 String methodName = signature.substring(0, firstParen); 271 String [] parameterTypeNames = 272 StringUtils.commaDelimitedListToStringArray(signature.substring(firstParen + 1, lastParen)); 273 Class [] parameterTypes = new Class [parameterTypeNames.length]; 274 for (int i = 0; i < parameterTypeNames.length; i++) { 275 String parameterTypeName = parameterTypeNames[i].trim(); 276 try { 277 parameterTypes[i] = ClassUtils.forName(parameterTypeName, clazz.getClassLoader()); 278 } 279 catch (Throwable ex) { 280 throw new IllegalArgumentException ("Invalid method signature: unable to resolve type [" + 281 parameterTypeName + "] for argument " + i + ". Root cause: " + ex); 282 } 283 } 284 return findMethod(clazz, methodName, parameterTypes); 285 } 286 } 287 288 289 295 public static PropertyDescriptor [] getPropertyDescriptors(Class clazz) throws BeansException { 296 CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); 297 return cr.getBeanInfo().getPropertyDescriptors(); 298 } 299 300 307 public static PropertyDescriptor getPropertyDescriptor(Class clazz, String propertyName) 308 throws BeansException { 309 310 CachedIntrospectionResults cr = CachedIntrospectionResults.forClass(clazz); 311 return cr.getPropertyDescriptor(propertyName); 312 } 313 314 322 public static PropertyDescriptor findPropertyForMethod(Method method) throws BeansException { 323 Assert.notNull(method, "Method must not be null"); 324 PropertyDescriptor [] pds = getPropertyDescriptors(method.getDeclaringClass()); 325 for (int i = 0; i < pds.length; i++) { 326 if (method.equals(pds[i].getReadMethod()) || method.equals(pds[i].getWriteMethod())) { 327 return pds[i]; 328 } 329 } 330 return null; 331 } 332 333 340 public static Class findPropertyType(String propertyName, Class [] beanClasses) { 341 if (beanClasses != null) { 342 for (int i = 0; i < beanClasses.length; i++) { 343 PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(beanClasses[i], propertyName); 344 if (pd != null) { 345 return pd.getPropertyType(); 346 } 347 } 348 } 349 return Object .class; 350 } 351 352 359 public static boolean isSimpleProperty(Class clazz) { 360 Assert.notNull(clazz, "Class must not be null"); 361 return clazz.isPrimitive() || ClassUtils.isPrimitiveArray(clazz) || 362 ClassUtils.isPrimitiveWrapper(clazz) || ClassUtils.isPrimitiveWrapperArray(clazz) || 363 clazz.equals(String .class) || clazz.equals(String [].class) || 364 clazz.equals(Class .class) || clazz.equals(Class [].class); 365 } 366 367 377 public static boolean isAssignable(Class targetType, Class valueType) { 378 return ClassUtils.isAssignable(targetType, valueType); 379 } 380 381 391 public static boolean isAssignable(Class type, Object value) { 392 return ClassUtils.isAssignableValue(type, value); 393 } 394 395 396 408 public static void copyProperties(Object source, Object target) throws BeansException { 409 copyProperties(source, target, null, null); 410 } 411 412 426 public static void copyProperties(Object source, Object target, Class editable) 427 throws BeansException { 428 429 copyProperties(source, target, editable, null); 430 } 431 432 446 public static void copyProperties(Object source, Object target, String [] ignoreProperties) 447 throws BeansException { 448 449 copyProperties(source, target, null, ignoreProperties); 450 } 451 452 464 private static void copyProperties(Object source, Object target, Class editable, String [] ignoreProperties) 465 throws BeansException { 466 467 Assert.notNull(source, "Source must not be null"); 468 Assert.notNull(target, "Target must not be null"); 469 470 Class actualEditable = target.getClass(); 471 if (editable != null) { 472 if (!editable.isInstance(target)) { 473 throw new IllegalArgumentException ("Target class [" + target.getClass().getName() + 474 "] not assignable to Editable class [" + editable.getName() + "]"); 475 } 476 actualEditable = editable; 477 } 478 PropertyDescriptor [] targetPds = getPropertyDescriptors(actualEditable); 479 List ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null; 480 481 for (int i = 0; i < targetPds.length; i++) { 482 PropertyDescriptor targetPd = targetPds[i]; 483 if (targetPd.getWriteMethod() != null && 484 (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) { 485 PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); 486 if (sourcePd != null && sourcePd.getReadMethod() != null) { 487 try { 488 Method readMethod = sourcePd.getReadMethod(); 489 if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { 490 readMethod.setAccessible(true); 491 } 492 Object value = readMethod.invoke(source, new Object [0]); 493 Method writeMethod = targetPd.getWriteMethod(); 494 if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { 495 writeMethod.setAccessible(true); 496 } 497 writeMethod.invoke(target, new Object [] {value}); 498 } 499 catch (Throwable ex) { 500 throw new FatalBeanException("Could not copy properties from source to target", ex); 501 } 502 } 503 } 504 } 505 } 506 507 } 508 | Popular Tags |