1 16 package org.apache.commons.jxpath.util; 17 18 import java.beans.IndexedPropertyDescriptor ; 19 import java.beans.PropertyDescriptor ; 20 import java.lang.reflect.Array ; 21 import java.lang.reflect.InvocationTargetException ; 22 import java.lang.reflect.Method ; 23 import java.lang.reflect.Modifier ; 24 import java.util.ArrayList ; 25 import java.util.Collection ; 26 import java.util.Collections ; 27 import java.util.HashMap ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 32 import org.apache.commons.jxpath.Container; 33 import org.apache.commons.jxpath.DynamicPropertyHandler; 34 import org.apache.commons.jxpath.JXPathException; 35 36 42 public class ValueUtils { 43 private static Map dynamicPropertyHandlerMap = new HashMap (); 44 private static final int UNKNOWN_LENGTH_MAX_COUNT = 16000; 45 46 49 public static boolean isCollection(Object value) { 50 if (value == null) { 51 return false; 52 } 53 value = getValue(value); 54 if (value.getClass().isArray()) { 55 return true; 56 } 57 else if (value instanceof Collection ) { 58 return true; 59 } 60 return false; 61 } 62 63 68 public static int getCollectionHint(Class clazz) { 69 if (clazz.isArray()) { 70 return 1; 71 } 72 73 if (Collection .class.isAssignableFrom(clazz)) { 74 return 1; 75 } 76 77 if (clazz.isPrimitive()) { 78 return -1; 79 } 80 81 if (clazz.isInterface()) { 82 return 0; 83 } 84 85 if (Modifier.isFinal(clazz.getModifiers())) { 86 return -1; 87 } 88 89 return 0; 90 } 91 92 100 public static int getIndexedPropertyLength( 101 Object object, 102 IndexedPropertyDescriptor pd) 103 { 104 if (pd.getReadMethod() != null) { 105 return getLength(getValue(object, pd)); 106 } 107 108 Method readMethod = pd.getIndexedReadMethod(); 109 if (readMethod == null) { 110 throw new JXPathException( 111 "No indexed read method for property " + pd.getName()); 112 } 113 114 for (int i = 0; i < UNKNOWN_LENGTH_MAX_COUNT; i++) { 115 try { 116 readMethod.invoke(object, new Object [] { new Integer (i)}); 117 } 118 catch (Throwable t) { 119 return i; 120 } 121 } 122 123 throw new JXPathException( 124 "Cannot determine the length of the indexed property " 125 + pd.getName()); 126 } 127 128 132 public static int getLength(Object collection) { 133 if (collection == null) { 134 return 0; 135 } 136 collection = getValue(collection); 137 if (collection.getClass().isArray()) { 138 return Array.getLength(collection); 139 } 140 else if (collection instanceof Collection ) { 141 return ((Collection ) collection).size(); 142 } 143 else { 144 return 1; 145 } 146 } 147 148 153 public static Iterator iterate(Object collection) { 154 if (collection == null) { 155 return Collections.EMPTY_LIST.iterator(); 156 } 157 if (collection.getClass().isArray()) { 158 int length = Array.getLength(collection); 159 if (length == 0) { 160 return Collections.EMPTY_LIST.iterator(); 161 } 162 ArrayList list = new ArrayList (); 163 for (int i = 0; i < length; i++) { 164 list.add(Array.get(collection, i)); 165 } 166 return list.iterator(); 167 } 168 else if (collection instanceof Collection ) { 169 return ((Collection ) collection).iterator(); 170 } 171 else { 172 return Collections.singletonList(collection).iterator(); 173 } 174 } 175 176 180 public static Object expandCollection(Object collection, int size) { 181 if (collection == null) { 182 return null; 183 } 184 else if (collection.getClass().isArray()) { 185 Object bigger = 186 Array.newInstance( 187 collection.getClass().getComponentType(), 188 size); 189 System.arraycopy( 190 collection, 191 0, 192 bigger, 193 0, 194 Array.getLength(collection)); 195 return bigger; 196 } 197 else if (collection instanceof Collection ) { 198 while (((Collection ) collection).size() < size) { 199 ((Collection ) collection).add(null); 200 } 201 return collection; 202 } 203 else { 204 throw new JXPathException( 205 "Cannot turn " 206 + collection.getClass().getName() 207 + " into a collection of size " 208 + size); 209 } 210 } 211 212 215 public static Object remove(Object collection, int index) { 216 collection = getValue(collection); 217 if (collection == null) { 218 return null; 219 } 220 else if (collection.getClass().isArray()) { 221 int length = Array.getLength(collection); 222 Object smaller = 223 Array.newInstance( 224 collection.getClass().getComponentType(), 225 length - 1); 226 if (index > 0) { 227 System.arraycopy(collection, 0, smaller, 0, index); 228 } 229 if (index < length - 1) { 230 System.arraycopy( 231 collection, 232 index + 1, 233 smaller, 234 index, 235 length - index - 1); 236 } 237 return smaller; 238 } 239 else if (collection instanceof List ) { 240 int size = ((List ) collection).size(); 241 if (index < size) { 242 ((List ) collection).remove(index); 243 } 244 return collection; 245 } 246 else if (collection instanceof Collection ) { 247 Iterator it = ((Collection ) collection).iterator(); 248 for (int i = 0; i < index; i++) { 249 if (!it.hasNext()) { 250 break; 251 } 252 it.next(); 253 } 254 if (it.hasNext()) { 255 it.next(); 256 it.remove(); 257 } 258 return collection; 259 } 260 else { 261 throw new JXPathException( 262 "Cannot remove " 263 + collection.getClass().getName() 264 + "[" 265 + index 266 + "]"); 267 } 268 } 269 270 273 public static Object getValue(Object collection, int index) { 274 collection = getValue(collection); 275 Object value = collection; 276 if (collection != null) { 277 if (collection.getClass().isArray()) { 278 if (index < 0 || index >= Array.getLength(collection)) { 279 return null; 280 } 281 value = Array.get(collection, index); 282 } 283 else if (collection instanceof List ) { 284 if (index < 0 || index >= ((List ) collection).size()) { 285 return null; 286 } 287 value = ((List ) collection).get(index); 288 } 289 else if (collection instanceof Collection ) { 290 int i = 0; 291 Iterator it = ((Collection ) collection).iterator(); 292 for (; i < index; i++) { 293 it.next(); 294 } 295 if (it.hasNext()) { 296 value = it.next(); 297 } 298 else { 299 value = null; 300 } 301 } 302 } 303 return value; 304 } 305 306 310 public static void setValue(Object collection, int index, Object value) { 311 collection = getValue(collection); 312 if (collection != null) { 313 if (collection.getClass().isArray()) { 314 Array.set( 315 collection, 316 index, 317 convert(value, collection.getClass().getComponentType())); 318 } 319 else if (collection instanceof List ) { 320 ((List ) collection).set(index, value); 321 } 322 else if (collection instanceof Collection ) { 323 throw new UnsupportedOperationException ( 324 "Cannot set value of an element of a " 325 + collection.getClass().getName()); 326 } 327 } 328 } 329 330 334 public static Object getValue( 335 Object bean, 336 PropertyDescriptor propertyDescriptor) 337 { 338 Object value; 339 try { 340 Method method = 341 getAccessibleMethod(propertyDescriptor.getReadMethod()); 342 if (method == null) { 343 throw new JXPathException("No read method"); 344 } 345 value = method.invoke(bean, new Object [0]); 346 } 347 catch (Exception ex) { 348 throw new JXPathException( 349 "Cannot access property: " 350 + (bean == null ? "null" : bean.getClass().getName()) 351 + "." 352 + propertyDescriptor.getName(), 353 ex); 354 } 355 return value; 356 } 357 358 362 public static void setValue( 363 Object bean, 364 PropertyDescriptor propertyDescriptor, 365 Object value) 366 { 367 try { 368 Method method = 369 getAccessibleMethod(propertyDescriptor.getWriteMethod()); 370 if (method == null) { 371 throw new JXPathException("No write method"); 372 } 373 value = convert(value, propertyDescriptor.getPropertyType()); 374 value = method.invoke(bean, new Object [] { value }); 375 } 376 catch (Exception ex) { 377 throw new JXPathException( 378 "Cannot modify property: " 379 + (bean == null ? "null" : bean.getClass().getName()) 380 + "." 381 + propertyDescriptor.getName(), 382 ex); 383 } 384 } 385 386 private static Object convert(Object value, Class type) { 387 try { 388 return TypeUtils.convert(value, type); 389 } 390 catch (Exception ex) { 391 throw new JXPathException( 392 "Cannot convert value of class " 393 + (value == null ? "null" : value.getClass().getName()) 394 + " to type " 395 + type, 396 ex); 397 } 398 } 399 400 404 public static Object getValue( 405 Object bean, 406 PropertyDescriptor propertyDescriptor, 407 int index) 408 { 409 if (propertyDescriptor instanceof IndexedPropertyDescriptor ) { 410 try { 411 IndexedPropertyDescriptor ipd = 412 (IndexedPropertyDescriptor ) propertyDescriptor; 413 Method method = ipd.getIndexedReadMethod(); 414 if (method != null) { 415 return method.invoke( 416 bean, 417 new Object [] { new Integer (index)}); 418 } 419 } 420 catch (InvocationTargetException ex) { 421 Throwable t = 422 ((InvocationTargetException ) ex).getTargetException(); 423 if (t instanceof ArrayIndexOutOfBoundsException ) { 424 return null; 425 } 426 427 throw new JXPathException( 428 "Cannot access property: " + propertyDescriptor.getName(), 429 t); 430 } 431 catch (Throwable ex) { 432 throw new JXPathException( 433 "Cannot access property: " + propertyDescriptor.getName(), 434 ex); 435 } 436 } 437 438 440 return getValue(getValue(bean, propertyDescriptor), index); 441 } 442 443 448 public static void setValue( 449 Object bean, 450 PropertyDescriptor propertyDescriptor, 451 int index, 452 Object value) 453 { 454 if (propertyDescriptor instanceof IndexedPropertyDescriptor ) { 455 try { 456 IndexedPropertyDescriptor ipd = 457 (IndexedPropertyDescriptor ) propertyDescriptor; 458 Method method = ipd.getIndexedWriteMethod(); 459 if (method != null) { 460 method.invoke( 461 bean, 462 new Object [] { 463 new Integer (index), 464 convert(value, ipd.getIndexedPropertyType())}); 465 return; 466 } 467 } 468 catch (Exception ex) { 469 throw new RuntimeException ( 470 "Cannot access property: " 471 + propertyDescriptor.getName() 472 + ", " 473 + ex.getMessage()); 474 } 475 } 476 Object collection = getValue(bean, propertyDescriptor); 478 if (isCollection(collection)) { 479 setValue(collection, index, value); 480 } 481 else if (index == 0) { 482 setValue(bean, propertyDescriptor, value); 483 } 484 else { 485 throw new RuntimeException ( 486 "Not a collection: " + propertyDescriptor.getName()); 487 } 488 } 489 490 494 public static Object getValue(Object object) { 495 while (object instanceof Container) { 496 object = ((Container) object).getValue(); 497 } 498 return object; 499 } 500 501 505 public static DynamicPropertyHandler getDynamicPropertyHandler(Class clazz) 506 { 507 DynamicPropertyHandler handler = 508 (DynamicPropertyHandler) dynamicPropertyHandlerMap.get(clazz); 509 if (handler == null) { 510 try { 511 handler = (DynamicPropertyHandler) clazz.newInstance(); 512 } 513 catch (Exception ex) { 514 throw new JXPathException( 515 "Cannot allocate dynamic property handler of class " 516 + clazz.getName(), 517 ex); 518 } 519 dynamicPropertyHandlerMap.put(clazz, handler); 520 } 521 return handler; 522 } 523 524 531 538 public static Method getAccessibleMethod(Method method) { 539 540 if (method == null) { 542 return (null); 543 } 544 545 if (!Modifier.isPublic(method.getModifiers())) { 547 return (null); 548 } 549 550 Class clazz = method.getDeclaringClass(); 552 if (Modifier.isPublic(clazz.getModifiers())) { 553 return (method); 554 } 555 556 method = 558 getAccessibleMethodFromInterfaceNest( 559 clazz, 560 method.getName(), 561 method.getParameterTypes()); 562 return (method); 563 } 564 565 566 576 private static Method getAccessibleMethodFromInterfaceNest( 577 Class clazz, 578 String methodName, 579 Class parameterTypes[]) 580 { 581 582 Method method = null; 583 584 Class interfaces[] = clazz.getInterfaces(); 586 for (int i = 0; i < interfaces.length; i++) { 587 588 if (!Modifier.isPublic(interfaces[i].getModifiers())) { 590 continue; 591 } 592 593 try { 595 method = 596 interfaces[i].getDeclaredMethod(methodName, parameterTypes); 597 } 598 catch (NoSuchMethodException e) { 599 ; 600 } 601 if (method != null) { 602 break; 603 } 604 605 method = 607 getAccessibleMethodFromInterfaceNest( 608 interfaces[i], 609 methodName, 610 parameterTypes); 611 if (method != null) { 612 break; 613 } 614 } 615 616 return (method); 618 } 619 } | Popular Tags |