1 package org.apache.commons.betwixt.digester; 2 3 18 19 import java.beans.IntrospectionException ; 20 import java.beans.Introspector ; 21 import java.beans.PropertyDescriptor ; 22 import java.lang.reflect.Method ; 23 import java.util.Collection ; 24 import java.util.Date ; 25 import java.util.Enumeration ; 26 import java.util.HashMap ; 27 import java.util.Iterator ; 28 import java.util.Map ; 29 30 import org.apache.commons.betwixt.AttributeDescriptor; 31 import org.apache.commons.betwixt.ElementDescriptor; 32 import org.apache.commons.betwixt.NodeDescriptor; 33 import org.apache.commons.betwixt.XMLIntrospector; 34 import org.apache.commons.betwixt.expression.IteratorExpression; 35 import org.apache.commons.betwixt.expression.MapEntryAdder; 36 import org.apache.commons.betwixt.expression.MethodExpression; 37 import org.apache.commons.betwixt.expression.MethodUpdater; 38 import org.apache.commons.betwixt.strategy.PluralStemmer; 39 import org.apache.commons.logging.Log; 40 import org.apache.commons.logging.LogFactory; 41 42 52 public class XMLIntrospectorHelper { 53 54 55 protected static Log log = LogFactory.getLog( XMLIntrospectorHelper.class ); 56 57 58 public XMLIntrospectorHelper() { 59 } 60 61 66 public static Log getLog() { 67 return log; 68 } 69 70 75 public static void setLog(Log aLog) { 76 log = aLog; 77 } 78 79 80 81 93 public static NodeDescriptor createDescriptor( 94 PropertyDescriptor propertyDescriptor, 95 boolean useAttributesForPrimitives, 96 XMLIntrospector introspector 97 ) throws IntrospectionException { 98 String name = propertyDescriptor.getName(); 99 Class type = propertyDescriptor.getPropertyType(); 100 101 if (log.isTraceEnabled()) { 102 log.trace("Creating descriptor for property: name=" 103 + name + " type=" + type); 104 } 105 106 NodeDescriptor nodeDescriptor = null; 107 Method readMethod = propertyDescriptor.getReadMethod(); 108 Method writeMethod = propertyDescriptor.getWriteMethod(); 109 110 if ( readMethod == null ) { 111 if (log.isTraceEnabled()) { 112 log.trace( "No read method for property: name=" 113 + name + " type=" + type); 114 } 115 return null; 116 } 117 118 if ( log.isTraceEnabled() ) { 119 log.trace( "Read method=" + readMethod.getName() ); 120 } 121 122 124 if ( Class .class.equals( type ) && "class".equals( name ) ) { 126 log.trace( "Ignoring class property" ); 127 return null; 128 } 129 if ( isPrimitiveType( type ) ) { 130 if (log.isTraceEnabled()) { 131 log.trace( "Primitive type: " + name); 132 } 133 if ( useAttributesForPrimitives ) { 134 if (log.isTraceEnabled()) { 135 log.trace( "Adding property as attribute: " + name ); 136 } 137 nodeDescriptor = new AttributeDescriptor(); 138 } else { 139 if (log.isTraceEnabled()) { 140 log.trace( "Adding property as element: " + name ); 141 } 142 nodeDescriptor = new ElementDescriptor(true); 143 } 144 nodeDescriptor.setTextExpression( new MethodExpression( readMethod ) ); 145 146 if ( writeMethod != null ) { 147 nodeDescriptor.setUpdater( new MethodUpdater( writeMethod ) ); 148 } 149 } else if ( isLoopType( type ) ) { 150 if (log.isTraceEnabled()) { 151 log.trace("Loop type: " + name); 152 log.trace("Wrap in collections? " + introspector.isWrapCollectionsInElement()); 153 } 154 ElementDescriptor loopDescriptor = new ElementDescriptor(); 155 loopDescriptor.setContextExpression( 156 new IteratorExpression( new MethodExpression( readMethod ) ) 157 ); 158 loopDescriptor.setWrapCollectionsInElement( 159 introspector.isWrapCollectionsInElement()); 160 if ( Map .class.isAssignableFrom( type ) ) { 163 loopDescriptor.setQualifiedName( "entry" ); 164 loopDescriptor.addElementDescriptor( new ElementDescriptor( "key" ) ); 166 loopDescriptor.addElementDescriptor( new ElementDescriptor( "value" ) ); 167 } 168 169 ElementDescriptor elementDescriptor = new ElementDescriptor(); 170 elementDescriptor.setWrapCollectionsInElement( 171 introspector.isWrapCollectionsInElement()); 172 elementDescriptor.setElementDescriptors( new ElementDescriptor[] { loopDescriptor } ); 173 174 nodeDescriptor = elementDescriptor; 175 } else { 176 if (log.isTraceEnabled()) { 177 log.trace( "Standard property: " + name); 178 } 179 ElementDescriptor elementDescriptor = new ElementDescriptor(); 180 elementDescriptor.setContextExpression( new MethodExpression( readMethod ) ); 181 if ( writeMethod != null ) { 182 elementDescriptor.setUpdater( new MethodUpdater( writeMethod ) ); 183 } 184 185 nodeDescriptor = elementDescriptor; 186 } 187 188 if (nodeDescriptor instanceof AttributeDescriptor) { 189 nodeDescriptor.setLocalName( 191 introspector.getAttributeNameMapper().mapTypeToElementName( name ) ); 192 } else { 193 nodeDescriptor.setLocalName( 194 introspector.getElementNameMapper().mapTypeToElementName( name ) ); 195 } 196 197 nodeDescriptor.setPropertyName( propertyDescriptor.getName() ); 198 nodeDescriptor.setPropertyType( type ); 199 200 204 if (log.isTraceEnabled()) { 205 log.trace("Created descriptor:"); 206 log.trace(nodeDescriptor); 207 } 208 return nodeDescriptor; 209 } 210 211 219 public static void configureProperty( 220 ElementDescriptor elementDescriptor, 221 PropertyDescriptor propertyDescriptor ) { 222 223 configureProperty( elementDescriptor, propertyDescriptor, null, null); 224 } 225 226 239 public static void configureProperty( 240 ElementDescriptor elementDescriptor, 241 PropertyDescriptor propertyDescriptor, 242 String updateMethodName, 243 Class beanClass ) { 244 245 Class type = propertyDescriptor.getPropertyType(); 246 Method readMethod = propertyDescriptor.getReadMethod(); 247 Method writeMethod = propertyDescriptor.getWriteMethod(); 248 249 elementDescriptor.setLocalName( propertyDescriptor.getName() ); 250 elementDescriptor.setPropertyType( type ); 251 252 256 if ( readMethod == null ) { 257 log.trace( "No read method" ); 258 return; 259 } 260 261 if ( log.isTraceEnabled() ) { 262 log.trace( "Read method=" + readMethod.getName() ); 263 } 264 265 267 if ( Class .class.equals( type ) && "class".equals( propertyDescriptor.getName() ) ) { 269 log.trace( "Ignoring class property" ); 270 return; 271 } 272 if ( isPrimitiveType( type ) ) { 273 elementDescriptor.setTextExpression( new MethodExpression( readMethod ) ); 274 275 } else if ( isLoopType( type ) ) { 276 log.trace("Loop type ??"); 277 278 elementDescriptor.setContextExpression( 281 new IteratorExpression( new MethodExpression( readMethod ) ) 282 ); 283 284 writeMethod = null; 285 } else { 286 log.trace( "Standard property" ); 287 elementDescriptor.setContextExpression( new MethodExpression( readMethod ) ); 288 } 289 290 if (updateMethodName == null) { 292 if ( writeMethod != null ) { 294 elementDescriptor.setUpdater( new MethodUpdater( writeMethod ) ); 295 } 296 297 } else { 298 if ( log.isTraceEnabled() ) { 300 log.trace( "Finding custom method: " ); 301 log.trace( " on:" + beanClass ); 302 log.trace( " name:" + updateMethodName ); 303 } 304 305 Method updateMethod = null; 306 Method [] methods = beanClass.getMethods(); 307 for ( int i = 0, size = methods.length; i < size; i++ ) { 308 Method method = methods[i]; 309 if ( updateMethodName.equals( method.getName() ) ) { 310 if (methods[i].getParameterTypes().length == 1) { 313 updateMethod = methods[i]; 315 if ( log.isTraceEnabled() ) { 316 log.trace("Matched method:" + updateMethod); 317 } 318 break; 320 } 321 } 322 } 323 324 if (updateMethod == null) { 325 if ( log.isInfoEnabled() ) { 326 327 log.info("No method with name '" + updateMethodName + "' found for update"); 328 } 329 } else { 330 331 elementDescriptor.setUpdater( new MethodUpdater( updateMethod ) ); 332 elementDescriptor.setSingularPropertyType( updateMethod.getParameterTypes()[0] ); 333 if ( log.isTraceEnabled() ) { 334 log.trace( "Set custom updater on " + elementDescriptor); 335 } 336 } 337 } 338 } 339 340 347 public static void configureProperty( 348 AttributeDescriptor attributeDescriptor, 349 PropertyDescriptor propertyDescriptor ) { 350 Class type = propertyDescriptor.getPropertyType(); 351 Method readMethod = propertyDescriptor.getReadMethod(); 352 Method writeMethod = propertyDescriptor.getWriteMethod(); 353 354 if ( readMethod == null ) { 355 log.trace( "No read method" ); 356 return; 357 } 358 359 if ( log.isTraceEnabled() ) { 360 log.trace( "Read method=" + readMethod ); 361 } 362 363 365 if ( Class .class.equals( type ) && "class".equals( propertyDescriptor.getName() ) ) { 367 log.trace( "Ignoring class property" ); 368 return; 369 } 370 if ( isLoopType( type ) ) { 371 log.warn( "Using loop type for an attribute. Type = " 372 + type.getName() + " attribute: " + attributeDescriptor.getQualifiedName() ); 373 } 374 375 log.trace( "Standard property" ); 376 attributeDescriptor.setTextExpression( new MethodExpression( readMethod ) ); 377 378 if ( writeMethod != null ) { 379 attributeDescriptor.setUpdater( new MethodUpdater( writeMethod ) ); 380 } 381 382 attributeDescriptor.setLocalName( propertyDescriptor.getName() ); 383 attributeDescriptor.setPropertyType( type ); 384 385 } 389 390 391 410 public static void defaultAddMethods( 411 XMLIntrospector introspector, 412 ElementDescriptor rootDescriptor, 413 Class beanClass ) { 414 if ( beanClass != null ) { 417 Method [] methods = beanClass.getMethods(); 418 for ( int i = 0, size = methods.length; i < size; i++ ) { 419 Method method = methods[i]; 420 String name = method.getName(); 421 if ( name.startsWith( "add" ) ) { 422 Class [] types = method.getParameterTypes(); 425 if ( types != null) { 426 if ( log.isTraceEnabled() ) { 427 log.trace("Searching for match for " + method); 428 } 429 430 if ( ( types.length == 1 ) || types.length == 2 ) { 431 String propertyName = Introspector.decapitalize( name.substring(3) ); 432 if (propertyName.length() == 0) 433 continue; 434 if ( log.isTraceEnabled() ) { 435 log.trace( name + "->" + propertyName ); 436 } 437 438 ElementDescriptor descriptor = 443 findGetCollectionDescriptor( 444 introspector, 445 rootDescriptor, 446 propertyName ); 447 448 if ( log.isDebugEnabled() ) { 449 log.debug( "!! " + propertyName + " -> " + descriptor ); 450 log.debug( "!! " + name + " -> " 451 + (descriptor!=null?descriptor.getPropertyName():"") ); 452 } 453 if ( descriptor != null ) { 454 boolean isMapDescriptor 455 = Map .class.isAssignableFrom( descriptor.getPropertyType() ); 456 if ( !isMapDescriptor && types.length == 1 ) { 457 log.trace("Matching collection or iteration"); 459 460 descriptor.setUpdater( new MethodUpdater( method ) ); 461 descriptor.setSingularPropertyType( types[0] ); 462 463 if ( log.isDebugEnabled() ) { 464 log.debug( "!! " + method); 465 log.debug( "!! " + types[0]); 466 } 467 468 ElementDescriptor[] children 470 = descriptor.getElementDescriptors(); 471 if ( children != null && children.length > 0 ) { 472 ElementDescriptor child = children[0]; 473 String localName = child.getLocalName(); 474 if ( localName == null || localName.length() == 0 ) { 475 child.setLocalName( 476 introspector.getElementNameMapper() 477 .mapTypeToElementName( propertyName ) ); 478 } 479 } 480 481 } else if ( isMapDescriptor && types.length == 2 ) { 482 log.trace("Matching map"); 484 ElementDescriptor[] children 485 = descriptor.getElementDescriptors(); 486 if ( children.length == 0 ) { 488 489 log.info( 490 "'entry' descriptor is missing for map. " 491 + "Updaters cannot be set"); 492 493 } else { 494 ElementDescriptor[] grandchildren 497 = children[0].getElementDescriptors(); 498 MapEntryAdder adder = new MapEntryAdder(method); 499 for ( 500 int n=0, 501 noOfGrandChildren = grandchildren.length; 502 n < noOfGrandChildren; 503 n++ ) { 504 if ( "key".equals( 505 grandchildren[n].getLocalName() ) ) { 506 507 grandchildren[n].setUpdater( 508 adder.getKeyUpdater() ); 509 grandchildren[n].setSingularPropertyType( 510 types[0] ); 511 if ( log.isTraceEnabled() ) { 512 log.trace( 513 "Key descriptor: " + grandchildren[n]); 514 } 515 516 } else if ( 517 "value".equals( 518 grandchildren[n].getLocalName() ) ) { 519 520 grandchildren[n].setUpdater( 521 adder.getValueUpdater() ); 522 grandchildren[n].setSingularPropertyType( 523 types[1] ); 524 if ( log.isTraceEnabled() ) { 525 log.trace( 526 "Value descriptor: " + grandchildren[n]); 527 } 528 } 529 } 530 } 531 } 532 } else { 533 if ( log.isDebugEnabled() ) { 534 log.debug( 535 "Could not find an ElementDescriptor with property name: " 536 + propertyName + " to attach the add method: " + method 537 ); 538 } 539 } 540 } 541 } 542 } 543 } 544 } 545 } 546 547 553 public static boolean isLoopType(Class type) { 554 if (type == null) { 556 log.trace("isLoopType: type is null"); 557 return false; 558 } 559 return type.isArray() 560 || Map .class.isAssignableFrom( type ) 561 || Collection .class.isAssignableFrom( type ) 562 || Enumeration .class.isAssignableFrom( type ) 563 || Iterator .class.isAssignableFrom( type ); 564 } 565 566 567 578 public static boolean isPrimitiveType(Class type) { 579 if ( type == null ) { 580 return false; 581 582 } else if ( type.isPrimitive() ) { 583 return true; 584 585 } else if ( type.equals( Object .class ) ) { 586 return false; 587 } 588 return type.getName().startsWith( "java.lang." ) 589 || Number .class.isAssignableFrom( type ) 590 || String .class.isAssignableFrom( type ) 591 || Date .class.isAssignableFrom( type ) 592 || java.sql.Date .class.isAssignableFrom( type ) 593 || java.sql.Time .class.isAssignableFrom( type ) 594 || java.sql.Timestamp .class.isAssignableFrom( type ) 595 || java.math.BigDecimal .class.isAssignableFrom( type ) 596 || java.math.BigInteger .class.isAssignableFrom( type ); 597 } 598 599 602 615 protected static ElementDescriptor findGetCollectionDescriptor( 616 XMLIntrospector introspector, 617 ElementDescriptor rootDescriptor, 618 String propertyName ) { 619 Map map = new HashMap (); 621 if ( log.isTraceEnabled() ) { 623 log.trace( "findPluralDescriptor( " + propertyName 624 + " ):root property name=" + rootDescriptor.getPropertyName() ); 625 } 626 627 if (rootDescriptor.getPropertyName() != null) { 628 map.put(propertyName, rootDescriptor); 629 } 630 makeElementDescriptorMap( rootDescriptor, map ); 631 632 PluralStemmer stemmer = introspector.getPluralStemmer(); 633 ElementDescriptor elementDescriptor = stemmer.findPluralDescriptor( propertyName, map ); 634 635 if ( log.isTraceEnabled() ) { 636 log.trace( 637 "findPluralDescriptor( " + propertyName 638 + " ):ElementDescriptor=" + elementDescriptor ); 639 } 640 641 return elementDescriptor; 642 } 643 644 652 protected static void makeElementDescriptorMap( ElementDescriptor rootDescriptor, Map map ) { 653 ElementDescriptor[] children = rootDescriptor.getElementDescriptors(); 654 if ( children != null ) { 655 for ( int i = 0, size = children.length; i < size; i++ ) { 656 ElementDescriptor child = children[i]; 657 String propertyName = child.getPropertyName(); 658 if ( propertyName != null ) { 659 map.put( propertyName, child ); 660 } 661 makeElementDescriptorMap( child, map ); 662 } 663 } 664 } 665 666 675 protected static void swapDescriptor( 676 ElementDescriptor rootDescriptor, 677 ElementDescriptor oldValue, 678 ElementDescriptor newValue ) { 679 ElementDescriptor[] children = rootDescriptor.getElementDescriptors(); 680 if ( children != null ) { 681 for ( int i = 0, size = children.length; i < size; i++ ) { 682 ElementDescriptor child = children[i]; 683 if ( child == oldValue ) { 684 children[i] = newValue; 685 break; 686 } 687 swapDescriptor( child, oldValue, newValue ); 688 } 689 } 690 } 691 } 692 | Popular Tags |