Coverage Report - org.apache.commons.betwixt.ElementDescriptor

Classes in this File Line Coverage Branch Coverage Complexity
ElementDescriptor
75% 
75% 
1.821

 1  
 /*
 2  
  * Copyright 2001-2004 The Apache Software Foundation.
 3  
  * 
 4  
  * Licensed under the Apache License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  * 
 8  
  *      http://www.apache.org/licenses/LICENSE-2.0
 9  
  * 
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */ 
 16  
 package org.apache.commons.betwixt;
 17  
 
 18  
 import java.util.ArrayList;
 19  
 import java.util.List;
 20  
 
 21  
 import org.apache.commons.betwixt.expression.Expression;
 22  
 
 23  
 /** <p><code>ElementDescriptor</code> describes the XML elements
 24  
   * to be created for a bean instance.</p>
 25  
   *
 26  
   * <p> It contains <code>AttributeDescriptor</code>'s for all it's attributes
 27  
   * and <code>ElementDescriptor</code>'s for it's child elements.
 28  
   *
 29  
   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 30  
   * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
 31  
   */
 32  
 public class ElementDescriptor extends NodeDescriptor {
 33  
 
 34  
     /** 
 35  
      * Descriptors for attributes this element contains.
 36  
      * <strong>Note:</strong> Constructed lazily on demand from a List.
 37  
      * {@link #getAttributeDescriptor()} should be called rather than accessing this
 38  
      * field directly.
 39  
      */
 40  
     private AttributeDescriptor[] attributeDescriptors;
 41  
     /** 
 42  
      * Descriptors for child elements.
 43  
      * <strong>Note:</strong> Constructed lazily on demand from a List.
 44  
      * {@link #getElementDescriptor()} should be called rather than accessing this
 45  
      * field directly.
 46  
      */
 47  
     private ElementDescriptor[] elementDescriptors;
 48  
     
 49  
     /** 
 50  
      * Descriptors for child content.
 51  
      * <strong>Note:</strong> Constructed lazily on demand from a List.
 52  
      * {@link #getContentDescriptor()} should be called rather than accessing this
 53  
      * field directly.
 54  
      */
 55  
     private Descriptor[] contentDescriptors;
 56  
     
 57  
     /** 
 58  
      * The List used on construction. It will be GC'd
 59  
      * after initilization and the array is lazily constructed
 60  
      */
 61  
     private List attributeList;
 62  
     
 63  
     /** 
 64  
      * The List used on construction. It will be GC'd
 65  
      * after initilization and the array is lazily constructed
 66  
      */
 67  
     private List elementList;
 68  
     
 69  
     /** 
 70  
      * The list used o construct array. It will be GC'd after
 71  
      * initialization when the array is lazily constructed.
 72  
      */
 73  
     private List contentList;
 74  
         
 75  
     /** the expression used to evaluate the new context of this node 
 76  
      * or null if the same context is to be used */
 77  
     private Expression contextExpression;
 78  
 
 79  
     /** Whether this element refers to a primitive type (or property of a parent object) */
 80  
     private boolean primitiveType;
 81  
     /** Is this a collective type? */
 82  
     private boolean isCollectiveType;
 83  
     
 84  
     /**
 85  
      * Is this element hollow?
 86  
      * In other words, is this descriptor a place holder indicating the name
 87  
      * and update for a root ElementDescriptor for this type obtained by introspection
 88  
      * TODO: this would probably be better modeled as a separate subclass
 89  
      */
 90  27834
     private boolean isHollow = false;
 91  
     
 92  
     /** 
 93  
      * Whether this collection element can be used
 94  
      * as a collection element. Defaults to true
 95  
      */
 96  27834
     private boolean wrapCollectionsInElement = true;
 97  
     
 98  
     /** specifies a separate implementation class that should be instantiated
 99  
       * when reading beans
 100  
       * or null if there is no separate implementation */
 101  27834
     private Class implementationClass = null;
 102  
     
 103  
     /** 
 104  
      * Should the bind time type determine the mapping? 
 105  
      * (As opposed to the introspection time type.)
 106  
      * Note that this attribute is write once, read many (WORM). 
 107  
      */
 108  27834
     private Boolean useBindTimeTypeForMapping = null;
 109  
     
 110  
     /**  
 111  
      * Constructs an <code>ElementDescriptor</code> that refers to a primitive type.
 112  
      */
 113  26794
     public ElementDescriptor() {
 114  26794
     }
 115  
     
 116  
     /**
 117  
      * Base constructor.
 118  
      * @param primitiveType if true, this element refers to a primitive type
 119  
      * @deprecated 0.6 PrimitiveType property has been removed
 120  
      */
 121  0
     public ElementDescriptor(boolean primitiveType) {
 122  0
         this.primitiveType = primitiveType;
 123  0
     }
 124  
 
 125  
     /** 
 126  
      * Creates a ElementDescriptor with no namespace URI or prefix.
 127  
      *
 128  
      * @param localName the (xml) local name of this node. 
 129  
      * This will be used to set both qualified and local name for this name.
 130  
      */
 131  
     public ElementDescriptor(String localName) {
 132  949
         super( localName );
 133  949
     }
 134  
 
 135  
 
 136  
     
 137  
     /** 
 138  
      * Creates a <code>ElementDescriptor</code> with namespace URI and qualified name
 139  
      * @param localName the (xml) local name of this  node
 140  
      * @param qualifiedName the (xml) qualified name of this node
 141  
      * @param uri the (xml) namespace prefix of this node
 142  
      */
 143  
     public ElementDescriptor(String localName, String qualifiedName, String uri) {
 144  91
         super(localName, qualifiedName, uri);
 145  91
     }
 146  
 
 147  
     /** 
 148  
      * Returns true if this element has child <code>ElementDescriptors</code>
 149  
      * @return true if this element has child elements 
 150  
      * @see #getElementDescriptors
 151  
      */
 152  
     public boolean hasChildren() {
 153  11882
         return getElementDescriptors().length > 0;
 154  
     }
 155  
     
 156  
     /** 
 157  
      * Returns true if this element has <code>AttributeDescriptors</code>
 158  
      * @return true if this element has attributes
 159  
      * @see #getAttributeDescriptors
 160  
      */
 161  
     public boolean hasAttributes() {
 162  23679
         return getAttributeDescriptors().length > 0;
 163  
     }
 164  
     
 165  
     /** 
 166  
      * Returns true if this element has child content.
 167  
      * @return true if this element has either child mixed content or child elements
 168  
      * @see #getContentDescriptors
 169  
      * @since 0.5
 170  
      */
 171  
     public boolean hasContent() {
 172  104
         return getContentDescriptors().length > 0; 
 173  
      } 
 174  
     
 175  
     /**
 176  
      * <p>Is this a simple element?</p>
 177  
      * <p>
 178  
      * A simple element is one without child elements or attributes.
 179  
      * This corresponds to the simple type concept used in XML Schema.
 180  
      * TODO: need to consider whether it's sufficient to calculate
 181  
      * which are simple types (and so don't get IDs assigned etc).
 182  
      * </p>
 183  
      * @return true if it is a <code>SimpleType</code> element
 184  
      */
 185  
     public boolean isSimple() {
 186  14755
         return !(hasAttributes()) && !(hasChildren());
 187  
     }
 188  
     
 189  
     
 190  
     /** 
 191  
      * Sets whether <code>Collection</code> bean properties should wrap items in a parent element.
 192  
      * In other words, should the mapping for bean properties which are <code>Collection</code>s 
 193  
      * enclosed the item elements within a parent element.
 194  
      * Normally only used when this describes a collection bean property.
 195  
      *
 196  
      * @param wrapCollectionsInElement true if the elements for the items in the collection 
 197  
      * should be contained in a parent element
 198  
      * @deprecated 0.6 moved to a declarative style of descriptors where the alrogithmic should
 199  
      * be done during introspection
 200  
      */
 201  
     public void setWrapCollectionsInElement(boolean wrapCollectionsInElement) {
 202  0
         this.wrapCollectionsInElement = wrapCollectionsInElement;
 203  0
     }
 204  
 
 205  
     /**
 206  
      * Returns true if collective bean properties should wrap the items in a parent element.
 207  
      * In other words, should the mapping for bean properties which are <code>Collection</code>s 
 208  
      * enclosed the item elements within a parent element.
 209  
      * Normally only used when this describes a collection bean property.
 210  
      *
 211  
      * @return true if the elements for the items in the collection should be contained 
 212  
      * in a parent element
 213  
      * @deprecated 0.6 moved to a declarative style of descriptors where the alrogithmic should
 214  
      * be done during introspection
 215  
      */
 216  
     public boolean isWrapCollectionsInElement() {
 217  39
         return this.wrapCollectionsInElement;
 218  
     }
 219  
 
 220  
     /**
 221  
      * Adds an attribute to the element this <code>ElementDescriptor</code> describes
 222  
      * @param descriptor the <code>AttributeDescriptor</code> that will be added to the 
 223  
      * attributes associated with element this <code>ElementDescriptor</code> describes
 224  
      */
 225  
     public void addAttributeDescriptor(AttributeDescriptor descriptor) {
 226  2717
         if ( attributeList == null ) {
 227  1599
             attributeList = new ArrayList();
 228  
         }
 229  2717
         getAttributeList().add( descriptor );
 230  2717
         attributeDescriptors = null;
 231  2717
     }
 232  
     
 233  
     
 234  
     /** 
 235  
      * Returns the attribute descriptors for this element 
 236  
      *
 237  
      * @return descriptors for the attributes of the element that this 
 238  
      * <code>ElementDescriptor</code> describes
 239  
      */
 240  
     public AttributeDescriptor[] getAttributeDescriptors() {
 241  54364
         if ( attributeDescriptors == null ) {
 242  15851
             if ( attributeList == null ) {
 243  14460
                 attributeDescriptors = new AttributeDescriptor[0];
 244  
             } else {
 245  1391
                 attributeDescriptors = new AttributeDescriptor[ attributeList.size() ];
 246  1391
                 attributeList.toArray( attributeDescriptors );
 247  
                 
 248  
                 // allow GC of List when initialized
 249  1391
                 attributeList = null;
 250  
             }
 251  
         }
 252  54364
         return attributeDescriptors;
 253  
     }
 254  
     
 255  
     /** 
 256  
      * Sets the <code>AttributesDescriptors</code> for this element.
 257  
      * This sets descriptors for the attributes of the element describe by the 
 258  
      * <code>ElementDescriptor</code>.
 259  
      *
 260  
      * @param attributeDescriptors the <code>AttributeDescriptor</code> describe the attributes
 261  
      * of the element described by this <code>ElementDescriptor</code>
 262  
      */
 263  
     public void setAttributeDescriptors(AttributeDescriptor[] attributeDescriptors) {
 264  1365
         this.attributeDescriptors = attributeDescriptors;
 265  1365
         this.attributeList = null;
 266  1365
     }
 267  
     
 268  
     /**
 269  
      * Adds a descriptor for a child element.
 270  
      * 
 271  
      * @param descriptor the <code>ElementDescriptor</code> describing the child element to add
 272  
      */
 273  
     public void addElementDescriptor(ElementDescriptor descriptor) {
 274  8645
         if ( elementList == null ) {
 275  3666
             elementList = new ArrayList();
 276  
         }
 277  8645
         getElementList().add( descriptor );
 278  8645
         elementDescriptors = null;
 279  8645
         addContentDescriptor( descriptor );
 280  8645
     }
 281  
     
 282  
     /** 
 283  
      * Returns descriptors for the child elements of the element this describes.
 284  
      * @return the <code>ElementDescriptor</code> describing the child elements
 285  
      * of the element that this <code>ElementDescriptor</code> describes
 286  
      */
 287  
     public ElementDescriptor[] getElementDescriptors() {
 288  66290
         if ( elementDescriptors == null ) {
 289  17521
             if ( elementList == null ) {
 290  14765
                 elementDescriptors = new ElementDescriptor[0];
 291  
             } else {
 292  2756
                 elementDescriptors = new ElementDescriptor[ elementList.size() ];
 293  2756
                 elementList.toArray( elementDescriptors );
 294  
                 
 295  
                 // allow GC of List when initialized
 296  2756
                 elementList = null;
 297  
             }
 298  
         }
 299  66290
         return elementDescriptors;
 300  
     }
 301  
     
 302  
     /**
 303  
       * Gets a child ElementDescriptor matching the given name if one exists.
 304  
       * Note that (so long as there are no better matches), a null name
 305  
       * acts as a wildcard. In other words, an 
 306  
       * <code>ElementDescriptor</code> the first descriptor 
 307  
       * with a null name will match any name
 308  
       * passed in, unless some other matches the name exactly.
 309  
       *
 310  
       * @param name the localname to be matched, not null
 311  
       * @return the child ElementDescriptor with the given name if one exists, 
 312  
       * otherwise null
 313  
       */
 314  
     public ElementDescriptor getElementDescriptor(String name) {
 315  
     
 316  8085
         ElementDescriptor elementDescriptor = null;
 317  8085
         ElementDescriptor descriptorWithNullName = null;
 318  8085
         ElementDescriptor firstPolymorphic = null;
 319  8085
         ElementDescriptor[] elementDescriptors = getElementDescriptors();
 320  17444
         for (int i=0, size=elementDescriptors.length; i<size; i++) {
 321  16418
             if (firstPolymorphic == null && elementDescriptors[i].isPolymorphic()) {
 322  545
                 firstPolymorphic = elementDescriptors[i];
 323  
             }
 324  16418
             String elementName = elementDescriptors[i].getQualifiedName();
 325  16418
             if (name.equals(elementName)) {
 326  7059
                 elementDescriptor = elementDescriptors[i];
 327  7059
                 break;
 328  
             }
 329  9359
             if (descriptorWithNullName == null && elementName == null) {
 330  545
                 descriptorWithNullName = elementDescriptors[i];
 331  
             }
 332  
         }
 333  8085
         if (elementDescriptor == null) {
 334  1026
             elementDescriptor = firstPolymorphic;
 335  
         }
 336  8085
         if (elementDescriptor == null) {
 337  494
             elementDescriptor = descriptorWithNullName;
 338  
         }
 339  8085
         return elementDescriptor;
 340  
     }
 341  
 
 342  
 
 343  
     /** 
 344  
      * Sets the descriptors for the child element of the element this describes. 
 345  
      * Also sets the child content descriptors for this element
 346  
      *
 347  
      * @param elementDescriptors the <code>ElementDescriptor</code>s of the element 
 348  
      * that this describes
 349  
      */
 350  
     public void setElementDescriptors(ElementDescriptor[] elementDescriptors) {
 351  5530
         this.elementDescriptors = elementDescriptors;
 352  5530
         this.elementList = null;
 353  5530
         setContentDescriptors( elementDescriptors );
 354  5530
     }
 355  
     
 356  
     /**
 357  
      * Adds a descriptor for child content.
 358  
      * 
 359  
      * @param descriptor the <code>Descriptor</code> describing the child content to add
 360  
      * @since 0.5
 361  
      */
 362  
     public void addContentDescriptor(Descriptor descriptor) {
 363  8736
         if ( contentList == null ) {
 364  3731
             contentList = new ArrayList();
 365  
         }
 366  8736
         getContentList().add( descriptor );
 367  8736
         contentDescriptors = null;
 368  8736
     }
 369  
     
 370  
     /** 
 371  
      * Returns descriptors for the child content of the element this describes.
 372  
      * @return the <code>Descriptor</code> describing the child elements
 373  
      * of the element that this <code>ElementDescriptor</code> describes
 374  
      * @since 0.5
 375  
      */
 376  
     public Descriptor[] getContentDescriptors() {
 377  20953
         if ( contentDescriptors == null ) {
 378  8825
             if ( contentList == null ) {
 379  6472
                 contentDescriptors = new Descriptor[0];
 380  
             } else {
 381  2353
                 contentDescriptors = new Descriptor[ contentList.size() ];
 382  2353
                 contentList.toArray( contentDescriptors );
 383  
                 
 384  
                 // allow GC of List when initialized
 385  2353
                 contentList = null;
 386  
             }
 387  
         }
 388  20953
         return contentDescriptors;
 389  
     }
 390  
     
 391  
     /**
 392  
      * <p>Gets the primary descriptor for body text of this element. 
 393  
      * Betwixt collects all body text for any element together.
 394  
      * This makes it rounds tripping difficult for beans that write more than one
 395  
      * mixed content property.
 396  
      * </p><p>
 397  
      * The algorithm used in the default implementation is that the first TextDescriptor
 398  
      * found amongst the descriptors is returned.
 399  
      *
 400  
      * @return the primary descriptor or null if this element has no mixed body content
 401  
      * @since 0.5
 402  
      */
 403  
     public TextDescriptor getPrimaryBodyTextDescriptor() {
 404  
         // todo: this probably isn't the most efficent algorithm
 405  
         // but should avoid premature optimization
 406  3450
         Descriptor[] descriptors = getContentDescriptors();
 407  8305
         for (int i=0, size=descriptors.length; i<size; i++) {
 408  4881
             if (descriptors[i] instanceof TextDescriptor) {
 409  26
                 return (TextDescriptor) descriptors[i];
 410  
             }
 411  
         }
 412  
         // if we haven't found anything, return null.
 413  3424
         return null;
 414  
     }
 415  
 
 416  
     /** 
 417  
      * Sets the descriptors for the child content of the element this describes. 
 418  
      * @param contentDescriptors the <code>Descriptor</code>s of the element 
 419  
      * that this describes
 420  
      * @since 0.5
 421  
      */
 422  
     public void setContentDescriptors(Descriptor[] contentDescriptors) {
 423  5530
         this.contentDescriptors = contentDescriptors;
 424  5530
         this.contentList = null;
 425  5530
     }
 426  
     
 427  
     /** 
 428  
      * Returns the expression used to evaluate the new context of this element.
 429  
      * @return the expression used to evaluate the new context of this element
 430  
      */
 431  
     public Expression getContextExpression() {
 432  13857
         return contextExpression;
 433  
     }
 434  
     
 435  
     /** 
 436  
      * Sets the expression used to evaluate the new context of this element 
 437  
      * @param contextExpression the expression used to evaluate the new context of this element 
 438  
      */
 439  
     public void setContextExpression(Expression contextExpression) {
 440  6388
         this.contextExpression = contextExpression;
 441  6388
     }
 442  
     
 443  
     /** 
 444  
      * Returns true if this element refers to a primitive type property
 445  
      * @return whether this element refers to a primitive type (or property of a parent object) 
 446  
      * @deprecated 0.6 moved to a declarative style of descriptors where the alrogithmic should
 447  
      * be done during introspection
 448  
      */
 449  
     public boolean isPrimitiveType() {
 450  0
         return primitiveType;
 451  
     }
 452  
     
 453  
     /** 
 454  
      * Sets whether this element refers to a primitive type (or property of a parent object) 
 455  
      * @param primitiveType true if this element refers to a primitive type
 456  
      * @deprecated 0.6 moved to a declarative style of descriptors where the alrogithmic should
 457  
      * be done during introspection
 458  
      */
 459  
     public void setPrimitiveType(boolean primitiveType) {
 460  0
         this.primitiveType = primitiveType;
 461  0
     }
 462  
     
 463  
     // Implementation methods
 464  
     //-------------------------------------------------------------------------    
 465  
         
 466  
     /** 
 467  
      * Lazily creates the mutable List.
 468  
      * This nullifies the attributeDescriptors array so that
 469  
      * as items are added to the list the Array is ignored until it is
 470  
      * explicitly asked for.
 471  
      * 
 472  
      * @return list of <code>AttributeDescriptors</code>'s describing the attributes
 473  
      * of the element that this <code>ElementDescriptor</code> describes
 474  
      */
 475  
     protected List getAttributeList() {
 476  2717
         if ( attributeList == null ) {
 477  0
             if ( attributeDescriptors != null ) {
 478  0
                 int size = attributeDescriptors.length;
 479  0
                 attributeList = new ArrayList( size );
 480  0
                 for ( int i = 0; i < size; i++ ) {
 481  0
                     attributeList.add( attributeDescriptors[i] );
 482  
                 }
 483  
                 // force lazy recreation later
 484  0
                 attributeDescriptors = null;
 485  
             } else {
 486  0
                 attributeList = new ArrayList();
 487  
             }            
 488  
         }
 489  2717
         return attributeList;
 490  
     }
 491  
     
 492  
     /**  
 493  
      * Lazily creates the mutable List of child elements.
 494  
      * This nullifies the elementDescriptors array so that
 495  
      * as items are added to the list the Array is ignored until it is
 496  
      * explicitly asked for.
 497  
      *
 498  
      * @return list of <code>ElementDescriptor</code>'s describe the child elements of 
 499  
      * the element that this <code>ElementDescriptor</code> describes
 500  
      */
 501  
     protected List getElementList() {
 502  8645
         if ( elementList == null ) {
 503  0
             if ( elementDescriptors != null ) {
 504  0
                 int size = elementDescriptors.length;
 505  0
                 elementList = new ArrayList( size );
 506  0
                 for ( int i = 0; i < size; i++ ) {
 507  0
                     elementList.add( elementDescriptors[i] );
 508  
                 }
 509  
                 // force lazy recreation later
 510  0
                 elementDescriptors = null;
 511  
             } else {
 512  0
                 elementList = new ArrayList();
 513  
             }            
 514  
         }
 515  8645
         return elementList;
 516  
     }
 517  
     
 518  
     /**  
 519  
      * Lazily creates the mutable List of child content descriptors.
 520  
      * This nullifies the contentDescriptors array so that
 521  
      * as items are added to the list the Array is ignored until it is
 522  
      * explicitly asked for.
 523  
      *
 524  
      * @return list of <code>Descriptor</code>'s describe the child content of 
 525  
      * the element that this <code>Descriptor</code> describes
 526  
      * @since 0.5
 527  
      */
 528  
     protected List getContentList() {
 529  8736
         if ( contentList == null ) {
 530  0
             if ( contentDescriptors != null ) {
 531  0
                 int size = contentDescriptors.length;
 532  0
                 contentList = new ArrayList( size );
 533  0
                 for ( int i = 0; i < size; i++ ) {
 534  0
                     contentList.add( contentDescriptors[i] );
 535  
                 }
 536  
                 // force lazy recreation later
 537  0
                 contentDescriptors = null;
 538  
             } else {
 539  0
                 contentList = new ArrayList();
 540  
             }            
 541  
         }
 542  8736
         return contentList;
 543  
     }
 544  
     
 545  
     /**
 546  
       * Gets the class which should be used for instantiation.
 547  
       * @return the class which should be used for instantiation of beans 
 548  
       * mapped from this element, null if the standard class should be used
 549  
       */
 550  
     public Class getImplementationClass() {
 551  3235
         return implementationClass;
 552  
     }
 553  
     
 554  
     /**
 555  
       * Sets the class which should be used for instantiation.
 556  
       * @param implementationClass the class which should be used for instantiation
 557  
       * or null to use the mapped type
 558  
       * @since 0.5
 559  
       */
 560  
     public void setImplementationClass(Class implementationClass) {
 561  26
         this.implementationClass = implementationClass;
 562  26
     }
 563  
     
 564  
     /**
 565  
      * Does this describe a collective?
 566  
      */
 567  
     public boolean isCollective() {
 568  
         // TODO is this implementation correct?
 569  
         // maybe this method is unnecessary
 570  1638
         return isCollectiveType;
 571  
     }
 572  
     
 573  
     /**
 574  
      * Sets whether the element described is a collective.
 575  
      * @since 0.7
 576  
      * @param isCollectiveType
 577  
      */
 578  
     public void setCollective(boolean isCollectiveType) {
 579  11326
         this.isCollectiveType = isCollectiveType;
 580  11326
     }
 581  
 
 582  
     /** 
 583  
      * Finds the parent of the given descriptor.
 584  
      * @param elementDescriptor <code>ElementDescriptor</code>
 585  
      * @return <code>ElementDescriptor</code>, not null
 586  
      */
 587  
     public ElementDescriptor findParent(ElementDescriptor elementDescriptor) {
 588  
         //TODO: is this really a good design?
 589  0
         ElementDescriptor result = null;
 590  0
         ElementDescriptor[] elementDescriptors = getElementDescriptors();
 591  0
         for (int i=0, size=elementDescriptors.length; i<size; i++) {
 592  0
             if (elementDescriptors[i].equals(elementDescriptor)) {
 593  0
                 result = this;
 594  0
                 break;
 595  
             }
 596  
             else
 597  
             {
 598  0
                 result = elementDescriptors[i].findParent(elementDescriptor);
 599  0
                 if (result != null) {
 600  0
                     break;
 601  
                 }
 602  
             }
 603  
         }
 604  0
         return result;
 605  
     }
 606  
     
 607  
     /**
 608  
      * Returns something useful for logging.
 609  
      *
 610  
      * @return a string useful for logging
 611  
      */ 
 612  
     public String toString() {
 613  39
         return 
 614  78
             "ElementDescriptor[qname=" + getQualifiedName() + ",pname=" + getPropertyName() 
 615  39
             + ",class=" + getPropertyType() + ",singular=" + getSingularPropertyType()
 616  39
             + ",updater=" + getUpdater() + ",wrap=" + isWrapCollectionsInElement() + "]";
 617  
     }
 618  
 
 619  
     /**
 620  
      * <p>Is this decriptor hollow?</p>
 621  
      * <p>
 622  
      * A hollow descriptor is one which gives only the class that the subgraph
 623  
      * is mapped to rather than describing the entire subgraph.
 624  
      * A new <code>XMLBeanInfo</code> should be introspected 
 625  
      * and that used to describe the subgraph.
 626  
      * A hollow descriptor should not have any child descriptors. 
 627  
      * TODO: consider whether a subclass would be better
 628  
      * </p>
 629  
      * @return true if this is hollow 
 630  
      */
 631  
     public boolean isHollow() {
 632  11029
         return isHollow;
 633  
     }    
 634  
     
 635  
     /**
 636  
      * Sets whether this descriptor is hollow.
 637  
      * A hollow descriptor is one which gives only the class that the subgraph
 638  
      * is mapped to rather than describing the entire subgraph.
 639  
      * A new <code>XMLBeanInfo</code> should be introspected 
 640  
      * and that used to describe the subgraph.
 641  
      * A hollow descriptor should not have any child descriptors. 
 642  
      * TODO: consider whether a subclass would be better
 643  
      * @param isHollow true if this is hollow 
 644  
      */
 645  
     public void setHollow(boolean isHollow) {
 646  9595
         this.isHollow = isHollow;
 647  9595
     }  
 648  
     
 649  
     /**
 650  
      * <p>Is the bind time type to be used to determine the mapping?</p>
 651  
      * <p>
 652  
      * The mapping for an object property value can either be the 
 653  
      * introspection time type (based on the logical type of the property)
 654  
      * or the bind time type (based on the type of the actual instance).
 655  
      * </p>
 656  
      * @since 0.7
 657  
      * @return true if the bind time type is to be used to determine the mapping,
 658  
      * false if the introspection time type is to be used
 659  
      */
 660  
     public boolean isUseBindTimeTypeForMapping() {
 661  14452
         boolean result = true;
 662  14452
         if ( this.useBindTimeTypeForMapping != null ) {
 663  11254
             result = this.useBindTimeTypeForMapping.booleanValue();
 664  
         }
 665  14452
         return result;
 666  
     }
 667  
 
 668  
     /**
 669  
      * <p>Sets whether the bind time type to be used to determine the mapping.
 670  
      * The mapping for an object property value can either be the 
 671  
      * introspection time type (based on the logical type of the property)
 672  
      * or the bind time type (based on the type of the actual instance).
 673  
      * </p><p>
 674  
      * <strong>Note:</strong> this property is write once, read many.
 675  
      * So, the first time that this method is called the value will be set
 676  
      * but subsequent calls will be ignored.
 677  
      * </p>
 678  
      * @since 0.7
 679  
      * @param useBindTimeTypeForMapping true if the bind time type is to be used to 
 680  
      * determine the mapping, false if the introspection time type is to be used
 681  
      */
 682  
     public void setUseBindTimeTypeForMapping(boolean useBindTimeTypeForMapping) {
 683  21362
         if ( this.useBindTimeTypeForMapping == null ) {
 684  21349
             this.useBindTimeTypeForMapping = new Boolean(useBindTimeTypeForMapping);
 685  
         }
 686  21362
     }
 687  
 
 688  
     /**
 689  
      * <p>Is this a polymorphic element?</p>
 690  
      * <p>
 691  
      * A polymorphic element's name is not fixed at 
 692  
      * introspection time and it's resolution is postponed to bind time.
 693  
      * </p>
 694  
      * @since 0.7
 695  
      * @return true if {@link #getQualifiedName} is null, 
 696  
      * false otherwise
 697  
      */
 698  
     public boolean isPolymorphic() { 
 699  23585
         return (getQualifiedName() == null);
 700  
     }
 701  
 }