View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.xml;
37  
38  import java.util.ArrayList;
39  import java.util.HashMap;
40  import java.util.HashSet;
41  import java.util.Iterator;
42  import java.util.Map;
43  import java.util.List;
44  import java.util.Set;
45  
46  import org.castor.xml.BackwardCompatibilityContext;
47  import org.castor.xml.InternalContext;
48  import org.castor.xml.AbstractInternalContext;
49  import org.castor.xml.JavaNaming;
50  import org.exolab.castor.mapping.ClassDescriptor;
51  import org.exolab.castor.mapping.CollectionHandler;
52  import org.exolab.castor.mapping.FieldDescriptor;
53  import org.exolab.castor.mapping.MappingException;
54  import org.exolab.castor.mapping.loader.CollectionHandlers;
55  import org.exolab.castor.util.ReflectionUtil;
56  
57  
58  /**
59   * A core class for common code shared throughout the Marshalling Framework
60   * 
61   * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
62   * @version $Revision$ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
63   */
64  abstract class MarshalFramework {
65  
66  
67  
68    // --------------------------/
69    // - Public class variables -/
70    // --------------------------/
71  
72    /**
73     * JDK version 1.5 .
74     */
75    private static final double JDK_VERSION_1_5 = 1.5;
76  
77    /**
78     * The XSI Namespace URI.
79     **/
80    public static final String XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance";
81  
82    /**
83     * The name of the Schema location attribute.
84     **/
85    public static final String XSI_SCHEMA_LOCATION = "schemaLocation";
86  
87    /**
88     * The name of the no namespace schema location attribute.
89     **/
90    public static final String XSI_NO_NAMESPACE_SCHEMA_LOCATION = "noNamespaceSchemaLocation";
91  
92    /**
93     * The xml:lang attribute name.
94     */
95    public static final String XML_LANG_ATTR = "xml:lang";
96  
97    /**
98     * The xml:lang attribute, without the "xml:" prefix.
99     */
100   public static final String LANG_ATTR = "lang";
101 
102   /**
103    * The xsi:nil attribute, without the "xsi:" prefix.
104    */
105   public static final String NIL_ATTR = "nil";
106 
107   /**
108    * The xsi:nil attribute.
109    */
110   public static final String XSI_NIL_ATTR = "xsi:nil";
111 
112   /**
113    * The xml:space attribute name.
114    */
115   public static final String XML_SPACE_ATTR = "xml:space";
116 
117   /**
118    * The xml:space attribute name, without the "xml:" prefix.
119    */
120   public static final String SPACE_ATTR = "space";
121 
122   /**
123    * The xsi:type attribute name, without the "xsi:" prefix.
124    */
125   public static final String TYPE_ATTR = "type";
126 
127   /**
128    * The value of 'true'.
129    */
130   public static final String TRUE_VALUE = "true";
131 
132   // -----------------------------/
133   // - Protected class variables -/
134   // -----------------------------/
135 
136   /**
137    * A constant to indicate a wrong name without setting null.
138    */
139   static final String INTERNAL_XML_NAME = "-error-if-this-is-used-";
140 
141   /**
142    * The default prefix used for specifying the xsi:type as a classname instead of a schema name.
143    * This is a Castor specific hack.
144    */
145   static final String JAVA_PREFIX = "java:";
146 
147   /**
148    * The name of the QName type.
149    */
150   static final String QNAME_NAME = "QName";
151 
152   /**
153    * An empty array of field descriptors.
154    */
155   static final XMLFieldDescriptor[] NO_FIELD_DESCRIPTORS = new XMLFieldDescriptor[0];
156 
157   // -----------------------------/
158   // - Private variables -/
159   // -----------------------------/
160 
161   /**
162    * The {@link AbstractInternalContext} to use at all un-marshal actions.
163    * 
164    * @since 1.1.3
165    */
166   private InternalContext _internalContext;
167 
168   // -----------------------------/
169   // - Public methods -/
170   // -----------------------------/
171 
172   /**
173    * We need some stuff initialized here. MarshalFramework requires internally an
174    * {@link InternalContext}, so either one is given or {@link BackwardCompatibilityContext} is
175    * instantiated! Mind that instantiating {@link BackwardCompatibilityContext} means to (re-)read
176    * configuration files.
177    * 
178    * @param internalContext either an {@link InternalContext} comes from outside or
179    *        {@link BackwardCompatibilityContext} is instantiated
180    */
181   public MarshalFramework(final InternalContext internalContext) {
182     if (internalContext == null) {
183       _internalContext = new BackwardCompatibilityContext();
184     } else {
185       _internalContext = internalContext;
186     }
187   }
188 
189   /**
190    * To get the {@link JavaNaming} instance to be used.
191    * 
192    * @return the JavaNaming to be used
193    */
194   public JavaNaming getJavaNaming() {
195     return _internalContext.getJavaNaming();
196   }
197 
198   /**
199    * To set the {@link JavaNaming} instance to be used.
200    * 
201    * @param javaNaming the JavaNaming to be used TODO: joachim remove me if possible!
202    */
203   private void setJavaNaming(final JavaNaming javaNaming) {
204     _internalContext.setJavaNaming(javaNaming);
205   }
206 
207   /**
208    * To get the {@link AbstractInternalContext} to use.
209    * 
210    * @return the {@link AbstractInternalContext} to use
211    */
212   public InternalContext getInternalContext() {
213     return _internalContext;
214   }
215 
216   /**
217    * To set the {@link AbstractInternalContext} to use.
218    * 
219    * @param internalContext the {@link AbstractInternalContext} to use
220    */
221   public void setInternalContext(final InternalContext internalContext) {
222     _internalContext = internalContext;
223   }
224 
225   /**
226    * Returns true if the given Class is a considered a collection by the marshalling framework.
227    * 
228    * @param clazz the Class to check
229    * @return true if the given Class is considered a collection. TODO: joachim: this code exists
230    *         somewhere else too!!
231    */
232   public static boolean isCollection(final Class clazz) {
233     return CollectionHandlers.hasHandler(clazz);
234   } // -- isCollection
235 
236   /**
237    * Returns the CollectionHandler associated with the given collection, or null if no such handler
238    * exists.
239    * 
240    * @param clazz the Class to check
241    * @return the CollectionHandler for the associated type.
242    */
243   public CollectionHandler getCollectionHandler(final Class clazz) {
244     CollectionHandler handler = null;
245     try {
246       handler = CollectionHandlers.getHandler(clazz);
247     } catch (MappingException mx) {
248       // -- Not a collection, or no handler exists, return null.
249     }
250     return handler;
251   } // -- getCollectionHandler
252 
253 
254   /**
255    * Returns true if the given class should be treated as a primitive type. This method will return
256    * true for all Java primitive types, the set of primitive object wrappers, as well as Strings.
257    * 
258    * @param type the Class to check
259    * @return true if the given class should be treated as a primitive type TODO: joachim: this code
260    *         exists somewhere else too!!
261    **/
262   static boolean isPrimitive(final Class type) {
263 
264     if (type == null) {
265       return false;
266     }
267 
268     // -- java primitive
269     if (type.isPrimitive()) {
270       return true;
271     }
272 
273     // -- we treat strings as primitives
274     if (type == String.class) {
275       return true;
276     }
277 
278     // -- primtive wrapper classes
279     if ((type == Boolean.class) || (type == Character.class)) {
280       return true;
281     }
282 
283     Class superClass = type.getSuperclass();
284     if (superClass == Number.class) {
285       return true;
286     }
287 
288     if (superClass != null) {
289       return superClass.getName().equals("java.lang.Enum");
290     }
291 
292     return false;
293 
294   } // -- isPrimitive
295 
296   /**
297    * Returns true if the given class should be treated as an enum type. This method will return true
298    * for all Java 5 (or later) enums, and for enum-style classes.
299    * 
300    * @param type the Class to check
301    * @return true if the given class should be treated as an enum
302    **/
303   static boolean isEnum(final Class type) {
304 
305     if (type == null) {
306       return false;
307     }
308 
309     float javaVersion =
310         Float.valueOf(System.getProperty("java.specification.version")).floatValue();
311     if (javaVersion >= JDK_VERSION_1_5) {
312       try {
313         Boolean isEnum = ReflectionUtil.isEnumViaReflection(type);
314         return isEnum.booleanValue();
315       } catch (Exception e) {
316         // nothing to report; implies that there's no such method
317       }
318     }
319 
320     // TODO: add code to cover 1.4 enum-stype classes as well.
321 
322     return false;
323 
324   } // -- isPrimitive
325 
326   // /**
327   // * Calls isEnum() method on target class vi areflection to find out
328   // * whether the given type is a Java 5 enumeration.
329   // * @param type The type to analyze.
330   // * @return True if the type given is a Java 5.0 enum.
331   // * @throws NoSuchMethodException If the method can not be found.
332   // * @throws IllegalAccessException If access to this method is illegal
333   // * @throws InvocationTargetException If the target method can not be invoked.
334   // */
335   // private static Boolean isEnumViaReflection(Class type)
336   // throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
337   // Method isEnumMethod = type.getClass().getMethod("isEnum", (Class[]) null);
338   // return (Boolean) isEnumMethod.invoke(type, (Object[]) null);
339   // }
340   //
341 
342   /**
343    * Returns true if any of the fields associated with the given XMLClassDescriptor are located at,
344    * or beneath, the given location.
345    *
346    * @param location the location to compare against
347    * @param classDesc the XMLClassDescriptor in which to check the field locations
348    * @return true if any of the fields has a location associated
349    */
350   static final boolean hasFieldsAtLocation(final String location,
351       final XMLClassDescriptor classDesc) {
352     // -- check elements
353     XMLFieldDescriptor[] descriptors = classDesc.getElementDescriptors();
354     for (int i = 0; i < descriptors.length; i++) {
355       if (descriptors[i] == null) {
356         continue;
357       }
358       String tmpLocation = descriptors[i].getLocationPath();
359       if ((tmpLocation != null) && (tmpLocation.startsWith(location))) {
360         return true;
361       }
362     }
363 
364     // -- check attributes
365     descriptors = classDesc.getAttributeDescriptors();
366     for (int i = 0; i < descriptors.length; i++) {
367       if (descriptors[i] == null) {
368         continue;
369       }
370       String tmpLocation = descriptors[i].getLocationPath();
371       if ((tmpLocation != null) && (tmpLocation.startsWith(location))) {
372         return true;
373       }
374     }
375 
376     // -- check content/text
377     XMLFieldDescriptor content = classDesc.getContentDescriptor();
378     if (content != null) {
379       String tmpLocation = content.getLocationPath();
380       if ((tmpLocation != null) && (tmpLocation.startsWith(location))) {
381         return true;
382       }
383     }
384     return false;
385   } // -- hasFieldsAtLocation
386 
387   /**
388    * Compares the given namespaces (as strings) for equality. null and empty values are considered
389    * equal.
390    *
391    * @param ns1 the namespace to compare to argument ns2
392    * @param ns2 the namespace to compare to argument ns1
393    * @return true if the namespaces are considert equal TODO: joachim put it into XMLNaming!
394    */
395   public static boolean namespaceEquals(final String ns1, final String ns2) {
396     if (ns1 == null) {
397       return ((ns2 == null) || (ns2.length() == 0));
398     }
399     if (ns2 == null) {
400       return (ns1.length() == 0);
401     }
402     return ns1.equals(ns2);
403   } // -- namespaceEquals
404 
405   /**
406    * Returns true if the given classes are both the same primitive or primitive wrapper class. For
407    * exmaple, if class "a" is an int (Integer.TYPE) and class "b" is either an int or Integer.class
408    * then true will be returned, otherwise false.
409    * 
410    * @param a compare a with b
411    * @param b compare a with b
412    * @return true if both a and b are considered equal
413    */
414   static boolean primitiveOrWrapperEquals(final Class a, final Class b) {
415     if (!isPrimitive(a)) {
416       return false;
417     }
418     if (!isPrimitive(b)) {
419       return false;
420     }
421 
422     if (a == b) {
423       return true;
424     }
425 
426     // -- Boolean/boolean
427     if ((a == Boolean.class) || (a == Boolean.TYPE)) {
428       return ((b == Boolean.class) || (b == Boolean.TYPE));
429     }
430     // -- Byte/byte
431     else if ((a == Byte.class) || (a == Byte.TYPE)) {
432       return ((b == Byte.class) || (b == Byte.TYPE));
433     }
434     // -- Character/char
435     else if ((a == Character.class) || (a == Character.TYPE)) {
436       return ((b == Character.class) || (b == Character.TYPE));
437     }
438     // -- Double/double
439     else if ((a == Double.class) || (a == Double.TYPE)) {
440       return ((b == Double.class) || (b == Double.TYPE));
441     } else if ((a == Float.class) || (a == Float.TYPE)) {
442       return ((b == Float.class) || (b == Float.TYPE));
443     }
444     // -- Integer/int
445     else if ((a == Integer.class) || (a == Integer.TYPE)) {
446       return ((b == Integer.class) || (b == Integer.TYPE));
447     }
448     // -- Long/long
449     else if ((a == Long.class) || (a == Long.TYPE)) {
450       return ((b == Long.class) || (b == Long.TYPE));
451     }
452     // -- Short/short
453     else if ((a == Short.class) || (a == Short.TYPE)) {
454       return ((b == Short.class) || (b == Short.TYPE));
455     }
456 
457     return false;
458   } // -- primitiveOrWrapperEquals
459 
460   /**
461    * 
462    */
463   private static final InheritanceMatch[] NO_MATCH_ARRAY = new InheritanceMatch[0];
464 
465   /**
466    * Search there is a field descriptor which can accept one of the class descriptor which match the
467    * given name and namespace.
468    * 
469    * @param name XML name of the field
470    * @param namespace namespace of the field
471    * @param classDesc the class descriptor to match against
472    * @param cdResolver the class descriptor resolver to use
473    * @return An array of InheritanceMatch.
474    * @throws MarshalException if the resolver called fails fatally
475    */
476   protected InheritanceMatch[] searchInheritance(final String name, final String namespace,
477       final XMLClassDescriptor classDesc) throws MarshalException {
478     Iterator classDescriptorIterator = null;
479 
480     try {
481       // -- A little required logic for finding Not-Yet-Loaded
482       // -- descriptors
483       String className = getJavaNaming().toJavaClassName(name);
484       // -- should use namespace-to-prefix mappings, but
485       // -- just create package for now.
486       Class clazz = classDesc.getJavaClass();
487       String pkg = null;
488       if (clazz != null) {
489         while (clazz.getDeclaringClass() != null) {
490           clazz = clazz.getDeclaringClass();
491         }
492         pkg = clazz.getName();
493         int idx = pkg.lastIndexOf('.');
494         if (idx >= 0) {
495           pkg = pkg.substring(0, idx + 1);
496           className = pkg + className;
497         }
498       }
499       getInternalContext().getXMLClassDescriptorResolver().resolve(className,
500           classDesc.getClass().getClassLoader());
501       // -- end Not-Yet-Loaded descriptor logic
502 
503       // -- resolve all by XML name + namespace URI
504       classDescriptorIterator = getInternalContext().getXMLClassDescriptorResolver()
505           .resolveAllByXMLName(name, namespace, null);
506     } catch (ResolverException rx) {
507       Throwable actual = rx.getCause();
508       if (actual instanceof MarshalException) {
509         throw (MarshalException) actual;
510       }
511       if (actual != null) {
512         throw new MarshalException(actual);
513       }
514       throw new MarshalException(rx);
515     }
516 
517     List<InheritanceMatch> inheritanceList = null;
518     XMLFieldDescriptor descriptor = null;
519     XMLFieldDescriptor[] descriptors = classDesc.getElementDescriptors();
520     XMLClassDescriptor cdInherited = null;
521 
522     if (classDescriptorIterator.hasNext()) {
523       while (classDescriptorIterator.hasNext() && (descriptor == null)) {
524         cdInherited = (XMLClassDescriptor) classDescriptorIterator.next();
525         Class subclass = cdInherited.getJavaClass();
526 
527         for (int i = 0; i < descriptors.length; i++) {
528 
529           if (descriptors[i] == null) {
530             continue;
531           }
532 
533           // -- skip descriptors with special internal name
534           if (INTERNAL_XML_NAME.equals(descriptors[i].getXMLName())) {
535             continue;
536           }
537 
538           // -- check for inheritence
539           Class superclass = descriptors[i].getFieldType();
540 
541           // It is possible that the superclass is of type object if we use any node.
542           if (superclass.isAssignableFrom(subclass) && (superclass != Object.class)) {
543             descriptor = descriptors[i];
544             if (inheritanceList == null) {
545               inheritanceList = new ArrayList<>(3);
546             }
547             inheritanceList.add(new InheritanceMatch(descriptor, cdInherited));
548           }
549         }
550       }
551       // -- reset inherited class descriptor, if necessary
552       if (descriptor == null) {
553         cdInherited = null;
554       }
555     }
556 
557     if (inheritanceList != null) {
558       InheritanceMatch[] result = new InheritanceMatch[inheritanceList.size()];
559       return inheritanceList.toArray(result);
560     }
561     return NO_MATCH_ARRAY;
562   }
563 
564   /**
565    * Used to store the information when we find a possible inheritance. It store the
566    * XMLClassDescriptor of the object to instantiate and the XMLFieldDescriptor of the parent, where
567    * the instance of the XMLClassDescriptor will be put.
568    */
569   public static class InheritanceMatch {
570     /**
571      * The field descriptor of the parent.
572      */
573     public XMLFieldDescriptor parentFieldDesc;
574     /**
575      * The class descriptor to instantiate.
576      */
577     public XMLClassDescriptor inheritedClassDesc;
578 
579     public InheritanceMatch(XMLFieldDescriptor fieldDesc, XMLClassDescriptor classDesc) {
580       parentFieldDesc = fieldDesc;
581       inheritedClassDesc = classDesc;
582     }
583   }
584 
585 
586 
587   /**
588    * An internal implementation of XMLClassDescriptor used by the Unmarshaller and Marshaller...
589    */
590   class InternalXMLClassDescriptor implements XMLClassDescriptor {
591 
592     private XMLClassDescriptor _classDesc = null;
593 
594     /**
595      * Cached arrays.
596      */
597     private XMLFieldDescriptor[] _attributes = null;
598     /**
599      * Cached arrays.
600      */
601     private XMLFieldDescriptor[] _elements = null;
602     /**
603      * Cached arrays.
604      */
605     private FieldDescriptor[] _fields = null;
606 
607     /**
608      * Map holding the properties set and read by Natures.
609      */
610     private final Map<String, Object> _properties = new HashMap<>();
611 
612     /**
613      * Map holding the available natures.
614      */
615     private final Set<String> _natures = new HashSet<>();
616 
617     /**
618      * Creates a new InternalXMLClassDescriptor for the given XMLClassDescriptor.
619      */
620     protected InternalXMLClassDescriptor(XMLClassDescriptor classDesc) {
621       if (classDesc == null) {
622         String err = "The argument 'classDesc' must not be null.";
623         throw new IllegalArgumentException(err);
624       }
625 
626       // -- prevent wrapping another InternalXMLClassDescriptor,
627       while (classDesc instanceof InternalXMLClassDescriptor) {
628         classDesc = ((InternalXMLClassDescriptor) classDesc).getClassDescriptor();
629       }
630       _classDesc = classDesc;
631     }
632 
633     /**
634      * Returns the XMLClassDescriptor that this InternalXMLClassDescriptor wraps.
635      *
636      * @return the XMLClassDescriptor
637      */
638     public XMLClassDescriptor getClassDescriptor() {
639       return _classDesc;
640     } // -- getClassDescriptor
641 
642 
643     /**
644      * Returns the set of XMLFieldDescriptors for all members that should be marshalled as XML
645      * attributes. This includes namespace nodes.
646      *
647      * @return an array of XMLFieldDescriptors for all members that should be marshalled as XML
648      *         attributes.
649      */
650     public XMLFieldDescriptor[] getAttributeDescriptors() {
651       if (_attributes == null) {
652         _attributes = _classDesc.getAttributeDescriptors();
653       }
654       return _attributes;
655     } // -- getAttributeDescriptors
656 
657     /**
658      * Returns the XMLFieldDescriptor for the member that should be marshalled as text content.
659      *
660      * @return the XMLFieldDescriptor for the member that should be marshalled as text content.
661      */
662     public XMLFieldDescriptor getContentDescriptor() {
663       return _classDesc.getContentDescriptor();
664     } // -- getContentDescriptor
665 
666 
667     /**
668      * Returns the XML field descriptor matching the given xml name and nodeType. If NodeType is
669      * null, then either an AttributeDescriptor, or ElementDescriptor may be returned. Null is
670      * returned if no matching descriptor is available.
671      *
672      * @param name the xml name to match against
673      * @param namespace the xml namespace to match
674      * @param nodeType the NodeType to match against, or null if the node type is not known.
675      * @return the matching descriptor, or null if no matching descriptor is available.
676      *
677      */
678     public XMLFieldDescriptor getFieldDescriptor(final String name, final String namespace,
679         final NodeType nodeType) {
680       return _classDesc.getFieldDescriptor(name, namespace, nodeType);
681     } // -- getFieldDescriptor
682 
683     /**
684      * Returns the set of XMLFieldDescriptors for all members that should be marshalled as XML
685      * elements.
686      *
687      * @return an array of XMLFieldDescriptors for all members that should be marshalled as XML
688      *         elements.
689      */
690     public XMLFieldDescriptor[] getElementDescriptors() {
691       if (_elements == null) {
692         _elements = _classDesc.getElementDescriptors();
693       }
694       return _elements;
695     } // -- getElementDescriptors
696 
697     /**
698      * @return the namespace prefix to use when marshalling as XML.
699      */
700     public String getNameSpacePrefix() {
701       return _classDesc.getNameSpacePrefix();
702     } // -- getNameSpacePrefix
703 
704     /**
705      * @return the namespace URI used when marshalling and unmarshalling as XML.
706      */
707     public String getNameSpaceURI() {
708       return _classDesc.getNameSpaceURI();
709     } // -- getNameSpaceURI
710 
711     /**
712      * Returns a specific validator for the class described by this ClassDescriptor. A null value
713      * may be returned if no specific validator exists.
714      *
715      * @return the type validator for the class described by this ClassDescriptor.
716      */
717     public TypeValidator getValidator() {
718       return _classDesc.getValidator();
719     } // -- getValidator
720 
721     /**
722      * Returns the XML Name for the Class being described.
723      *
724      * @return the XML name.
725      */
726     public String getXMLName() {
727       return _classDesc.getXMLName();
728     } // -- getXMLName
729 
730     /**
731      * Returns true if the wrapped ClassDescriptor was created by introspection.
732      * 
733      * @return true if the wrapped ClassDescriptor was created by introspection.
734      */
735     public boolean introspected() {
736       return Introspector.introspected(_classDesc);
737     } // -- introspected
738 
739     /**
740      * @see org.exolab.castor.xml.XMLClassDescriptor#canAccept( java.lang.String, java.lang.String,
741      *      java.lang.Object)
742      */
743     public boolean canAccept(final String name, final String namespace, final Object object) {
744       return _classDesc.canAccept(name, namespace, object);
745     } // -- canAccept
746 
747     /**
748      * {@inheritDoc}
749      * 
750      * @see org.exolab.castor.xml.XMLClassDescriptor#checkDescriptorForCorrectOrderWithinSequence(org.exolab.castor.xml.XMLFieldDescriptor,
751      *      org.exolab.castor.xml.UnmarshalState, java.lang.String)
752      */
753     public void checkDescriptorForCorrectOrderWithinSequence(
754         final XMLFieldDescriptor elementDescriptor, final UnmarshalState parentState,
755         final String xmlName) throws ValidationException {
756       _classDesc.checkDescriptorForCorrectOrderWithinSequence(elementDescriptor, parentState,
757           xmlName);
758     }
759 
760     // -------------------------------------/
761     // - Implementation of ClassDescriptor -/
762     // -------------------------------------/
763 
764     /**
765      * Returns the Java class represented by this descriptor.
766      *
767      * @return The Java class
768      */
769     public Class getJavaClass() {
770       return _classDesc.getJavaClass();
771     } // -- getJavaClass
772 
773 
774     /**
775      * Returns a list of fields represented by this descriptor.
776      *
777      * @return A list of fields
778      */
779     public FieldDescriptor[] getFields() {
780       if (_fields == null) {
781         _fields = _classDesc.getFields();
782       }
783       return _fields;
784     } // -- getFields
785 
786 
787     /**
788      * Returns the class descriptor of the class extended by this class.
789      *
790      * @return The extended class descriptor
791      */
792     public ClassDescriptor getExtends() {
793       return _classDesc.getExtends();
794     } // -- getExtends
795 
796 
797     /**
798      * Returns the identity field, null if this class has no identity.
799      *
800      * @return The identity field
801      */
802     public FieldDescriptor getIdentity() {
803       return _classDesc.getIdentity();
804     } // -- getIdentity
805 
806     /**
807      * {@inheritDoc}
808      * 
809      * @see org.exolab.castor.xml.XMLClassDescriptor#isChoice()
810      */
811     public boolean isChoice() {
812       return false;
813     }
814 
815     /**
816      * @see org.exolab.castor.builder.info.nature.PropertyHolder# getProperty(java.lang.String)
817      * @param name of the property
818      * @return value of the property
819      */
820     public Object getProperty(final String name) {
821       return _properties.get(name);
822     }
823 
824     /**
825      * @see org.exolab.castor.builder.info.nature.PropertyHolder# setProperty(java.lang.String,
826      *      java.lang.Object)
827      * @param name of the property
828      * @param value of the property
829      */
830     public void setProperty(final String name, final Object value) {
831       _properties.put(name, value);
832     }
833 
834     /**
835      * @see org.exolab.castor.builder.info.nature.NatureExtendable# addNature(java.lang.String)
836      * @param nature ID of the Nature
837      */
838     public void addNature(final String nature) {
839       _natures.add(nature);
840     }
841 
842     /**
843      * @see org.exolab.castor.builder.info.nature.NatureExtendable# hasNature(java.lang.String)
844      * @param nature ID of the Nature
845      * @return true if the Nature ID was added.
846      */
847     public boolean hasNature(final String nature) {
848       return _natures.contains(nature);
849     }
850 
851   } // -- InternalXMLClassDescriptor
852 
853 
854 } // -- MarshalFramework