View Javadoc
1   /*
2    * Copyright 2006 Keith Visco, Ralf Joachim
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.exolab.castor.xml.util;
17  
18  import org.exolab.castor.mapping.ClassDescriptor;
19  import org.exolab.castor.mapping.FieldDescriptor;
20  import org.exolab.castor.mapping.FieldHandler;
21  import org.exolab.castor.mapping.MapItem;
22  import org.exolab.castor.mapping.MappingException;
23  import org.exolab.castor.mapping.loader.FieldDescriptorImpl;
24  import org.exolab.castor.mapping.loader.FieldHandlerImpl;
25  import org.exolab.castor.xml.FieldValidator;
26  import org.exolab.castor.xml.NodeType;
27  import org.exolab.castor.xml.XMLClassDescriptor;
28  import org.exolab.castor.xml.XMLFieldDescriptor;
29  import org.exolab.castor.xml.descriptors.CoreDescriptors;
30  import org.exolab.castor.xml.handlers.DateFieldHandler;
31  
32  import java.util.ArrayList;
33  import java.util.List;
34  import java.util.StringTokenizer;
35  import java.util.Properties;
36  
37  /**
38   * XML field descriptor. Wraps {@link FieldDescriptor} and adds XML-related
39   * information, type conversion, etc.
40   * <p>
41   * Note: When using a GeneralizedFieldHandler the getFieldType() methods of
42   * handler and descriptor need to return the same result.
43   *
44   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
45   * @author <a href="mailto:ralf DOT joachim AT syscon DOT eu">Ralf Joachim</a>
46   * @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr 2006) $
47   */
48  public class XMLFieldDescriptorImpl extends FieldDescriptorImpl implements XMLFieldDescriptor {
49      private static final String WILD_CARD = "*";
50  
51      private static final String NULL_CLASS_ERR
52          = "The 'type' argument passed to the constructor of "
53           + "XMLFieldDescriptorImpl may not be null.";
54  
55      private static final String NULL_NAME_ERR
56          = "The 'fieldName' argument passed to the constructor of "
57           + "XMLFieldDescriptorImpl may not be null.";
58  
59      /** The index of this field within the constructor arguments. Note: This
60       * field is only applicable if the field is an attribute field and it's
61       * supposed to be set via the constructor. A value less than zero indicates
62       * that this field is not part of the constructor arguments.
63       */
64      private int _argIndex = -1;
65  
66      /** True if the field is a container field. */
67      private boolean _container = false;
68  
69      /** Flag to indicate that objects should be added to their as soon as they
70       * are created, but before they are finished being populated.
71       */
72      private boolean _incremental = false;
73  
74      /** True if the field is a reference to another Object in the hierarchy. */
75      public boolean _isReference = false;
76  
77      private boolean _isWild = false;
78  
79      /** True if the field type is mapped in a Hashtable or Map. */
80      private boolean _mapped = false;
81  
82      private String[] _matches = null;
83  
84      /** True if the field is allowed to have nil content. */
85      private boolean _nillable = false;
86  
87      /** The node type (attribute, element, text). */
88      private NodeType _nodeType = null;
89  
90      /** The namespace prefix that is to be used when marshaling */
91      private String _nsPrefix = null;
92  
93      /** The namespace URI used for both marshaling and unmarshaling. */
94      private String _nsURI = null;
95  
96      /** The "user-set" properties of this XMLFieldDescriptor. */
97      private Properties _xmlProperties = null;
98  
99      /** The XML Schema type of this field value. */
100     private String _schemaType = null;
101 
102     /** The XML Schema type of the components for XML schema lists. */
103     private String _componentType = null;
104 
105     /** The prefix used in case the value of the field described is of type QName. */
106     private String _qNamePrefix = null;
107 
108     /** A flag which indicates the parent class' namespace should be used by default. */
109     private boolean _useParentClassNamespace = false;
110 
111     private FieldValidator _validator = null;
112 
113     /** 
114      * The local XML name of the field; this does not include any
115      * path elements.
116      */
117     private String _xmlName    = null;
118 
119     /** The relative XML path used when wrapping in nested elements, does not
120      * include the name of the field itself.
121      */
122     private String _xmlPath    = null;
123 
124 	private List<String> _substitutes;
125 
126     /**
127      * Indicates whether the field described by this {@link XMLFieldDescriptorImpl} is
128      * created as a result of a <xs:list> definition.
129      */
130     private boolean _derivedFromXSList;
131 	
132 
133     //----------------/
134     //- Constructors -/
135     //----------------/
136 
137     public XMLFieldDescriptorImpl(final Class<?> fieldType, final String fieldName,
138             final String xmlName, final NodeType nodeType) {
139         _matches = new String[0];
140 
141         if (fieldName == null) { 
142             throw new IllegalArgumentException(NULL_NAME_ERR); 
143         }
144         if (fieldType == null) { 
145             throw new IllegalArgumentException(NULL_CLASS_ERR); 
146         }
147 
148         setFieldName(fieldName);
149 
150         if (fieldType == org.exolab.castor.types.AnyNode.class) {
151             // if the field type is an AnyNode Castor must treat it as
152             // an object to avoid changes in the marshaling framework
153             setFieldType(java.lang.Object.class);
154         } else {
155             setFieldType(fieldType);
156         }
157 
158         _nodeType = ((nodeType == null) ? NodeType.Attribute : nodeType );
159 
160         //-- call the setXMLName method to handle checking for full path
161         setXMLName(xmlName);
162     }
163 
164     /**
165      * Construct a new field descriptor for the specified field. This is an XML
166      * field descriptor wrapping a field descriptor and adding XML related
167      * properties and methods.
168      *
169      * @param fieldDesc The field descriptor
170      * @param xmlName The XML name of the field
171      * @param nodeType The node type of this field
172      * @param primitiveNodeType
173      * @throws MappingException Invalid mapping information
174      */
175     public XMLFieldDescriptorImpl(final FieldDescriptor fieldDesc, final String xmlName,
176             final NodeType nodeType, final NodeType primitiveNodeType) throws MappingException {
177         _matches = new String[0];
178 
179         if (fieldDesc instanceof XMLFieldDescriptor) {
180             setContainingClassDescriptor(fieldDesc.getContainingClassDescriptor());
181         }
182 
183         setFieldName(fieldDesc.getFieldName());
184 
185         if (fieldDesc.getFieldType() == org.exolab.castor.types.AnyNode.class) {
186             // if the field type is an AnyNode Castor must treat it as
187             // an object to avoid changes in the marshaling framework
188             setFieldType(java.lang.Object.class);
189         } else {
190             setFieldType(fieldDesc.getFieldType());
191         }
192 
193         ClassDescriptor cd = fieldDesc.getClassDescriptor();
194         if (cd != null) {
195             if (cd instanceof XMLClassDescriptor) {
196                 setClassDescriptor(cd);
197             } else {
198                 setClassDescriptor(new XMLClassDescriptorAdapter(cd, null, primitiveNodeType));
199             }
200         }
201 
202         setHandler(fieldDesc.getHandler());
203         // Check for instances of java.util.Date. This logic really doesn't belong here,
204         // as it can interfere with user specified handlers. Instead it should go into
205         // XMLMappingLoader.
206         if (getFieldType() != null) {
207             if (java.util.Date.class.isAssignableFrom(getFieldType())) {
208                 if (getHandler() instanceof FieldHandlerImpl) {
209                     setHandler(new DateFieldHandler(getHandler()));
210                 }
211             }
212         }
213 
214         setTransient(fieldDesc.isTransient());
215         setImmutable(fieldDesc.isImmutable());
216         setRequired(fieldDesc.isRequired());
217         setMultivalued(fieldDesc.isMultivalued());
218 
219         //-- handle xml name
220         if (xmlName == null) {
221             setXMLName(getFieldName());
222         } else {
223             setXMLName(xmlName);
224         }
225 
226         if (nodeType == null) {
227             if (isMultivalued()) {
228                 _nodeType = NodeType.Element;
229             } else {
230                 _nodeType = NodeType.Attribute;
231             }
232         } else {
233             _nodeType = nodeType;
234         }
235 
236         if (isRequired()) {
237             _validator = new FieldValidator();
238             _validator.setMinOccurs(1);
239             _validator.setDescriptor(this);
240         }
241     }
242 
243     /**
244      * Sets whether or not the value of the field represented by this
245      * FieldDescriptor should be set via the constructor of the containing
246      * ClassDescriptor. The index value greater than 0 specifies the index
247      * within the argument array that the value of this field should be.
248      * <p>
249      * Note: This only applies to attribute mapped fields at this time.
250      *
251      * @param index the index within the argument array. A value less than zero
252      *        indicates that this field should not be part of the constructor
253      *        arguments.
254      */
255     public void setConstructorArgumentIndex(final int index) {
256         if (_nodeType != NodeType.Attribute) {
257             String err = "constructor arguments only valid for attribute mapped fields.";
258             throw new IllegalStateException(err);
259         }
260         _argIndex = index;
261     }
262 
263     /**
264      * @see org.exolab.castor.xml.XMLFieldDescriptor#getConstructorArgumentIndex()
265      * {@inheritDoc}
266      */
267     public int getConstructorArgumentIndex() {
268         return _argIndex;
269     }
270 
271     /**
272      * @see org.exolab.castor.xml.XMLFieldDescriptor#isConstructorArgument()
273      * {@inheritDoc}
274      */
275     public boolean isConstructorArgument() {
276         return (_argIndex >= 0);
277     }
278 
279     /**
280      * Sets the location path for the field being described.
281      * <p>
282      * In most cases, this isn't needed. However sometimes a field may be mapped
283      * to a nested element. In which case the value of the location path should
284      * be the nested element name. If more than one level of nesting is needed
285      * each nested element name should be separated by a path separator (forward
286      * slash '/').
287      * <p>
288      * The location path name is "relative" to the parent Class. The name of the
289      * parent should not be included in the path.
290      * <p>
291      * For example, give the following two classes: <code>
292      *    class Root {
293      *        Bar bar;
294      *    }
295      *
296      *    class Bar {
297      *       String value;
298      *    }
299      * </code>
300      *
301      * And the following XML:
302      *
303      * <code>
304      *    &lt;root&gt;
305      *       &lt;foo&gt;
306      *          &lt;bar&gt; value of bar &lt;/bar&gt;
307      *       &lt;/foo&gt;
308      *    &lt;/root&gt;
309      * </code>
310      *
311      * Since foo has no associated class, the path for 'bar' would be: "foo"
312      *
313      * @param path the "relative" location path for the field.
314      * @see #getLocationPath
315      */
316     public void setLocationPath(final String path) {
317         //-- need to add some validation to the path at some point.
318         _xmlPath = path;
319     }
320 
321     /**
322      * @see org.exolab.castor.xml.XMLFieldDescriptor#getLocationPath()
323      * {@inheritDoc}
324      */
325     public String getLocationPath() {
326         return _xmlPath;
327     }
328 
329     /**
330      * Sets the namespace prefix used when marshaling as XML.
331      *
332      * @param nsPrefix The namespace prefix used when marshaling the
333      *        "described" object.
334      */
335     public void setNameSpacePrefix(final String nsPrefix) {
336         _nsPrefix = nsPrefix;
337     }
338 
339     /**
340      * @see org.exolab.castor.xml.XMLFieldDescriptor#getNameSpacePrefix()
341      * {@inheritDoc}
342      */
343     public String getNameSpacePrefix() {
344         return _nsPrefix;
345     }
346 
347     /**
348      * Sets whether or not the namespace for the parent "containing" class
349      * should be used during marshaling/unmarshaling when no specific
350      * namespace URI has been set for this field.
351      */
352     public void setUseParentsNamespace(final boolean useParentsNamespace) {
353         _useParentClassNamespace = useParentsNamespace;
354     }
355 
356     /**
357      * Sets the namespace URI used when marshaling and unmarshaling as XML.
358      *
359      * @param nsURI The namespace URI used when marshaling and unmarshaling the
360      *        "described" Object.
361      */
362     public void setNameSpaceURI(final String nsURI) {
363         _nsURI = nsURI;
364     }
365 
366     /**
367      * @see org.exolab.castor.xml.XMLFieldDescriptor#getNameSpaceURI()
368      * {@inheritDoc}
369      */
370     public String getNameSpaceURI() {
371         ClassDescriptor parent = getContainingClassDescriptor();
372         if ((_nsURI == null) && (parent != null) && _useParentClassNamespace) {
373             Class<?> type = getFieldType();
374             boolean test = ! (isAnyNode(type));
375             if ((_nodeType == NodeType.Element) && test) {
376                 if (parent instanceof XMLClassDescriptor) {
377                     return ((XMLClassDescriptor) parent).getNameSpaceURI();
378                 }
379             }
380         }
381         return _nsURI;
382     }
383 
384     /**
385      * Sets the XML node type for the described field.
386      *
387      * @param nodeType the NodeType for the described field.
388      */
389     public void setNodeType(final NodeType nodeType) {
390         _nodeType = ((nodeType == null) ? NodeType.Attribute : nodeType);
391     }
392 
393     /**
394      * @see org.exolab.castor.xml.XMLFieldDescriptor#getNodeType()
395      * {@inheritDoc}
396      */
397     public NodeType getNodeType() {
398         return _nodeType;
399     }
400 
401     /**
402      * Sets the value property with the given name.
403      *
404      * @param propertyName The name of the property to set the value of.
405      * @param value The value of the property.
406      * @see #getProperty
407      */
408     public void setXMLProperty(final String propertyName, final String value) {
409         if (propertyName == null) {
410             String err = "The argument 'propertyName' must not be null.";
411             throw new IllegalArgumentException(err);
412         }
413 
414         if (_xmlProperties == null) {
415             _xmlProperties = new Properties();
416         }
417 
418         if (value == null) {
419             _xmlProperties.remove(propertyName);
420         } else {
421             _xmlProperties.put(propertyName, value);
422         }
423     }
424 
425     /**
426      * @see org.exolab.castor.xml.XMLFieldDescriptor#getProperty(java.lang.String)
427      * {@inheritDoc}
428      */
429     public String getXMLProperty(final String propertyName) {
430         if ((_xmlProperties == null) || (propertyName == null)) { 
431             return null; 
432         }
433         return _xmlProperties.getProperty(propertyName);
434     }
435 
436     /**
437      * Sets the type of the XML Schema type of the value for the field being
438      * described.
439      *
440      * @param schemaType The value type.
441      */
442     public void setSchemaType(final String schemaType) {
443         _schemaType =schemaType;
444     }
445 
446     /**
447      * Sets the type of the XML Schema type of the value for the field being
448      * described.
449      *
450      * @param componentType The component type for &lt;xs:list&gt;s.
451      */
452     public void setComponentType(final String componentType) {
453         _componentType = componentType;
454     }
455 
456     /**
457      * @see org.exolab.castor.xml.XMLFieldDescriptor#getSchemaType()
458      * {@inheritDoc}
459      */
460     public String getSchemaType() {
461          return _schemaType;
462      }
463 
464     /**
465      * {@inheritDoc}
466      * @see org.exolab.castor.xml.XMLFieldDescriptor#getComponentType()
467      */
468     public String getComponentType() {
469          return _componentType;
470      }
471 
472     public void setValidator(final FieldValidator validator) {
473         if (_validator != null) {
474             _validator.setDescriptor(null);
475         }
476         _validator = validator;
477         if (_validator != null) {
478             _validator.setDescriptor(this);
479         }
480     }
481 
482     /**
483      * @see org.exolab.castor.xml.XMLFieldDescriptor#getValidator()
484      * {@inheritDoc}
485      */
486     public FieldValidator getValidator() {
487         return _validator;
488     }
489 
490     /**
491      * Sets the xml name for the described field.
492      *
493      * @param xmlName the XML name for the described field.
494      */
495     public void setXMLName(final String xmlName) {
496         _xmlName = xmlName;
497     }
498 
499     /**
500      * @see org.exolab.castor.xml.XMLFieldDescriptor#getXMLName()
501      * {@inheritDoc}
502      */
503     public String getXMLName() {
504         return _xmlName;
505     }
506 
507     /**
508      * Set if the field is a container field or not.
509      *
510      * @param isContainer a boolean indicating whether or not the field is a
511      *        container field.
512      */
513     public void setContainer(final boolean isContainer) {
514         _container = isContainer;
515     }
516 
517     /**
518      * @see org.exolab.castor.xml.XMLFieldDescriptor#isContainer()
519      * {@inheritDoc}
520      */
521     public boolean isContainer() {
522         return _container;
523     }
524 
525     /**
526      * Sets the incremental flag which indicates whether this member can be
527      * added before the unmarshaler is finished unmarshaling it.
528      *
529      * @param incremental the boolean which if true indicated that this member
530      *        can safely be added before the unmarshaler is finished
531      *        unmarshaling it.
532      */
533     public void setIncremental(final boolean incremental) {
534         _incremental = incremental;
535     }
536 
537     /**
538      * @see org.exolab.castor.xml.XMLFieldDescriptor#isIncremental()
539      * {@inheritDoc}
540      */
541     public boolean isIncremental() {
542         return _incremental;
543     }
544 
545     /**
546      * Sets whether or not this field has been mapped in a Map or Hashtable.
547      *
548      * @param mapped a boolean that when true indicates this field is a
549      *        Hashtable or Map.
550      */
551     public void setMapped(final boolean mapped) {
552         _mapped = mapped;
553     }
554 
555     /**
556      * @see org.exolab.castor.xml.XMLFieldDescriptor#isMapped()
557      * {@inheritDoc}
558      */
559     public boolean isMapped() {
560         return _mapped;
561     }
562 
563     /**
564      * Sets whether or not the described field is allowed to be nil. A nillable
565      * field can have empty content (text or element content), but may have
566      * attribute values, and still be considered value, even if the child
567      * elements are required.
568      *
569      * @param nillable a boolean indicating whether or not the described field
570      *        may be nillable.
571      */
572     public void setNillable(final boolean nillable) {
573         _nillable = nillable;
574     }
575 
576     /**
577      * @see org.exolab.castor.xml.XMLFieldDescriptor#isNillable()
578      * {@inheritDoc}
579      */
580     public boolean isNillable() {
581         return _nillable;
582     }
583 
584     /**
585      * Sets the flag indicating that the field described by this descriptor is a
586      * reference to another field in the object model.
587      *
588      * @param isReference true if the field is a reference to another field.
589      */
590     public void setReference(final boolean isReference) {
591         _isReference = isReference;
592     }
593 
594     /**
595      * @see org.exolab.castor.xml.XMLFieldDescriptor#isReference()
596      * {@inheritDoc}
597      */
598     public boolean isReference() {
599         return _isReference;
600     }
601 
602     /**
603      * Sets the prefix used in case the value of the field described by this
604      * descriptor is of type QName.
605      *
606      * @param qNamePrefix
607      */
608     public void setQNamePrefix(final String qNamePrefix) {
609         _qNamePrefix = qNamePrefix;
610     }
611 
612     /**
613      * Returns the prefix used in case the value of the field described by this
614      * descriptor is of type QName. This is helpful for the marshaler but not
615      * mandatory.
616      *
617      * @return the prefix used in the QName value.
618      */
619     public String getQNamePrefix() {
620         return _qNamePrefix;
621     }
622 
623     /**
624      * This is a space separated list of xml names that this Field descriptor
625      * matches. A '*' is wild.
626      *
627      * @param matchExpr the space separated list of xml names, matched by this
628      *        descriptor.
629      */
630     public void setMatches(String matchExpr) {
631         _isWild = false;
632 
633         if ((matchExpr == null) || (matchExpr.length() == 0)) {
634             return;
635         }
636 
637         StringTokenizer st = new StringTokenizer(matchExpr);
638         List<String> names = new ArrayList<String>();
639         while (st.hasMoreTokens()) {
640             String token = st.nextToken();
641             if (WILD_CARD.equals(token)) {
642                 _isWild = true;
643                 break;
644             }
645             names.add(token);
646         }
647         _matches = new String[names.size()];
648         names.toArray(_matches);
649     }
650 
651     /**
652      * @see org.exolab.castor.xml.XMLFieldDescriptor#matches(java.lang.String)
653      * {@inheritDoc}
654      */
655     public boolean matches(final String xmlName) {
656         if (xmlName != null) {
657             if (_isWild) {
658                 return true;
659             } else if (_matches.length > 0) {
660                 for (int i = 0; i < _matches.length; i++) {
661                     if (xmlName.equals(_matches[i])) {
662                         return true;
663                     }
664                 }
665             } else {
666                 return xmlName.equals(_xmlName);
667             }
668         }
669         return false;
670     }
671 
672     /**
673      * @see org.exolab.castor.xml.XMLFieldDescriptor#matches(java.lang.String, java.lang.String)
674      * {@inheritDoc}
675      */
676     public boolean matches(final String xmlName, final String namespace) {
677         // compare namespaces
678         if (namespace == null) {
679             if ((_nsURI != null) && (_nsURI.length() > 0)) {
680                 return false;
681             }
682         } else if (_nsURI == null) {
683             if ((namespace.length() > 0) && (!_isWild)) {
684                 return false;
685             }
686         } else if (!_nsURI.equals(namespace)) {
687             return false;
688         }
689 
690         // if we make this far the namespaces match, now compare names
691         return matches(xmlName);
692     }
693 
694     /**
695      * Returns true if two XMLFieldDescriptors should be treated as equal. Any
696      * XMLFieldDescriptor that handles the same field is considered equal.
697      * @param obj The object to compare to <code>this</code>
698      *
699      * @return true if two XMLFieldDescriptors should be treated as equal.
700      */
701     public boolean equals(final Object obj) {
702         if (obj == this) {
703             return true;
704         }
705 
706         if ((obj == null) || (!(obj instanceof XMLFieldDescriptor))) {
707             return false;
708         }
709 
710         XMLFieldDescriptor descriptor = (XMLFieldDescriptor) obj;
711 
712         // check field names
713         if (!getFieldName().equals(descriptor.getFieldName())) {
714             return false;
715         }
716 
717         // check field types
718         if (!getFieldType().equals(descriptor.getFieldType())) {
719             return false;
720         }
721 
722         // check field handler
723         FieldHandler tmpHandler = descriptor.getHandler();
724         if (getHandler() == null) {
725             return (tmpHandler == null);
726         } else if (tmpHandler == null) {
727             return false;
728         }
729 
730         // The following line causes some issues when used against a FieldHandlerImpl
731         // because the equals method for FieldHandlerImpl is the default. Temporarily
732         // replace it with a slightly more generic comparison but this should probably
733         // change in the future. (kv)
734         // return (_handler.equals(tmpHandler));
735         return (getHandler().getClass().isInstance(tmpHandler));
736     }
737 
738     /**
739      * Returns the hashCode for this XMLFieldDescriptor
740      * @return the hashCode for this XMLFieldDescriptor
741      */
742     public int hashCode() {
743         int hash = 17;
744         hash = 17 * getFieldName().hashCode();
745         hash = hash * 17 * getFieldType().hashCode();
746         if (getHandler() != null) { hash = hash * 17 * getHandler().hashCode(); }
747         return hash;
748     }
749 
750     public String toString() {
751         StringBuffer buffer = new StringBuffer(32);
752         buffer.append("XMLFieldDesciptor: ");
753         buffer.append(getFieldName());
754         buffer.append(" AS ");
755         buffer.append(_xmlName);
756         if (getNameSpaceURI() != null) {
757             buffer.append("{" + getNameSpaceURI() + "}");
758         }
759         return buffer.toString();
760     }
761 
762     /**
763      * Returns true if the given class should be treated as a primitive type.
764      * This method will return true for all Java primitive types, the set of
765      * primitive object wrappers, as well as Strings.
766      *
767      * @return true If the given class should be treated as a primitive type.
768      */
769     private static boolean isPrimitive(final Class<?> type) {
770         if (type == null) {
771             return false;
772         }
773         if (type.isPrimitive()) {
774             return true;
775         }
776         if (type == String.class) {
777             return true;
778         }
779         if ((type == Boolean.class) || (type == Character.class)) {
780             return true;
781         }
782 
783         // Any class which extends Number should be treated as a primitive.
784         return (type.getSuperclass() == Number.class);
785     }
786 
787     /**
788      * Return true if the given class is a "built-in" type. A built-in type is
789      * one in which Castor provides the default descriptor for.
790      *
791      * @param type The class to check.
792      * @return true If the given class is a built-in type.
793      */
794     private static boolean isBuiltInType(final Class<?> type) {
795         if (type == null) {
796             return false;
797         }
798         //-- All built-in Java types, such as java.util.Date,
799         //-- java.sql.Date, various Collection classes, etc.
800         return (CoreDescriptors.getDescriptor(type) != null);
801     }
802 
803     private static boolean isMappedItem(final Class<?> fieldType) {
804         return (fieldType == MapItem.class);
805     }
806 
807     private static boolean isAnyNode(final Class<?> type) {
808        return (type == Object.class);
809     }
810     
811     /**
812      * Returns the possible substitution groups for this class.
813      * @return the possible substitution groups for this class.
814      */
815     public List<String> getSubstitutes() {
816         return _substitutes;
817     }
818 
819     /**
820      * Sets the possible substitution groups for this class.
821      * @param substitutes Possible substitution groups for this class.
822      */
823     public void setSubstitutes(List<String> substitutes) {
824         _substitutes = substitutes;
825     }
826 
827     /**
828      * {@inheritDoc}
829      * 
830      * @see org.exolab.castor.xml.XMLFieldDescriptor#setDerivedFromXSList(boolean)
831      */
832     public void setDerivedFromXSList(final boolean derivedFromXSList) {
833         _derivedFromXSList = derivedFromXSList;
834     }
835 
836     /**
837      * {@inheritDoc}
838      * 
839      * @see org.exolab.castor.xml.XMLFieldDescriptor#isDerivedFromXSList()
840      */
841     public boolean isDerivedFromXSList() {
842         return _derivedFromXSList;
843     }
844 
845 }