1 22 23 24 package com.mchange.v2.beans; 25 26 import java.beans.*; 27 import java.lang.reflect.*; 28 import java.util.*; 29 import com.mchange.v2.log.*; 30 31 import com.mchange.v2.lang.Coerce; 32 33 public final class BeansUtils 34 { 35 final static MLogger logger = MLog.getLogger( BeansUtils.class ); 36 37 final static Object [] EMPTY_ARGS = new Object [0]; 38 39 public static PropertyEditor findPropertyEditor( PropertyDescriptor pd ) 40 { 41 PropertyEditor out = null; 42 Class editorClass = null; 43 try 44 { 45 editorClass = pd.getPropertyEditorClass(); 46 if (editorClass != null) 47 out = (PropertyEditor) editorClass.newInstance(); 48 } 49 catch (Exception e) 50 { 51 if (logger.isLoggable( MLevel.WARNING ) ) 55 logger.log(MLevel.WARNING, "Bad property editor class " + editorClass.getName() + " registered for property " + pd.getName(), e); 56 } 57 58 if ( out == null ) 59 out = PropertyEditorManager.findEditor( pd.getPropertyType() ); 60 return out; 61 } 62 63 public static boolean equalsByAccessibleProperties( Object bean0, Object bean1 ) 64 throws IntrospectionException 65 { return equalsByAccessibleProperties( bean0, bean1, Collections.EMPTY_SET ); } 66 67 public static boolean equalsByAccessibleProperties( Object bean0, Object bean1, Collection ignoreProps ) 68 throws IntrospectionException 69 { 70 Map m0 = new HashMap(); 71 Map m1 = new HashMap(); 72 extractAccessiblePropertiesToMap( m0, bean0, ignoreProps ); 73 extractAccessiblePropertiesToMap( m1, bean1, ignoreProps ); 74 return m0.equals(m1); 77 } 78 79 public static void overwriteAccessibleProperties( Object sourceBean, Object destBean ) 80 throws IntrospectionException 81 { overwriteAccessibleProperties( sourceBean, destBean, Collections.EMPTY_SET ); } 82 83 public static void overwriteAccessibleProperties( Object sourceBean, Object destBean, Collection ignoreProps ) 84 throws IntrospectionException 85 { 86 try 87 { 88 BeanInfo beanInfo = Introspector.getBeanInfo( sourceBean.getClass(), Object .class ); PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); 90 for( int i = 0, len = pds.length; i < len; ++i) 91 { 92 PropertyDescriptor pd = pds[i]; 93 if ( ignoreProps.contains( pd.getName() ) ) 94 continue; 95 96 Method getter = pd.getReadMethod(); 97 Method setter = pd.getWriteMethod(); 98 99 if ( getter == null || setter == null ) 100 { 101 if ( pd instanceof IndexedPropertyDescriptor ) 102 { 103 109 if ( logger.isLoggable( MLevel.WARNING ) ) 110 logger.warning("BeansUtils.overwriteAccessibleProperties() does not" + 111 " support indexed properties that do not provide single-valued" + 112 " array getters and setters! [The indexed methods provide no means" + 113 " of modifying the size of the array in the destination bean if" + 114 " it does not match the source.]"); 115 } 116 117 if (logger.isLoggable( MLevel.INFO )) 119 logger.info("Property inaccessible for overwriting: " + pd.getName()); 120 } 121 else 122 { 123 Object value = getter.invoke( sourceBean, EMPTY_ARGS ); 124 setter.invoke( destBean, new Object [] { value } ); 125 } 126 } 127 } 128 catch ( IntrospectionException e ) 129 { throw e; } 130 catch ( Exception e ) 131 { 132 if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED && logger.isLoggable( MLevel.FINE )) 134 logger.log( MLevel.FINE, "Converting exception to throwable IntrospectionException" ); 135 136 throw new IntrospectionException( e.getMessage() ); 137 } 138 } 139 140 public static void overwriteAccessiblePropertiesFromMap( Map sourceMap, Object destBean, boolean skip_nulls ) 141 throws IntrospectionException 142 { overwriteAccessiblePropertiesFromMap( sourceMap, destBean, skip_nulls, Collections.EMPTY_SET ); } 143 144 public static void overwriteAccessiblePropertiesFromMap( Map sourceMap, Object destBean, boolean skip_nulls, Collection ignoreProps ) 145 throws IntrospectionException 146 { 147 overwriteAccessiblePropertiesFromMap( sourceMap, 148 destBean, 149 skip_nulls, 150 ignoreProps, 151 false, 152 MLevel.WARNING, 153 MLevel.WARNING, 154 true); 155 } 156 157 public static void overwriteAccessiblePropertiesFromMap( Map sourceMap, 158 Object destBean, 159 boolean skip_nulls, 160 Collection ignoreProps, 161 boolean coerce_strings, 162 MLevel cantWriteLevel, 163 MLevel cantCoerceLevel, 164 boolean die_on_one_prop_failure) 165 throws IntrospectionException 166 { 167 if (cantWriteLevel == null) 168 cantWriteLevel = MLevel.WARNING; 169 if (cantCoerceLevel == null) 170 cantCoerceLevel = MLevel.WARNING; 171 172 Set sourceMapProps = sourceMap.keySet(); 173 174 String propName = null; 175 BeanInfo beanInfo = Introspector.getBeanInfo( destBean.getClass(), Object .class ); PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); 177 for( int i = 0, len = pds.length; i < len; ++i) 179 { 180 PropertyDescriptor pd = pds[i]; 181 propName = pd.getName(); 182 183 if (! sourceMapProps.contains( propName )) 184 continue; 185 186 if ( ignoreProps != null && ignoreProps.contains( propName ) ) 187 { 188 continue; 190 } 191 194 Object propVal = sourceMap.get( propName ); 195 if (propVal == null) 196 { 197 if (skip_nulls) continue; 198 } 200 201 Method setter = pd.getWriteMethod(); 202 boolean rethrow = false; 203 204 Class propType = pd.getPropertyType();; 205 206 209 if ( setter == null ) 210 { 211 if ( pd instanceof IndexedPropertyDescriptor ) 212 { 213 if ( logger.isLoggable( MLevel.FINER ) ) 214 logger.finer("BeansUtils.overwriteAccessiblePropertiesFromMap() does not" + 215 " support indexed properties that do not provide single-valued" + 216 " array getters and setters! [The indexed methods provide no means" + 217 " of modifying the size of the array in the destination bean if" + 218 " it does not match the source.]"); 219 220 } 221 222 if ( logger.isLoggable( cantWriteLevel )) 223 { 224 String msg = "Property inaccessible for overwriting: " + propName; 225 logger.log( cantWriteLevel, msg ); 226 if (die_on_one_prop_failure) 227 { 228 rethrow = true; 229 throw new IntrospectionException( msg ); 230 } 231 } 232 233 } 234 else 235 { 236 if (coerce_strings && 237 propVal != null && 238 propVal.getClass() == String .class && 239 (propType = pd.getPropertyType()) != String .class && 240 Coerce.canCoerce( propType )) 241 { 242 Object coercedPropVal; 243 try 244 { 245 coercedPropVal = Coerce.toObject( (String ) propVal, propType ); 246 setter.invoke( destBean, new Object [] { coercedPropVal } ); 248 } 249 catch (IllegalArgumentException e) 250 { 251 String msg = 254 "Failed to coerce property: " + propName + 255 " [propVal: " + propVal + "; propType: " + propType + "]"; 256 if ( logger.isLoggable( cantCoerceLevel ) ) 257 logger.log( cantCoerceLevel, msg, e ); 258 if (die_on_one_prop_failure) 259 { 260 rethrow = true; 261 throw new IntrospectionException( msg ); 262 } 263 } 264 catch (Exception e) 265 { 266 String msg = 267 "Failed to set property: " + propName + 268 " [propVal: " + propVal + "; propType: " + propType + "]"; 269 if ( logger.isLoggable( cantWriteLevel ) ) 270 logger.log( cantWriteLevel, msg, e ); 271 if (die_on_one_prop_failure) 272 { 273 rethrow = true; 274 throw new IntrospectionException( msg ); 275 } 276 } 277 } 278 else 279 { 280 try 281 { 282 setter.invoke( destBean, new Object [] { propVal } ); 284 } 285 catch (Exception e) 286 { 287 String msg = 288 "Failed to set property: " + propName + 289 " [propVal: " + propVal + "; propType: " + propType + "]"; 290 if ( logger.isLoggable( cantWriteLevel ) ) 291 logger.log( cantWriteLevel, msg, e ); 292 if (die_on_one_prop_failure) 293 { 294 rethrow = true; 295 throw new IntrospectionException( msg ); 296 } 297 } 298 } 299 } 300 } 319 } 320 321 public static void appendPropNamesAndValues(StringBuffer appendIntoMe, Object bean, Collection ignoreProps) throws IntrospectionException 322 { 323 Map tmp = new TreeMap( String.CASE_INSENSITIVE_ORDER ); 324 extractAccessiblePropertiesToMap( tmp, bean, ignoreProps ); 325 boolean first = true; 326 for (Iterator ii = tmp.keySet().iterator(); ii.hasNext(); ) 327 { 328 String key = (String ) ii.next(); 329 Object val = tmp.get( key ); 330 if (first) 331 first = false; 332 else 333 appendIntoMe.append( ", " ); 334 appendIntoMe.append( key ); 335 appendIntoMe.append( " -> "); 336 appendIntoMe.append( val ); 337 } 338 } 339 340 341 public static void extractAccessiblePropertiesToMap( Map fillMe, Object bean ) throws IntrospectionException 342 { extractAccessiblePropertiesToMap( fillMe, bean, Collections.EMPTY_SET ); } 343 344 public static void extractAccessiblePropertiesToMap( Map fillMe, Object bean, Collection ignoreProps ) throws IntrospectionException 345 { 346 String propName = null; 347 try 348 { 349 BeanInfo bi = Introspector.getBeanInfo( bean.getClass(), Object .class ); 350 PropertyDescriptor[] pds = bi.getPropertyDescriptors(); 351 for (int i = 0, len = pds.length; i < len; ++i) 352 { 353 PropertyDescriptor pd = pds[i]; 354 propName = pd.getName(); 355 if (ignoreProps.contains( propName )) 356 continue; 357 358 Method readMethod = pd.getReadMethod(); 359 Object propVal = readMethod.invoke( bean, EMPTY_ARGS ); 360 fillMe.put( propName, propVal ); 361 } 362 } 363 catch ( IntrospectionException e ) 364 { 365 if ( logger.isLoggable( MLevel.WARNING ) ) 368 logger.warning("Problem occurred while overwriting property: " + propName); 369 if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED && logger.isLoggable( MLevel.FINE )) 370 logger.logp( MLevel.FINE, 371 BeansUtils.class.getName(), 372 "extractAccessiblePropertiesToMap( Map fillMe, Object bean, Collection ignoreProps )", 373 (propName != null ? "Problem occurred while overwriting property: " + propName : "") + " throwing...", 374 e ); 375 throw e; 376 } 377 catch ( Exception e ) 378 { 379 if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED && logger.isLoggable( MLevel.FINE )) 381 logger.logp( MLevel.FINE, 382 BeansUtils.class.getName(), 383 "extractAccessiblePropertiesToMap( Map fillMe, Object bean, Collection ignoreProps )", 384 "Caught unexpected Exception; Converting to IntrospectionException.", 385 e ); 386 throw new IntrospectionException( e.toString() + (propName == null ? "" : " [" + propName + ']') ); 387 } 388 } 389 390 private static void overwriteProperty( String propName, Object value, Method putativeSetter, Object target ) 391 throws Exception 392 { 393 if ( putativeSetter.getDeclaringClass().isAssignableFrom( target.getClass() ) ) 394 putativeSetter.invoke( target, new Object [] { value } ); 395 else 396 { 397 BeanInfo beanInfo = Introspector.getBeanInfo( target.getClass(), Object .class ); 398 PropertyDescriptor pd = null; 399 400 PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); 401 for( int i = 0, len = pds.length; i < len; ++i) 402 if (propName.equals( pds[i].getName() )) 403 { 404 pd = pds[i]; 405 break; 406 } 407 408 Method targetSetter = pd.getWriteMethod(); 409 targetSetter.invoke( target, new Object [] { value } ); 410 } 411 } 412 413 414 public static void overwriteSpecificAccessibleProperties( Object sourceBean, Object destBean, Collection props ) 415 throws IntrospectionException 416 { 417 try 418 { 419 Set _props = new HashSet(props); 420 421 BeanInfo beanInfo = Introspector.getBeanInfo( sourceBean.getClass(), Object .class ); PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); 423 for( int i = 0, len = pds.length; i < len; ++i) 424 { 425 PropertyDescriptor pd = pds[i]; 426 String name = pd.getName(); 427 if (! _props.remove( name ) ) 428 continue; 429 430 Method getter = pd.getReadMethod(); 431 Method setter = pd.getWriteMethod(); 432 433 if ( getter == null || setter == null ) 434 { 435 if ( pd instanceof IndexedPropertyDescriptor ) 436 { 437 443 if ( logger.isLoggable( MLevel.WARNING ) ) 444 logger.warning("BeansUtils.overwriteAccessibleProperties() does not" + 445 " support indexed properties that do not provide single-valued" + 446 " array getters and setters! [The indexed methods provide no means" + 447 " of modifying the size of the array in the destination bean if" + 448 " it does not match the source.]"); 449 } 450 451 if ( logger.isLoggable( MLevel.INFO ) ) 452 logger.info("Property inaccessible for overwriting: " + pd.getName()); 453 } 454 else 455 { 456 Object value = getter.invoke( sourceBean, EMPTY_ARGS ); 457 overwriteProperty( name, value, setter, destBean ); 458 } 460 } 461 if ( logger.isLoggable( MLevel.WARNING ) ) 462 { 463 for (Iterator ii = _props.iterator(); ii.hasNext(); ) 464 logger.warning("failed to find expected property: " + ii.next()); 465 } 467 } 468 catch ( IntrospectionException e ) 469 { throw e; } 470 catch ( Exception e ) 471 { 472 if (Debug.DEBUG && Debug.TRACE >= Debug.TRACE_MED && logger.isLoggable( MLevel.FINE )) 474 logger.logp( MLevel.FINE, 475 BeansUtils.class.getName(), 476 "overwriteSpecificAccessibleProperties( Object sourceBean, Object destBean, Collection props )", 477 "Caught unexpected Exception; Converting to IntrospectionException.", 478 e ); 479 throw new IntrospectionException( e.getMessage() ); 480 } 481 } 482 483 public static void debugShowPropertyChange( PropertyChangeEvent evt ) 484 { 485 System.err.println("PropertyChangeEvent: [ propertyName -> " + evt.getPropertyName() + 486 ", oldValue -> " + evt.getOldValue() + 487 ", newValue -> " + evt.getNewValue() + 488 " ]"); 489 } 490 491 private BeansUtils() 492 {} 493 } 494 | Popular Tags |