1 16 package org.apache.commons.beanutils; 17 18 import java.beans.BeanInfo ; 19 import java.beans.IntrospectionException ; 20 import java.beans.Introspector ; 21 import java.beans.PropertyDescriptor ; 22 import java.lang.reflect.Constructor ; 23 import java.lang.reflect.InvocationTargetException ; 24 import java.lang.reflect.Method ; 25 import java.util.AbstractMap ; 26 import java.util.AbstractSet ; 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.Set ; 32 33 import org.apache.commons.collections.list.UnmodifiableList; 34 import org.apache.commons.collections.keyvalue.AbstractMapEntry; 35 import org.apache.commons.collections.set.UnmodifiableSet; 36 import org.apache.commons.collections.Transformer; 37 38 50 public class BeanMap extends AbstractMap implements Cloneable { 51 52 private transient Object bean; 53 54 private transient HashMap readMethods = new HashMap (); 55 private transient HashMap writeMethods = new HashMap (); 56 private transient HashMap types = new HashMap (); 57 58 61 public static final Object [] NULL_ARGUMENTS = {}; 62 63 67 public static HashMap defaultTransformers = new HashMap (); 68 69 static { 70 defaultTransformers.put( 71 Boolean.TYPE, 72 new Transformer() { 73 public Object transform( Object input ) { 74 return Boolean.valueOf( input.toString() ); 75 } 76 } 77 ); 78 defaultTransformers.put( 79 Character.TYPE, 80 new Transformer() { 81 public Object transform( Object input ) { 82 return new Character ( input.toString().charAt( 0 ) ); 83 } 84 } 85 ); 86 defaultTransformers.put( 87 Byte.TYPE, 88 new Transformer() { 89 public Object transform( Object input ) { 90 return Byte.valueOf( input.toString() ); 91 } 92 } 93 ); 94 defaultTransformers.put( 95 Short.TYPE, 96 new Transformer() { 97 public Object transform( Object input ) { 98 return Short.valueOf( input.toString() ); 99 } 100 } 101 ); 102 defaultTransformers.put( 103 Integer.TYPE, 104 new Transformer() { 105 public Object transform( Object input ) { 106 return Integer.valueOf( input.toString() ); 107 } 108 } 109 ); 110 defaultTransformers.put( 111 Long.TYPE, 112 new Transformer() { 113 public Object transform( Object input ) { 114 return Long.valueOf( input.toString() ); 115 } 116 } 117 ); 118 defaultTransformers.put( 119 Float.TYPE, 120 new Transformer() { 121 public Object transform( Object input ) { 122 return Float.valueOf( input.toString() ); 123 } 124 } 125 ); 126 defaultTransformers.put( 127 Double.TYPE, 128 new Transformer() { 129 public Object transform( Object input ) { 130 return Double.valueOf( input.toString() ); 131 } 132 } 133 ); 134 } 135 136 137 140 143 public BeanMap() { 144 } 145 146 153 public BeanMap(Object bean) { 154 this.bean = bean; 155 initialise(); 156 } 157 158 161 165 public String toString() { 166 return "BeanMap<" + String.valueOf(bean) + ">"; 167 } 168 169 192 public Object clone() throws CloneNotSupportedException { 193 BeanMap newMap = (BeanMap)super.clone(); 194 195 if(bean == null) { 196 return newMap; 199 } 200 201 Object newBean = null; 202 Class beanClass = null; 203 try { 204 beanClass = bean.getClass(); 205 newBean = beanClass.newInstance(); 206 } catch (Exception e) { 207 throw new CloneNotSupportedException 209 ("Unable to instantiate the underlying bean \"" + 210 beanClass.getName() + "\": " + e); 211 } 212 213 try { 214 newMap.setBean(newBean); 215 } catch (Exception exception) { 216 throw new CloneNotSupportedException 217 ("Unable to set bean in the cloned bean map: " + 218 exception); 219 } 220 221 try { 222 Iterator readableKeys = readMethods.keySet().iterator(); 226 while(readableKeys.hasNext()) { 227 Object key = readableKeys.next(); 228 if(getWriteMethod(key) != null) { 229 newMap.put(key, get(key)); 230 } 231 } 232 } catch (Exception exception) { 233 throw new CloneNotSupportedException 234 ("Unable to copy bean values to cloned bean map: " + 235 exception); 236 } 237 238 return newMap; 239 } 240 241 247 public void putAllWriteable(BeanMap map) { 248 Iterator readableKeys = map.readMethods.keySet().iterator(); 249 while (readableKeys.hasNext()) { 250 Object key = readableKeys.next(); 251 if (getWriteMethod(key) != null) { 252 this.put(key, map.get(key)); 253 } 254 } 255 } 256 257 258 266 public void clear() { 267 if(bean == null) return; 268 269 Class beanClass = null; 270 try { 271 beanClass = bean.getClass(); 272 bean = beanClass.newInstance(); 273 } 274 catch (Exception e) { 275 throw new UnsupportedOperationException ( "Could not create new instance of class: " + beanClass ); 276 } 277 } 278 279 294 public boolean containsKey(Object name) { 295 Method method = getReadMethod(name); 296 return method != null; 297 } 298 299 307 public boolean containsValue(Object value) { 308 return super.containsValue(value); 310 } 311 312 327 public Object get(Object name) { 328 if ( bean != null ) { 329 Method method = getReadMethod( name ); 330 if ( method != null ) { 331 try { 332 return method.invoke( bean, NULL_ARGUMENTS ); 333 } 334 catch ( IllegalAccessException e ) { 335 logWarn( e ); 336 } 337 catch ( IllegalArgumentException e ) { 338 logWarn( e ); 339 } 340 catch ( InvocationTargetException e ) { 341 logWarn( e ); 342 } 343 catch ( NullPointerException e ) { 344 logWarn( e ); 345 } 346 } 347 } 348 return null; 349 } 350 351 362 public Object put(Object name, Object value) throws IllegalArgumentException , ClassCastException { 363 if ( bean != null ) { 364 Object oldValue = get( name ); 365 Method method = getWriteMethod( name ); 366 if ( method == null ) { 367 throw new IllegalArgumentException ( "The bean of type: "+ bean.getClass().getName() + " has no property called: " + name ); 368 } 369 try { 370 Object [] arguments = createWriteMethodArguments( method, value ); 371 method.invoke( bean, arguments ); 372 373 Object newValue = get( name ); 374 firePropertyChange( name, oldValue, newValue ); 375 } 376 catch ( InvocationTargetException e ) { 377 logInfo( e ); 378 throw new IllegalArgumentException ( e.getMessage() ); 379 } 380 catch ( IllegalAccessException e ) { 381 logInfo( e ); 382 throw new IllegalArgumentException ( e.getMessage() ); 383 } 384 return oldValue; 385 } 386 return null; 387 } 388 389 394 public int size() { 395 return readMethods.size(); 396 } 397 398 399 409 public Set keySet() { 410 return UnmodifiableSet.decorate(readMethods.keySet()); 411 } 412 413 420 public Set entrySet() { 421 return UnmodifiableSet.decorate(new AbstractSet () { 422 public Iterator iterator() { 423 return entryIterator(); 424 } 425 public int size() { 426 return BeanMap.this.readMethods.size(); 427 } 428 }); 429 } 430 431 437 public Collection values() { 438 ArrayList answer = new ArrayList ( readMethods.size() ); 439 for ( Iterator iter = valueIterator(); iter.hasNext(); ) { 440 answer.add( iter.next() ); 441 } 442 return UnmodifiableList.decorate(answer); 443 } 444 445 446 449 456 public Class getType(String name) { 457 return (Class ) types.get( name ); 458 } 459 460 467 public Iterator keyIterator() { 468 return readMethods.keySet().iterator(); 469 } 470 471 476 public Iterator valueIterator() { 477 final Iterator iter = keyIterator(); 478 return new Iterator () { 479 public boolean hasNext() { 480 return iter.hasNext(); 481 } 482 public Object next() { 483 Object key = iter.next(); 484 return get(key); 485 } 486 public void remove() { 487 throw new UnsupportedOperationException ( "remove() not supported for BeanMap" ); 488 } 489 }; 490 } 491 492 497 public Iterator entryIterator() { 498 final Iterator iter = keyIterator(); 499 return new Iterator () { 500 public boolean hasNext() { 501 return iter.hasNext(); 502 } 503 public Object next() { 504 Object key = iter.next(); 505 Object value = get(key); 506 return new Entry( BeanMap.this, key, value ); 507 } 508 public void remove() { 509 throw new UnsupportedOperationException ( "remove() not supported for BeanMap" ); 510 } 511 }; 512 } 513 514 515 518 524 public Object getBean() { 525 return bean; 526 } 527 528 534 public void setBean( Object newBean ) { 535 bean = newBean; 536 reinitialise(); 537 } 538 539 545 public Method getReadMethod(String name) { 546 return (Method ) readMethods.get(name); 547 } 548 549 555 public Method getWriteMethod(String name) { 556 return (Method ) writeMethods.get(name); 557 } 558 559 560 563 571 protected Method getReadMethod( Object name ) { 572 return (Method ) readMethods.get( name ); 573 } 574 575 583 protected Method getWriteMethod( Object name ) { 584 return (Method ) writeMethods.get( name ); 585 } 586 587 591 protected void reinitialise() { 592 readMethods.clear(); 593 writeMethods.clear(); 594 types.clear(); 595 initialise(); 596 } 597 598 private void initialise() { 599 if(getBean() == null) return; 600 601 Class beanClass = getBean().getClass(); 602 try { 603 BeanInfo beanInfo = Introspector.getBeanInfo( beanClass ); 605 PropertyDescriptor [] propertyDescriptors = beanInfo.getPropertyDescriptors(); 606 if ( propertyDescriptors != null ) { 607 for ( int i = 0; i < propertyDescriptors.length; i++ ) { 608 PropertyDescriptor propertyDescriptor = propertyDescriptors[i]; 609 if ( propertyDescriptor != null ) { 610 String name = propertyDescriptor.getName(); 611 Method readMethod = propertyDescriptor.getReadMethod(); 612 Method writeMethod = propertyDescriptor.getWriteMethod(); 613 Class aType = propertyDescriptor.getPropertyType(); 614 615 if ( readMethod != null ) { 616 readMethods.put( name, readMethod ); 617 } 618 if ( writeMethods != null ) { 619 writeMethods.put( name, writeMethod ); 620 } 621 types.put( name, aType ); 622 } 623 } 624 } 625 } 626 catch ( IntrospectionException e ) { 627 logWarn( e ); 628 } 629 } 630 631 640 protected void firePropertyChange( Object key, Object oldValue, Object newValue ) { 641 } 642 643 646 649 protected static class Entry extends AbstractMapEntry { 650 private BeanMap owner; 651 652 659 protected Entry( BeanMap owner, Object key, Object value ) { 660 super( key, value ); 661 this.owner = owner; 662 } 663 664 670 public Object setValue(Object value) { 671 Object key = getKey(); 672 Object oldValue = owner.get( key ); 673 674 owner.put( key, value ); 675 Object newValue = owner.get( key ); 676 super.setValue( newValue ); 677 return oldValue; 678 } 679 } 680 681 695 protected Object [] createWriteMethodArguments( Method method, Object value ) throws IllegalAccessException , ClassCastException { 696 try { 697 if ( value != null ) { 698 Class [] types = method.getParameterTypes(); 699 if ( types != null && types.length > 0 ) { 700 Class paramType = types[0]; 701 if ( ! paramType.isAssignableFrom( value.getClass() ) ) { 702 value = convertType( paramType, value ); 703 } 704 } 705 } 706 Object [] answer = { value }; 707 return answer; 708 } 709 catch ( InvocationTargetException e ) { 710 logInfo( e ); 711 throw new IllegalArgumentException ( e.getMessage() ); 712 } 713 catch ( InstantiationException e ) { 714 logInfo( e ); 715 throw new IllegalArgumentException ( e.getMessage() ); 716 } 717 } 718 719 750 protected Object convertType( Class newType, Object value ) 751 throws InstantiationException , IllegalAccessException , IllegalArgumentException , InvocationTargetException { 752 753 Class [] types = { value.getClass() }; 755 try { 756 Constructor constructor = newType.getConstructor( types ); 757 Object [] arguments = { value }; 758 return constructor.newInstance( arguments ); 759 } 760 catch ( NoSuchMethodException e ) { 761 Transformer transformer = getTypeTransformer( newType ); 763 if ( transformer != null ) { 764 return transformer.transform( value ); 765 } 766 return value; 767 } 768 } 769 770 777 protected Transformer getTypeTransformer( Class aType ) { 778 return (Transformer) defaultTransformers.get( aType ); 779 } 780 781 787 protected void logInfo(Exception ex) { 788 System.out.println( "INFO: Exception: " + ex ); 790 } 791 792 798 protected void logWarn(Exception ex) { 799 System.out.println( "WARN: Exception: " + ex ); 801 ex.printStackTrace(); 802 } 803 } 804 | Popular Tags |