View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999-2004 (C) Intalio Inc. All Rights Reserved.
42   *
43   * This file was originally developed by Keith Visco during the course
44   * of employment at Intalio Inc.
45   * Portions of this file developed by Keith Visco after Jan 19 2005 are
46   * Copyright (C) 2005 Keith Visco. All Rights Reserverd.
47   *
48   * $Id$
49   */
50  package org.exolab.castor.builder.factory;
51  
52  import java.util.ArrayList;
53  import java.util.Enumeration;
54  import java.util.Iterator;
55  import java.util.LinkedList;
56  import java.util.List;
57  
58  import org.apache.commons.lang.StringUtils;
59  import org.castor.core.util.StringUtil;
60  import org.exolab.castor.builder.AnnotationBuilder;
61  import org.exolab.castor.builder.BuilderConfiguration;
62  import org.exolab.castor.builder.FactoryState;
63  import org.exolab.castor.builder.GroupNaming;
64  import org.exolab.castor.builder.SGStateInfo;
65  import org.exolab.castor.builder.SGTypes;
66  import org.exolab.castor.builder.SourceGenerator;
67  import org.exolab.castor.builder.SourceGeneratorConstants;
68  import org.exolab.castor.builder.TypeConversion;
69  import org.exolab.castor.builder.binding.ExtendedBinding;
70  import org.exolab.castor.builder.binding.XMLBindingComponent;
71  import org.exolab.castor.builder.info.ClassInfo;
72  import org.exolab.castor.builder.info.FieldInfo;
73  import org.exolab.castor.builder.info.GroupInfo;
74  import org.exolab.castor.builder.info.XMLInfo;
75  import org.exolab.castor.builder.info.nature.JDOClassInfoNature;
76  import org.exolab.castor.builder.info.nature.JDOFieldInfoNature;
77  import org.exolab.castor.builder.info.nature.SolrjFieldInfoNature;
78  import org.exolab.castor.builder.info.nature.XMLInfoNature;
79  import org.exolab.castor.builder.info.nature.relation.JDOOneToManyNature;
80  import org.exolab.castor.builder.info.nature.relation.JDOOneToOneNature;
81  import org.exolab.castor.builder.types.XSClass;
82  import org.exolab.castor.builder.types.XSString;
83  import org.exolab.castor.builder.types.XSType;
84  import org.exolab.castor.mapping.AccessMode;
85  import org.exolab.castor.xml.schema.Annotated;
86  import org.exolab.castor.xml.schema.Annotation;
87  import org.exolab.castor.xml.schema.AppInfo;
88  import org.exolab.castor.xml.schema.AppInfoJpaNature;
89  import org.exolab.castor.xml.schema.AppInfoSolrjNature;
90  import org.exolab.castor.xml.schema.AttributeDecl;
91  import org.exolab.castor.xml.schema.AttributeGroupDecl;
92  import org.exolab.castor.xml.schema.ComplexType;
93  import org.exolab.castor.xml.schema.ContentModelGroup;
94  import org.exolab.castor.xml.schema.ContentType;
95  import org.exolab.castor.xml.schema.Documentation;
96  import org.exolab.castor.xml.schema.ElementDecl;
97  import org.exolab.castor.xml.schema.Facet;
98  import org.exolab.castor.xml.schema.Group;
99  import org.exolab.castor.xml.schema.ModelGroup;
100 import org.exolab.castor.xml.schema.Order;
101 import org.exolab.castor.xml.schema.Particle;
102 import org.exolab.castor.xml.schema.Schema;
103 import org.exolab.castor.xml.schema.SimpleContent;
104 import org.exolab.castor.xml.schema.SimpleType;
105 import org.exolab.castor.xml.schema.SimpleTypesFactory;
106 import org.exolab.castor.xml.schema.Structure;
107 import org.exolab.castor.xml.schema.Wildcard;
108 import org.exolab.castor.xml.schema.XMLType;
109 import org.exolab.castor.xml.schema.annotations.jdo.Column;
110 import org.exolab.castor.xml.schema.annotations.jdo.OneToMany;
111 import org.exolab.castor.xml.schema.annotations.jdo.OneToOne;
112 import org.exolab.castor.xml.schema.annotations.jdo.PrimaryKey;
113 import org.exolab.castor.xml.schema.annotations.jdo.Table;
114 import org.exolab.castor.xml.schema.annotations.solrj.Field;
115 //import org.exolab.castor.xml.schema.annotations.solrj.Id;
116 import org.exolab.javasource.JAnnotation;
117 import org.exolab.javasource.JAnnotationType;
118 import org.exolab.javasource.JClass;
119 import org.exolab.javasource.JCollectionType;
120 import org.exolab.javasource.JConstructor;
121 import org.exolab.javasource.JDocComment;
122 import org.exolab.javasource.JDocDescriptor;
123 import org.exolab.javasource.JEnum;
124 import org.exolab.javasource.JField;
125 import org.exolab.javasource.JMethod;
126 import org.exolab.javasource.JParameter;
127 import org.exolab.javasource.JSourceCode;
128 import org.exolab.javasource.JType;
129 
130 /**
131  * Creates the Java Source classes for Schema components.
132  *
133  * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
134  * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
135  * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
136  */
137 public final class SourceFactory extends BaseFactory {
138     private static final String ENUM_ACCESS_INTERFACE =
139         "org.exolab.castor.types.EnumeratedTypeAccess";
140 
141     private static final short  BASE_TYPE_ENUMERATION   = 0;
142     private static final short  OBJECT_TYPE_ENUMERATION = 1;
143 
144     private static final String CLASS_METHOD_SUFFIX     = "Class";
145     private static final String CLASS_KEYWORD           = "class";
146     private static final String ITEM_NAME               = "Item";
147 
148     /**  The current Binding for which we are creating classes. */
149     private ExtendedBinding _binding = null;
150     /** The member factory. */
151     private MemberFactory _memberFactory = null;
152 
153     private short _enumerationType = OBJECT_TYPE_ENUMERATION;
154 
155     /**
156      * A flag indicating whether or not to generate XML marshaling framework
157      * specific methods.
158      */
159     private boolean _createMarshalMethods = true;
160 
161     /**
162      * A flag indicating whether or not to implement CastorTestable (used by the
163      * Castor Testing Framework).
164      */
165     private boolean _testable = false;
166     /** A flag indicating that SAX1 should be used when generating the source. */
167     private boolean _sax1 = false;
168     /** The TypeConversion instance to use for mapping SimpleTypes into XSTypes. */
169     private TypeConversion _typeConversion = null;
170     /** Enumeration factory used to create code for enumerations. */
171     private final EnumerationFactory _enumerationFactory;
172 
173     /**
174      * Creates a new SourceFactory with the given FieldInfoFactory.
175      *
176      * @param config the BuilderConfiguration instance (must not be null).
177      * @param infoFactory the FieldInfoFactory to use
178      * @param groupNaming Group naming scheme to be used.
179      * @param sourceGenerator the calling source generator.
180      */
181     public SourceFactory(final BuilderConfiguration config,
182             final FieldInfoFactory infoFactory,
183             final GroupNaming groupNaming,
184             final SourceGenerator sourceGenerator) {
185         super(config, infoFactory, groupNaming, sourceGenerator);
186 
187         // set the config into the info factory (CASTOR-1346)
188         infoFactory.setBoundProperties(config.boundPropertiesEnabled());
189 
190         this._memberFactory = new MemberFactory(config, infoFactory, getGroupNaming(), sourceGenerator);
191         this._typeConversion = new TypeConversion(getConfig());
192         this._enumerationFactory =
193             new EnumerationFactory(getConfig(), getGroupNaming(), sourceGenerator);
194     } //-- SourceFactory
195 
196    /**
197      * Sets whether or not to create the XML marshaling framework specific
198      * methods (marshal, unmarshal, validate) in the generated classes. By
199      * default, these methods are generated.
200      *
201      * @param createMarshalMethods
202      *            a boolean, when true indicates to generated the marshaling
203      *            framework methods
204      *
205      */
206     public void setCreateMarshalMethods(final boolean createMarshalMethods) {
207         _createMarshalMethods = createMarshalMethods;
208     } //-- setCreateMarshalMethpds
209 
210     /**
211      * Sets whether or not to create extra collection methods for accessing the
212      * actual collection.
213      *
214      * @param extraMethods
215      *            a boolean that when true indicates that extra collection
216      *            accessor methods should be created. False by default.
217      * @see org.exolab.castor.builder.SourceFactory#setReferenceMethodSuffix
218      */
219     public void setCreateExtraMethods(final boolean extraMethods) {
220         getInfoFactory().setCreateExtraMethods(extraMethods);
221     } //-- setCreateExtraMethods
222 
223     /**
224      * Sets the method suffix (ending) to use when creating the extra collection
225      * methods.
226      *
227      * @param suffix
228      *            the method suffix to use when creating the extra collection
229      *            methods. If null or emtpty the default value, as specified in
230      *            CollectionInfo will be used.
231      * @see org.exolab.castor.builder.SourceFactory#setCreateExtraMethods
232      */
233     public void setReferenceMethodSuffix(final String suffix) {
234         getInfoFactory().setReferenceMethodSuffix(suffix);
235     } //-- setReferenceMethodSuffix
236 
237     /**
238      * Sets whether or not to implement CastorTestable.
239      *
240      * @param testable
241      *            if true, indicates to implement CastorTestable
242      */
243     public void setTestable(final boolean testable) {
244         _testable = testable;
245     }
246 
247    /**
248      * Sets to true if SAX1 should be used in the marshall method.
249      *
250      * @param sax1
251      *            true if SAX1 should be used.
252      */
253     public void setSAX1(final boolean sax1) {
254         _sax1 = sax1;
255     }
256 
257     /**
258      * Set to true if enumerated type lookups should be performed in a case
259      * insensitive manner.
260      *
261      * @param caseInsensitive
262      *            when true
263      */
264     public void setCaseInsensitive(final boolean caseInsensitive) {
265         _enumerationFactory.setCaseInsensitive(caseInsensitive);
266     }
267 
268     //------------------/
269     //- Public Methods -/
270     //------------------/
271 
272     /**
273      * Creates a new ClassInfo for the given XMLBindingComponent.
274      *
275      * @param component the XMLBindingComponent that abstracts all XML Schema
276      *        definition for a XML Schema component.
277      * @param sgState The given state of the SourceGenerator.
278      * @return an array of JClasses reflecting the given XMLBindingComponent.
279      */
280     public JClass[] createSourceCode(final XMLBindingComponent component,
281                                      final SGStateInfo sgState) {
282         if (component == null) {
283             throw new IllegalStateException("XMLBindingComponent may not be null.");
284         }
285         if (sgState == null) {
286             throw new IllegalStateException("SGStateInfo may not be null.");
287         }
288 
289         //-- check for previous JClass bindings
290         JClass[] classes = sgState.getSourceCode(component.getAnnotated());
291         if (classes != null) {
292             return classes;
293         }
294 
295         _binding = component.getBinding();
296 
297         if (sgState.verbose()) {
298              String name = component.getXMLName();
299              if (name == null) {
300                  name = component.getJavaClassName();
301              }
302              String msg = "Creating classes for: " + name;
303              sgState.getDialog().notify(msg);
304         }
305 
306         //0-- set the packageName
307         String packageName = component.getJavaPackage();
308         if (packageName == null || packageName.length() == 0) {
309             packageName = sgState.getPackageName();
310         }
311 
312         //1-- get the name
313         //--if no package used then try to append the default package
314         //--used in the SourceGenerator
315         String className = component.getQualifiedName();
316         if (className.indexOf('.') == -1) {
317             //--be sure it is a valid className
318             className = getJavaNaming().toJavaClassName(className);
319             className = resolveClassName(className, packageName);
320         }
321 
322         //2-- check if we have to create an Item class
323         boolean createGroupItem = component.createGroupItem();
324         if (createGroupItem) {
325             className += ITEM_NAME;
326             classes = new JClass[2];
327         } else {
328             classes = new JClass[1];
329         }
330 
331         //3-- Create factoryState and chain it to sgState to prevent endless loop
332         FactoryState state =
333             new FactoryState(className, sgState, packageName, component);
334         state.setCreateGroupItem(createGroupItem);
335         if (sgState.getCurrentFactoryState() != null) {
336             state.setParent(sgState.getCurrentFactoryState());
337         }
338         sgState.setCurrentFactoryState(state);
339 
340         //--Prevent endless loop
341         if (state.processed(component.getAnnotated())) {
342             return new JClass[0];
343         }
344 
345         //-- Mark the enclosed annotated structure as processed in the
346         //-- current FactoryState for preventing endless loop.
347         state.markAsProcessed(component.getAnnotated());
348 
349         //////////////////////////////////////////////////////
350         //NOTE: check that the component is not referring to
351         //an imported schema to prevent class creation
352         //////////////////////////////////////////////////////
353 
354         //4-- intialization of the JClass
355         ClassInfo classInfo = state.getClassInfo();
356         JClass    jClass    = state.getJClass();
357         initialize(jClass);
358 
359         if (classInfo.hasNature(XMLInfoNature.class.getName())) {
360             final XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
361             
362             //-- name information
363             xmlNature.setNodeName(component.getXMLName());
364             
365             //-- namespace information
366             xmlNature.setNamespaceURI(component.getTargetNamespace());
367             
368             //5--processing the type
369             XMLType type = component.getXMLType();
370             boolean createForSingleGroup = false;
371             boolean creatingForAnElement =
372                 (component.getAnnotated().getStructureType() == Structure.ELEMENT);
373             
374             //-- created from element definition information
375             xmlNature.setElementDefinition(creatingForAnElement);
376             
377             // deal with substitution groups
378             if (creatingForAnElement) {
379                 ElementDecl elementDeclaration = (ElementDecl) component.getAnnotated();
380                 Enumeration<ElementDecl> possibleSubstitutes = elementDeclaration.getSubstitutionGroupMembers();
381                 if (possibleSubstitutes.hasMoreElements()) {
382                     List<String> substitutionGroupMembers = new ArrayList<String>();
383                     while (possibleSubstitutes.hasMoreElements()) {
384                         ElementDecl substitute = possibleSubstitutes.nextElement();
385                         substitutionGroupMembers.add(substitute.getName());
386                     }
387                     xmlNature.setSubstitutionGroups(substitutionGroupMembers);
388                 }
389             }
390 
391             if (type != null) {
392                 if (type.isComplexType()) {
393                     processComplexType(component, sgState, state);
394                 } else if (type.isSimpleType()) {
395                     SimpleType simpleType = (SimpleType) type;
396                     //-- handle our special case for enumerated types
397                     if (simpleType.hasFacet(Facet.ENUMERATION)) {
398                         processSimpleTypeEnumeration(component, sgState, classInfo, simpleType);
399                     } else {
400                         //////////////////////////////////////////////////////////
401                         //NOTE: generate sources if the flag for generating sources
402                         //from imported schemas is on
403                         //////////////////////////////////////////////////////////
404                         return new JClass[0];
405                     }
406                 } else if (type.isAnyType()) {
407                     //-- Do not create classes for AnyType
408                     xmlNature.setSchemaType(new XSClass(SGTypes.OBJECT));
409                     return new JClass[0];
410                 }
411             } else {
412                 //--no type we must be facing an XML schema group
413                 //--MODEL GROUP OR GROUP
414                 createForSingleGroup = processSchemaGroup(component, state, classInfo);
415             }
416 
417             //6--createGroupItem
418             if (createGroupItem) {
419                 //-- create Bound Properties code
420                 if (component.hasBoundProperties()) {
421                     createPropertyChangeMethods(jClass);
422                 }
423 
424                 sgState.bindReference(jClass, classInfo);
425 
426                 classes[1] = jClass;
427 
428                 //-- create main group class
429                 String fname = component.getJavaClassName() + ITEM_NAME;
430                 fname = getJavaNaming().toJavaMemberName(fname, false);
431 
432                 FieldInfo fInfo = null;
433                 if (createForSingleGroup) {
434                     //By default a nested group Item can occur only once
435                     fInfo = getInfoFactory().createFieldInfo(new XSClass(jClass), fname);
436                 } else {
437                     fInfo = getInfoFactory().createCollection(
438                             new XSClass(jClass), "_items", fname, getJavaNaming(), getConfig().useJava50());
439                 }
440                 fInfo.setContainer(true);
441                 String newClassName = className.substring(0, className.length() - 4);
442                 state = new FactoryState(newClassName, sgState, packageName, component);
443                 classInfo = state.getClassInfo();
444                 jClass    = state.getJClass();
445                 initialize(jClass);
446                 if (type != null && type.isComplexType()) {
447                     ComplexType complexType = (ComplexType) type;
448                     if (complexType.isTopLevel() ^ creatingForAnElement) {
449                         //process attributes and content type since it has not be performed before
450                         Annotated saved = component.getAnnotated();
451                         processAttributes(component.getBinding(), complexType, state);
452                         component.setView(saved);
453                         if (complexType.getContentType() == ContentType.mixed) {
454                             FieldInfo fieldInfo = _memberFactory.createFieldInfoForContent(
455                                     component, new XSString(), getConfig().useJava50());
456                             handleField(fieldInfo, state, component);
457                         } else if (complexType.getContentType().getType() == ContentType.SIMPLE) {
458                             SimpleContent simpleContent = (SimpleContent) complexType.getContentType();
459                             SimpleType temp = simpleContent.getSimpleType();
460                             XSType xsType = _typeConversion.convertType(
461                                     temp, packageName, getConfig().useJava50());
462                             FieldInfo fieldInfo = _memberFactory.createFieldInfoForContent(
463                                     component, xsType, getConfig().useJava50());
464                             handleField(fieldInfo, state, component);
465                             temp = null;
466                         } else {
467                             // handle multi-valued choice group
468                             xmlNature.setSchemaType(new XSClass(jClass));
469                         }
470                     }
471                 }
472 
473                 classInfo.addFieldInfo(fInfo);
474                 fInfo.getMemberAndAccessorFactory().createJavaField(fInfo, jClass);
475                 fInfo.getMemberAndAccessorFactory().createAccessMethods(
476                         fInfo, jClass, getConfig().useJava50(), getConfig().getAnnotationBuilders());
477                 fInfo.getMemberAndAccessorFactory().generateInitializerCode(
478                         fInfo, jClass.getConstructor(0).getSourceCode());
479 
480                 //-- name information
481                 XMLInfoNature xmlInfoNature = new XMLInfoNature(classInfo);
482                 xmlInfoNature.setNodeName(component.getXMLName());
483 
484                 //-- mark as a container
485                 xmlInfoNature.setContainer(true);
486                 
487                 // -- if we have a superclass, make sure that the actual type extends it, not the
488                 // xxxItem holder class.
489                 String actSuperClass = classes[1].getSuperClassQualifiedName();
490                 jClass.setSuperClass(actSuperClass);
491                 classes[1].setSuperClass(null);
492             }
493 
494         }
495         
496         classes[0] = jClass;
497 
498         //7--set the class information given the component information
499         //--base class
500         String baseClass = component.getExtends();
501         if (baseClass != null && baseClass.length() > 0) {
502             //-- at this point if a base class has been set
503             //-- it means that it is a class generated for an element
504             //-- that extends a class generated for a complexType. Thus
505             //-- no change is possible
506             if (jClass.getSuperClassQualifiedName() == null) {
507                 jClass.setSuperClass(baseClass);
508             }
509         }
510 
511         //--interface implemented
512         String[] implemented = component.getImplements();
513         if (implemented != null) {
514             for (int i = 0; i < implemented.length; i++) {
515                 String interfaceName = implemented[i];
516                 if ((interfaceName != null) && (interfaceName.length() > 0)) {
517                     jClass.addInterface(interfaceName);
518                 }
519             }
520         }
521 
522         //--final
523         jClass.getModifiers().setFinal(component.isFinal());
524 
525         //--abstract
526         if (component.isAbstract()) {
527             jClass.getModifiers().setAbstract(true);
528             classInfo.setAbstract(true);
529         }
530         
531         processAppInfo(component.getAnnotated(), classInfo);
532         extractAnnotations(component.getAnnotated(), jClass);
533 
534         createContructorForDefaultValueForSimpleContent(component.getAnnotated(), classInfo, sgState);
535         makeMethods(component, sgState, state, jClass, baseClass);
536         
537         if (classInfo.hasNature(JDOClassInfoNature.class.getName())) {
538             JDOClassInfoNature jdoNature = new JDOClassInfoNature(classInfo);
539             if (jdoNature.getDetachable()) {
540                 createJdoTimestampImplementations(jClass);
541             }
542         }
543 
544         sgState.bindReference(jClass, classInfo);
545         sgState.bindReference(component.getAnnotated(), classInfo);
546 
547         //-- Save source code bindings to prevent duplicate code generation
548         sgState.bindSourceCode(component.getAnnotated(), classes);
549 
550         // custom annotations
551         AnnotationBuilder[] annotationBuilders = getConfig().getAnnotationBuilders();
552         for (int i = 0; i < annotationBuilders.length; i++) {
553             AnnotationBuilder annotationBuilder = annotationBuilders[i];
554             annotationBuilder.addClassAnnotations(classInfo, jClass);
555         }
556 
557         return classes;
558     }
559 
560     /**
561      * This method adds a contructor with a string parameter to set the default
562      * value of a simple content. If the provided class is not a Simple Content
563      * class, nothing is done.
564      *
565      * @param annotated type information for the class to potentially create a
566      *        constructor for
567      * @param classInfo the ClassInfo for the class to potentially create a
568      *        constructor for
569      */
570     private void createContructorForDefaultValueForSimpleContent(final Annotated annotated,
571                                                                  final ClassInfo classInfo,
572                                                                  final SGStateInfo sgStateInfo) {
573         FieldInfo textFieldInfo =  classInfo.getTextField();
574 
575         boolean generate = false;
576         boolean inherited = false;
577         
578         // check if there is some field inherited from a type
579         if (annotated instanceof ElementDecl) {
580             XMLType type = ((ElementDecl) annotated).getType();
581             ClassInfo typeInfo = sgStateInfo.resolve(type);
582             if (typeInfo != null && typeInfo.getTextField() != null) {
583                 textFieldInfo = typeInfo.getTextField();
584                 inherited = true;
585             }
586             generate = (type.isComplexType() && ((ComplexType) type).isSimpleContent());
587         }
588         
589         // check if we are a complexType ourself
590         else if (annotated instanceof ComplexType && ((ComplexType) annotated).isSimpleContent()) {
591             generate = true;
592         }
593         
594 
595         // discard primitiv types and collections
596         if (textFieldInfo != null) {
597             XSType textFieldType = new XMLInfoNature(textFieldInfo).getSchemaType();
598             if (textFieldType != null && textFieldType.getJType().isArray()) {
599                 generate = false;
600             }
601         }
602 
603         if (!generate) {
604             return;
605         }
606 
607         XMLInfoNature xmlNature = new XMLInfoNature(textFieldInfo);
608         
609         // create constructor
610         JClass jClass = classInfo.getJClass();
611         JParameter parameter = new JParameter(new JClass("java.lang.String"), "defaultValue");
612         JConstructor constructor = jClass.createConstructor(new JParameter[] {parameter});
613         JSourceCode sourceCode = new JSourceCode();
614 
615         if (inherited) {
616             sourceCode.add("super(defaultValue);");
617         } else {
618             sourceCode.add("try {");
619             String defaultValue = 
620                 xmlNature.getSchemaType().createDefaultValueWithString("defaultValue");
621             sourceCode.addIndented("setContent(" + defaultValue + ");");
622             sourceCode.add(" } catch(Exception e) {");
623             sourceCode.addIndented("throw new RuntimeException(\"Unable to cast default value for simple content!\");");
624             sourceCode.add(" } ");
625         }
626 
627         constructor.setSourceCode(sourceCode);
628         jClass.addConstructor(constructor);
629     }
630 
631     /**
632      * Extract 'documentation' annotations from the {@link Annotated} instance given.
633      * @param annotated {@link Annotated} instance to extract annotations from.
634      * @param jClass {@link JClass} instance to inject annotations into.
635      */
636     private void extractAnnotations(final Annotated annotated, final JClass jClass) {
637         //-- process annotation
638         String comment  = extractCommentsFromAnnotations(annotated);
639         if (comment != null) {
640             jClass.getJDocComment().setComment(comment);
641             
642             if (getConfig().generateExtraDocumentationMethods()) {
643                 generateExtraDocumentationMethods(annotated, jClass);
644             }
645         }
646     }
647 
648     /**
649      * Creates the #getXmlSchemaDocumentation methods for the given JClass.
650      * 
651      * @param annotated
652      *            The {@link Annotation} instance to extract the XML schema
653      *            documentation instances from.
654      * @param parent
655      *            the JClass to create the #getXmlSchemaDocumentation() methods
656      *            for
657      */
658     private void generateExtraDocumentationMethods(final Annotated annotated,
659             final JClass jClass) {
660         JField documentationsField = 
661             new JField(new JClass("java.util.Map"), "_xmlSchemaDocumentations");
662         documentationsField.setComment("The content of the <xsd:documentation> elements");
663         documentationsField.setInitString("new java.util.HashMap()");
664         jClass.addMember(documentationsField);
665 
666         Enumeration<Annotation> annotations = annotated.getAnnotations();
667         while (annotations.hasMoreElements()) {
668             Annotation annotation = annotations.nextElement();
669             Enumeration<Documentation> documentations = annotation.getDocumentation();
670             while (documentations.hasMoreElements()) {
671                 Documentation documentation = documentations.nextElement();
672                 JConstructor defaultConstructor = jClass.getConstructor(0);
673                 String documentationContent = normalize(documentation.getContent());
674                 documentationContent = 
675                     StringUtil.replaceAll(documentationContent, "\n", "\"\n+ \" ");
676                 defaultConstructor.getSourceCode().add("_xmlSchemaDocumentations.put(\"" 
677                         +  documentation.getSource() + "\", \"" 
678                         + documentationContent + "\");");
679             }
680         }
681 
682         JMethod aMethod = new JMethod("getXmlSchemaDocumentations", 
683                 new JClass("java.util.Map"), 
684         " A collection of documentation elements.");
685         JSourceCode sourceCode = aMethod.getSourceCode();
686         sourceCode.add("return _xmlSchemaDocumentations;");
687         jClass.addMethod(aMethod);
688 
689         JMethod anotherMethod = new JMethod("getXmlSchemaDocumentation", 
690                 new JClass("java.lang.String"), 
691                     " A specific XML schema documentation element.");
692         JParameter parameter = new JParameter(new JClass("java.lang.String"), "source");
693         anotherMethod.addParameter(parameter);
694         sourceCode = anotherMethod.getSourceCode();
695         sourceCode.add("return (java.lang.String) _xmlSchemaDocumentations.get(source);");
696         jClass.addMethod(anotherMethod);
697     }
698 
699     /**
700      * Generate methods for our class.
701      *
702      * @param component
703      * @param sgState
704      * @param state
705      * @param jClass
706      * @param baseClass
707      */
708     private void makeMethods(
709             final XMLBindingComponent component,
710             final SGStateInfo sgState,
711             final FactoryState state,
712             final JClass jClass,
713             final String baseClass) {
714         //NOTE: be careful with the derivation stuff when generating bounds properties
715 
716         if (_createMarshalMethods) {
717             //-- #validate()
718             createValidateMethods(jClass);
719             //--don't generate marshal/unmarshal methods
720             //--for abstract classes
721             if (!component.isAbstract()) {
722                 //-- #marshal()
723                 createMarshalMethods(jClass);
724                 //-- #unmarshal()
725                 createUnmarshalMethods(jClass, sgState);
726             }
727         }
728 
729         //create equals() method?
730         if (component.hasEquals()) {
731             createEqualsMethod(jClass);
732             createHashCodeMethod(jClass);
733         }
734 
735         //implements CastorTestable?
736         if (_testable) {
737             createTestableMethods(jClass, state);
738         }
739 
740         //-- This boolean is set to create bound properties
741         //-- even if the user has set the SUPER CLASS property
742         String superclassQualifiedName = jClass.getSuperClassQualifiedName();
743         if (superclassQualifiedName == null || superclassQualifiedName.equals(baseClass)) {
744             //-- create Bound Properties code
745             if (component.hasBoundProperties()) {
746                 createPropertyChangeMethods(jClass);
747             }
748         }
749     }
750 
751     private boolean processSchemaGroup(final XMLBindingComponent component,
752                                        final FactoryState state, final ClassInfo classInfo) {
753         try {
754             Group group = (Group) component.getAnnotated();
755             processContentModel(group, state);
756             component.setView(group);
757 
758             //-- Check Group Type
759             Order order = group.getOrder();
760             GroupInfo groupInfo = new XMLInfoNature(classInfo).getGroupInfo();
761             if (order == Order.choice) {
762                 groupInfo.setAsChoice();
763             } else if (order == Order.sequence) {
764                 groupInfo.setAsSequence();
765             } else {
766                 groupInfo.setAsAll();
767             }
768 
769             return group.getMaxOccurs() == 1;
770         } catch (ClassCastException ce) {
771             //--Should not happen
772             throw new IllegalArgumentException("Illegal binding component: " + ce.getMessage());
773         }
774     }
775 
776     private void processSimpleTypeEnumeration(final XMLBindingComponent component,
777                                               final SGStateInfo sgState, final ClassInfo classInfo,
778                                               final SimpleType simpleType) {
779         //-- Don't create source code for simple types that
780         //-- don't belong in the elements target namespace
781         String tns = simpleType.getSchema().getTargetNamespace();
782         boolean create = false;
783         if (tns == null) {
784             create = (component.getTargetNamespace() == null);
785         } else {
786             create = tns.equals(component.getTargetNamespace());
787         }
788 
789         if (create) {
790             ClassInfo tmpInfo = sgState.resolve(simpleType);
791             JClass tmpClass = null;
792             if (tmpInfo != null) {
793                 tmpClass = tmpInfo.getJClass();
794             } else {
795                 tmpClass = createSourceCode(component.getBinding(), simpleType, sgState);
796             }
797             XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
798             xmlNature.setSchemaType(new XSClass(tmpClass));
799         }
800     }
801 
802     private void processComplexType(final XMLBindingComponent component, final SGStateInfo sgState,
803                                     final FactoryState state) {
804         XMLType   type      = component.getXMLType();
805         ClassInfo classInfo = state.getClassInfo();
806         JClass    jClass    = state.getJClass();
807         boolean creatingForAnElement =
808             (component.getAnnotated().getStructureType() == Structure.ELEMENT);
809 
810         ComplexType complexType = (ComplexType) type;
811         if (complexType.isTopLevel() && creatingForAnElement) {
812              //--move the view and keep the structure
813              Annotated saved = component.getAnnotated();
814              String previousPackage = component.getJavaPackage();
815              XMLBindingComponent baseComponent = new XMLBindingComponent(
816                      getConfig(), getGroupNaming());
817              baseComponent.setBinding(component.getBinding());
818              baseComponent.setView(complexType);
819              //-- call createSourceCode to pre-process the complexType
820              createSourceCode(baseComponent, sgState);
821              String baseClassName = null;
822              String basePackage = baseComponent.getJavaPackage();
823              //--if the base class is not in the same package
824              //--of the current class then we have to qualify the base
825              //--class
826              if (basePackage != null && !basePackage.equals(previousPackage)) {
827                  baseClassName = baseComponent.getQualifiedName();
828                  if (baseClassName.indexOf('.') == -1) {
829                      //--be sure it is a valid className
830                      baseClassName = getJavaNaming().toJavaClassName(baseClassName);
831                  }
832              } else {
833                  baseClassName = baseComponent.getJavaClassName();
834              }
835              jClass.setSuperClass(baseClassName);
836              basePackage = null;
837              baseClassName = null;
838              component.setView(saved);
839              saved = null;
840         } else if (complexType.isTopLevel() || creatingForAnElement) {
841             //generate class if the complexType is anonymous and we create classes
842             //for an element OR if the complexType is top-level and we create
843             //classes for it.
844 
845             //-- check Group type
846             if (complexType.getParticleCount() == 1) {
847                 Particle particle = complexType.getParticle(0);
848                 if (particle.getStructureType() == Structure.GROUP) {
849                     Group group = (Group) particle;
850                     if (group.getOrder() == Order.choice) {
851                         new XMLInfoNature(classInfo).getGroupInfo().setAsChoice();
852                     }
853                 }
854             }
855             Annotated saved = component.getAnnotated();
856             processComplexType(complexType, state);
857             component.setView(saved);
858             saved = null;
859         }
860     }
861 
862     /**
863      * Creates the Java source code to support the given Simpletype.
864      *
865      * @param binding Current XML binding
866      * @param simpleType the Simpletype to create the Java source for
867      * @param sgState the current SGStateInfo (cannot be null).
868      * @return the JClass representation of the given Simpletype
869      */
870     public JClass createSourceCode(final ExtendedBinding binding,
871             final SimpleType simpleType, final SGStateInfo sgState) {
872         if (SimpleTypesFactory.isBuiltInType(simpleType.getTypeCode())) {
873             String err = "You cannot construct a ClassInfo for a built-in SimpleType.";
874             throw new IllegalArgumentException(err);
875         }
876         if (sgState == null) {
877             throw new IllegalArgumentException("SGStateInfo cannot be null.");
878         }
879 
880         //-- Unions are currently processed as the built-in
881         //-- basetype for the member types of the Union, so
882         //-- do nothing for now...however we can warn
883         //-- user that no validation will be peformed on the
884         //-- union
885         if (simpleType.getStructureType() == Structure.UNION) {
886             if (!sgState.getSuppressNonFatalWarnings()) {
887                 String message = "warning: support for unions is incomplete.";
888                 sgState.getDialog().notify(message);
889             }
890             return null;
891         }
892 
893         ClassInfo cInfo = sgState.resolve(simpleType);
894         if (cInfo != null) {
895             return cInfo.getJClass();
896         }
897 
898         boolean enumeration = false;
899 
900         //-- class name information
901         String typeName = simpleType.getName();
902         if (typeName == null) {
903             Structure struct = simpleType.getParent();
904             FactoryState fstate = null;
905             switch (struct.getStructureType()) {
906                 case Structure.ATTRIBUTE:
907                     typeName = ((AttributeDecl) struct).getName();
908                     fstate = sgState.getCurrentFactoryState();
909                     break;
910                 case Structure.ELEMENT:
911                     typeName = ((ElementDecl) struct).getName();
912                     break;
913                 default:
914                     // Nothing to do
915                     break;
916             }
917             //-- In case of naming collision we append current class name
918             if (fstate != null) {
919                 typeName = getJavaNaming().toJavaClassName(typeName);
920                 Structure attrDeclParent = ((AttributeDecl) struct).getParent();
921                 if (attrDeclParent != null
922                         && attrDeclParent.getStructureType() == Structure.ATTRIBUTE_GROUP) {
923                     typeName = getJavaNaming().toJavaClassName(
924                             ((AttributeGroupDecl) attrDeclParent).getName() + typeName);
925                 } else {
926                     typeName = fstate.getJClass().getLocalName() + typeName;
927                 }
928             }
929             //-- otherwise (???) just append "Type"
930             typeName += "Type";
931         }
932 
933         String className   = getJavaNaming().toJavaClassName(typeName);
934 
935         //--XMLBindingComponent is only used to retrieve the java package
936         //-- we need to optimize it by enabling the binding of simpleTypes.
937         XMLBindingComponent comp =
938             new XMLBindingComponent(getConfig(), getGroupNaming());
939         if (binding != null) {
940             comp.setBinding(binding);
941         }
942         
943         // set component view for anonymous simple types to parent 
944         if (simpleType.getName() == null) {
945             Annotated annotated = (Annotated) simpleType.getParent();
946             comp.setView(annotated);
947         } else {
948             comp.setView(simpleType);
949         }
950 
951         String packageName = comp.getJavaPackage();
952         if ((packageName == null) || (packageName.length() == 0)) {
953             packageName = sgState.getPackageName();
954         }
955 
956         // reset component view for anonymous simple types
957         if (simpleType.getName() == null) {
958             comp.setView(simpleType);
959         }
960         
961         if (simpleType.hasFacet(Facet.ENUMERATION)) {
962             enumeration = true;
963             // Fix packageName
964             // TODO  this is a hack I know, we should change this
965             if ((packageName != null) && (packageName.length() > 0)) {
966                 packageName = packageName + "." + SourceGeneratorConstants.TYPES_PACKAGE;
967             } else {
968                 packageName = SourceGeneratorConstants.TYPES_PACKAGE;
969             }
970         }
971 
972         String boundClassName = comp.getJavaClassName();
973         if ((boundClassName != null) && (boundClassName.length() > 0)) {
974             className = boundClassName;
975             typeName = boundClassName;
976         }
977 
978         className = resolveClassName(className, packageName);
979 
980         FactoryState state = new FactoryState(className, sgState, packageName, comp,
981                 (enumeration && getConfig().useJava5Enums()));
982 
983         state.setParent(sgState.getCurrentFactoryState());
984 
985         ClassInfo classInfo = state.getClassInfo();
986         JClass    jClass    = state.getJClass();
987 
988         initialize(jClass);
989 
990         //-- XML information
991         Schema  schema = simpleType.getSchema();
992         XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
993         xmlNature.setNamespaceURI(schema.getTargetNamespace());
994         xmlNature.setNodeName(typeName);
995 
996         extractAnnotations(simpleType, jClass);
997 
998         XSClass xsClass = new XSClass(jClass, typeName);
999 
1000         xmlNature.setSchemaType(xsClass);
1001 
1002         //-- handle enumerated types
1003         if (enumeration) {
1004             xsClass.setAsEnumerated(true);
1005             processEnumeration(binding, simpleType, state);
1006         }
1007 
1008         //-- create Bound Properties code
1009         if (state.hasBoundProperties() && !enumeration) {
1010             createPropertyChangeMethods(jClass);
1011         }
1012         
1013         if (classInfo.hasNature(JDOClassInfoNature.class.getName())) {
1014             JDOClassInfoNature jdoNature = new JDOClassInfoNature(classInfo);
1015             if (jdoNature.getDetachable()) {
1016                 createJdoTimestampImplementations(jClass);
1017             }
1018         }
1019 
1020         sgState.bindReference(jClass, classInfo);
1021         sgState.bindReference(simpleType, classInfo);
1022 
1023         return jClass;
1024     }
1025 
1026     private void createJdoTimestampImplementations(final JClass jClass) {
1027 
1028         jClass.addInterface("org.exolab.castor.jdo.TimeStampable");
1029         
1030         JField jdoTimestamp = new JField(JType.LONG, "_jdoTimeStamp");
1031         jClass.addField(jdoTimestamp);
1032         
1033         JMethod getTSMethod = new JMethod("jdoGetTimeStamp", JType.LONG,
1034                  "returns the current time stamp");
1035         JSourceCode getSourceCode = getTSMethod.getSourceCode();
1036         getSourceCode.addIndented("return _jdoTimeStamp;");
1037         jClass.addMethod(getTSMethod);
1038 
1039         JMethod setTSMethod = new JMethod("jdoSetTimeStamp");
1040         JParameter parameter = new JParameter(JType.LONG, "jdoTimeStamp");
1041         setTSMethod.addParameter(parameter);
1042         JSourceCode setSourceCode = setTSMethod.getSourceCode();
1043         setSourceCode.addIndented("this._jdoTimeStamp = jdoTimeStamp;");
1044         jClass.addMethod(setTSMethod);
1045      }
1046 
1047 
1048     //-------------------/
1049     //- Private Methods -/
1050     //-------------------/
1051 
1052     /**
1053      * Initializes the given JClass.
1054      * @param jClass the JClass to initialize
1055      */
1056     private void initialize(final JClass jClass) {
1057         jClass.addInterface("java.io.Serializable");
1058 
1059         if (getConfig().useJava50()) {
1060             JAnnotation serial = new JAnnotation(new JAnnotationType("SuppressWarnings"));
1061             serial.setValue(new String[] {"\"serial\""});
1062             jClass.addAnnotation(serial);
1063         }
1064 
1065         //-- add default constructor
1066         JConstructor con = jClass.createConstructor();
1067         jClass.addConstructor(con);
1068         con.getSourceCode().add("super();");
1069     } //-- initialize
1070 
1071     /**
1072      * Creates the #marshal methods for the given JClass.
1073      * @param parent the JClass to create the #marshal methods for
1074      */
1075     private void createPropertyChangeMethods(final JClass parent) {
1076         //-- add vector to hold listeners
1077         String vName = "propertyChangeSupport";
1078         JField field = new JField(SGTypes.PROPERTY_CHANGE_SUPPORT, vName);
1079         field.getModifiers().makePrivate();
1080         parent.addField(field);
1081 
1082         //---------------------------------/
1083         //- notifyPropertyChangeListeners -/
1084         //---------------------------------/
1085 
1086         JMethod jMethod = new JMethod("notifyPropertyChangeListeners");
1087         jMethod.getModifiers().makeProtected();
1088 
1089         JDocComment jdc = jMethod.getJDocComment();
1090         JDocDescriptor jdDesc = null;
1091         String desc = null;
1092 
1093         desc = "Notifies all registered PropertyChangeListeners "
1094              + "when a bound property's value changes.";
1095         jdc.appendComment(desc);
1096 
1097         jMethod.addParameter(new JParameter(SGTypes.STRING, "fieldName"));
1098         jdDesc = jdc.getParamDescriptor("fieldName");
1099         jdDesc.setDescription("the name of the property that has changed.");
1100 
1101         jMethod.addParameter(new JParameter(SGTypes.OBJECT, "oldValue"));
1102         jdDesc = jdc.getParamDescriptor("oldValue");
1103         jdDesc.setDescription("the old value of the property.");
1104 
1105         jMethod.addParameter(new JParameter(SGTypes.OBJECT, "newValue"));
1106         jdDesc = jdc.getParamDescriptor("newValue");
1107         jdDesc.setDescription("the new value of the property.");
1108 
1109         parent.addMethod(jMethod);
1110         JSourceCode jsc = jMethod.getSourceCode();
1111         //--fix for bug 1026
1112         jsc.add("if (");
1113         jsc.append(vName);
1114         jsc.append(" == null) return;");
1115 
1116         jsc.add(vName);
1117         jsc.append(".firePropertyChange(fieldName,oldValue,newValue);");
1118 
1119         //-----------------------------/
1120         //- addPropertyChangeListener -/
1121         //-----------------------------/
1122 
1123         JType jType = new JClass("java.beans.PropertyChangeListener");
1124         jMethod = new JMethod("addPropertyChangeListener");
1125 
1126         desc = "Registers a PropertyChangeListener with this class.";
1127         jdc = jMethod.getJDocComment();
1128         jdc.appendComment(desc);
1129 
1130         jMethod.addParameter(new JParameter(jType, "pcl"));
1131         desc = "The PropertyChangeListener to register.";
1132         jdDesc = jdc.getParamDescriptor("pcl");
1133         jdDesc.setDescription(desc);
1134 
1135         parent.addMethod(jMethod);
1136 
1137         jsc = jMethod.getSourceCode();
1138 
1139         jsc.add("if (");
1140         jsc.append(vName);
1141         jsc.append(" == null) {");
1142         jsc.addIndented(vName + " = new java.beans.PropertyChangeSupport(this);");
1143         jsc.add("}");
1144         jsc.add(vName);
1145         jsc.append(".addPropertyChangeListener(pcl);");
1146 
1147         //--------------------------------/
1148         //- removePropertyChangeListener -/
1149         //--------------------------------/
1150 
1151         jMethod = new JMethod("removePropertyChangeListener", JType.BOOLEAN,
1152                               "always returns true if pcl != null");
1153 
1154         desc = "Removes the given PropertyChangeListener "
1155              + "from this classes list of ProperyChangeListeners.";
1156         jdc = jMethod.getJDocComment();
1157         jdc.appendComment(desc);
1158 
1159         jMethod.addParameter(new JParameter(jType, "pcl"));
1160         desc = "The PropertyChangeListener to remove.";
1161         jdDesc = jdc.getParamDescriptor("pcl");
1162         jdDesc.setDescription(desc);
1163 
1164         parent.addMethod(jMethod);
1165 
1166         jsc = jMethod.getSourceCode();
1167         jsc.add("if (");
1168         jsc.append(vName);
1169         jsc.append(" == null) return false;");
1170 
1171         jsc.add(vName);
1172         jsc.append(".removePropertyChangeListener(pcl);");
1173         jsc.add("return true;");
1174     } //-- createPropertyChangeMethods
1175 
1176     /**
1177      * Creates the #marshal methods for the given JClass.
1178      * @param parent the JClass to create the #marshal methods for
1179      */
1180     private void createMarshalMethods(final JClass parent) {
1181         createMarshalMethods(parent, false);
1182     } //-- createMarshalMethods
1183 
1184     /**
1185      * Creates the #marshal methods for the given JClass.
1186      * @param parent the JClass to create the #marshal methods for
1187      * @param isAbstract true if the generated Class should be marked abstract
1188      */
1189     private void createMarshalMethods(final JClass parent, final boolean isAbstract) {
1190         //-- create main marshal method
1191         JMethod jMethod = new JMethod("marshal");
1192         jMethod.addException(SGTypes.MARSHAL_EXCEPTION,
1193                 "if object is null or if any SAXException is thrown during marshaling");
1194         jMethod.addException(SGTypes.VALIDATION_EXCEPTION,
1195                 "if this object is an invalid instance according to the schema");
1196         jMethod.addParameter(new JParameter(SGTypes.WRITER, "out"));
1197 
1198         //if (_config.useJava50()) {
1199         // jMethod.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
1200         //}
1201 
1202         parent.addMethod(jMethod);
1203 
1204         if (isAbstract) {
1205             jMethod.getModifiers().setAbstract(true);
1206         } else {
1207             JSourceCode jsc = jMethod.getSourceCode();
1208             jsc.add("org.exolab.castor.xml.Marshaller.marshal(this, out);");
1209         }
1210 
1211         //-- create helper marshal method
1212         //-- start helper marshal method, this method will
1213         //-- be built up as we process the given ElementDecl
1214         jMethod = new JMethod("marshal");
1215         JClass jc = null;
1216         if (_sax1) {
1217             jc = new JClass("org.xml.sax.DocumentHandler");
1218         } else {
1219             jc = new JClass("org.xml.sax.ContentHandler");
1220             jMethod.addException(SGTypes.IO_EXCEPTION,
1221                     "if an IOException occurs during marshaling");
1222         }
1223         jMethod.addException(SGTypes.MARSHAL_EXCEPTION,
1224                 "if object is null or if any SAXException is thrown during marshaling");
1225         jMethod.addException(SGTypes.VALIDATION_EXCEPTION,
1226                 "if this object is an invalid instance according to the schema");
1227         jMethod.addParameter(new JParameter(jc, "handler"));
1228         parent.addMethod(jMethod);
1229 
1230         if (isAbstract) {
1231             jMethod.getModifiers().setAbstract(true);
1232         } else {
1233             JSourceCode jsc = jMethod.getSourceCode();
1234             jsc.add("org.exolab.castor.xml.Marshaller.marshal(this, handler);");
1235         }
1236     } //-- createMarshalMethods
1237 
1238     private void createUnmarshalMethods(final JClass parent, final SGStateInfo sgState) {
1239         //-- mangle method name to avoid compiler errors when this class is extended
1240         String methodName = "unmarshal";
1241         if (sgState.getSourceGenerator().mappingSchemaType2Java()) {
1242             methodName += parent.getLocalName();
1243         }
1244 
1245         //-- create main unmarshal method
1246 
1247         //-- search for proper base class
1248         // TODO[WG]: java 5.0 allows different types for unmarshal method in extension hierarchy
1249         JClass returnType;
1250         if (!getConfig().useJava50()) {
1251             returnType = findBaseClass(parent, sgState);
1252         } else {
1253             returnType = parent;
1254         }
1255 
1256         JMethod jMethod = new JMethod(methodName, returnType,
1257                                       "the unmarshaled " + returnType);
1258         jMethod.getModifiers().setStatic(true);
1259         jMethod.addException(SGTypes.MARSHAL_EXCEPTION,
1260                 "if object is null or if any SAXException is thrown during marshaling");
1261         jMethod.addException(SGTypes.VALIDATION_EXCEPTION,
1262                 "if this object is an invalid instance according to the schema");
1263         jMethod.addParameter(new JParameter(SGTypes.READER, "reader"));
1264         parent.addMethod(jMethod);
1265 
1266         JSourceCode jsc = jMethod.getSourceCode();
1267         jsc.add("return (");
1268         jsc.append(returnType.getName());
1269         jsc.append(") org.exolab.castor.xml.Unmarshaller.unmarshal(");
1270         jsc.append(parent.getName());
1271         jsc.append(".class, reader);");
1272     } //-- createUnmarshalMethods
1273 
1274     /**
1275      * Returns the base class (as found in the schema) of the provided class.
1276      * Climbs the inheritence tree of the provided class to find and return the
1277      * base class of the provided class.
1278      *
1279      * @param jClass class to find the base class of
1280      * @param sgState current state of source generation
1281      * @return the base class of the provided class.
1282      */
1283     private JClass findBaseClass(final JClass jClass, final SGStateInfo sgState) {
1284         JClass returnType = jClass;
1285 
1286         List<JClass> classes = new LinkedList<JClass>();
1287         classes.add(returnType);
1288 
1289         while (returnType.getSuperClassQualifiedName() != null) {
1290             String superClassName = returnType.getSuperClassQualifiedName();
1291             JClass superClass = sgState.getSourceCode(superClassName);
1292             if (superClass == null) {
1293                 superClass = sgState.getImportedSourceCode(superClassName);
1294             }
1295 
1296             // A binding can cause us to have to look for the superclass class in
1297             // the package of the current class
1298             if (superClass == null && superClassName.indexOf('.') < 0) {
1299                 String pkgName = returnType.getPackageName();
1300                 if (pkgName != null && pkgName.length() > 0) {
1301                     superClassName = pkgName + "." + superClassName;
1302                     superClass = sgState.getSourceCode(superClassName);
1303                 }
1304             }
1305 
1306             // If returnClass has no superclass then it is the base class
1307             if (superClass == null) {
1308                 break;
1309             }
1310 
1311             // Prevent inheritance loops from causing infinite loops
1312             if (classes.contains(superClass)) {
1313                 StringBuilder buffer = new StringBuilder(64);
1314                 buffer.append("Loop found in class hierarchy: ");
1315                 for (Iterator<JClass> i = classes.iterator(); i.hasNext(); ) {
1316                     JClass element = i.next();
1317                     // If JClass told us the source of the class (ComplexType, Element, ...
1318                     // then we could report that to and make name conflicts more obvious.
1319                     buffer.append(element.getName());
1320                     buffer.append(" -> ");
1321                 }
1322                 buffer.append(superClass.getName());
1323                 sgState.getDialog().notify(buffer.toString());
1324                 // FIXME We should probably throw an exception here
1325                 break;
1326             }
1327 
1328             classes.add(superClass);
1329             returnType = superClass;
1330         }
1331 
1332         classes.clear();
1333         return returnType;
1334     }
1335 
1336     /**
1337      * Create an "hashCode" method on the given JClass.
1338      *
1339      * @param jclass the JClass in wich we create the hashCode method.
1340      */
1341     public void createHashCodeMethod(final JClass jclass) {
1342         if (jclass == null) {
1343             throw new IllegalArgumentException("JClass must not be null");
1344         }
1345 
1346         // The argument is not null
1347         JField[] fields = jclass.getFields();
1348 
1349         // Creates the method signature
1350         JMethod jMethod = new JMethod("hashCode", JType.INT, "a hash code value for the object.");
1351         jMethod.setComment("Overrides the java.lang.Object.hashCode method.\n"
1352                            + "<p>\n"
1353                            + "The following steps came from "
1354                            + "<b>Effective Java Programming Language Guide</b> "
1355                            + "by Joshua Bloch, Chapter 3");
1356 
1357         // The hashCode method has no arguments
1358         jclass.addMethod(jMethod);
1359 
1360         JSourceCode jsc = jMethod.getSourceCode();
1361         if (jclass.getSuperClassQualifiedName() == null) {
1362             jsc.add("int resultHc = 17;");
1363         } else {
1364             jsc.add("int resultHc = super.hashCode();");
1365         }
1366         jsc.add("");
1367         jsc.add("long tmp;");
1368 
1369         for (int i = 0; i < fields.length; i++) {
1370             JField temp = fields[i];
1371             // If the field is an object the hashCode method is called recursively
1372 
1373             JType type = temp.getType();
1374             String name = temp.getName();
1375             if (type.isPrimitive()) {
1376                 if (type == JType.BOOLEAN) {
1377                     // Skip the _has_* variables only if they represent
1378                     // a primitive that may or may not be present
1379                     if (!name.startsWith("_has_") || jclass.getField(name.substring(5)) != null) {
1380                         jsc.add("resultHc = 37 * resultHc + (" + name + "?0:1);");
1381                     }
1382                 } else if (type == JType.BYTE || type == JType.INT || type == JType.SHORT) {
1383                     jsc.add("resultHc = 37 * resultHc + " + name + ";");
1384                 } else if (type == JType.LONG) {
1385                     jsc.add("resultHc = 37 * resultHc + (int)(" + name + "^(" + name + ">>>32));");
1386                 } else if (type == JType.FLOAT) {
1387                     jsc.add("resultHc = 37 * resultHc + java.lang.Float.floatToIntBits(" + name + ");");
1388                 } else if (type == JType.DOUBLE) {
1389                     jsc.add("tmp = java.lang.Double.doubleToLongBits(" + name + ");");
1390                     jsc.add("resultHc = 37 * resultHc + (int)(tmp^(tmp>>>32));");
1391                 }
1392             } else {
1393                 if (getConfig().useCycleBreaker()) {
1394                     // Calculates hashCode in an acyclic recursive manner
1395                     jsc.add("if (" + name + " != null");
1396                     jsc.add("       && !org.castor.core.util.CycleBreaker.startingToCycle(" + name + ")) {");
1397                 } else {
1398                     // Calculates hashCode in a recursive manner
1399                     jsc.add("if (" + name + " != null) {");
1400                 }
1401                 jsc.add("   resultHc = 37 * resultHc + " + name + ".hashCode();");
1402 
1403                 if (getConfig().useCycleBreaker()) {
1404                     // Calculates hashCode in an acyclic recursive manner
1405                     jsc.add("   org.castor.core.util.CycleBreaker.releaseCycleHandle(" + name + ");");
1406                 }
1407                 jsc.add("}");
1408             }
1409         }
1410         jsc.add("");
1411         jsc.add("return resultHc;");
1412     }   //createHashCodeMethod
1413 
1414     /**
1415      * Create an 'equals' method on the given JClass.
1416      *
1417      * @param jclass the Jclass in which we create the equals method
1418      */
1419      public void createEqualsMethod(final JClass jclass) {
1420          if (jclass == null) {
1421             throw new IllegalArgumentException("JClass must not be null");
1422          }
1423 
1424         JField[] fields = jclass.getFields();
1425         JMethod jMethod = new JMethod("equals", JType.BOOLEAN, "true if the objects are equal.");
1426         jMethod.setComment("Overrides the java.lang.Object.equals method.");
1427         jMethod.addParameter(new JParameter(SGTypes.OBJECT, "obj"));
1428 
1429         if (getConfig().useJava50()) {
1430             jMethod.addAnnotation(new JAnnotation(new JAnnotationType("Override")));
1431         }
1432 
1433         jclass.addMethod(jMethod);
1434         JSourceCode jsc = jMethod.getSourceCode();
1435         jsc.add("if ( this == obj )");
1436         jsc.indent();
1437         jsc.add("return true;");
1438         jsc.unindent();
1439         if (jclass.getSuperClassQualifiedName() != null) {
1440             jsc.add("");
1441             jsc.add("if (super.equals(obj)==false)");
1442             jsc.indent();
1443             jsc.add("return false;");
1444             jsc.unindent();
1445         }
1446         jsc.add("");
1447         jsc.add("if (obj instanceof ");
1448         jsc.append(jclass.getLocalName());
1449         jsc.append(") {");
1450         jsc.add("");
1451         if (fields.length > 0) {
1452             jsc.indent();
1453             jsc.add(jclass.getLocalName());
1454             jsc.append(" temp = (");
1455             jsc.append(jclass.getLocalName());
1456             jsc.append(")obj;");
1457             
1458             if (getConfig().useCycleBreaker()) {
1459                 jsc.add("boolean thcycle;");
1460                 jsc.add("boolean tmcycle;");
1461             }
1462         }
1463         for (int i = 0; i < fields.length; i++) {
1464             JField temp = fields[i];
1465             //Be careful to arrayList....
1466 
1467             String name = temp.getName();
1468             if (temp.getType().isPrimitive()) {
1469                 jsc.add("if (this.");
1470                 jsc.append(name);
1471                 jsc.append(" != temp.");
1472                 jsc.append(name);
1473                 jsc.append(")");
1474             } else {
1475                 //-- Check first if the field is not null. This can occur while comparing
1476                 //-- two objects that contains non-mandatory fields.  We only have to check
1477                 //-- one field since x.equals(null) should return false when equals() is
1478                 //-- correctly implemented.
1479                 jsc.add("if (this.");
1480                 jsc.append(name);
1481                 jsc.append(" != null) {");
1482                 jsc.indent();
1483                 jsc.add("if (temp.");
1484                 jsc.append(name);
1485                 jsc.append(" == null) ");
1486                 jsc.indent();
1487                 jsc.append("return false;");
1488                 jsc.unindent();
1489 
1490                 if (getConfig().useCycleBreaker()) {
1491                     jsc.add("if (this.");
1492                     jsc.append(name);
1493                     jsc.append(" != temp.");
1494                     jsc.append(name);
1495                     jsc.append(") {");
1496                     // This prevents string constants and improper DOM subtree self comparisons
1497                     // (where Q(A(B)) and Q'(C(B)) are compared) screwing up cycle detection
1498                     jsc.indent();
1499                     jsc.add("thcycle=org.castor.core.util.CycleBreaker.startingToCycle(this." + name + ");");
1500                     jsc.add("tmcycle=org.castor.core.util.CycleBreaker.startingToCycle(temp." + name + ");");
1501                     // equivalent objects *will* cycle at the same time
1502                     jsc.add("if (thcycle!=tmcycle) {");
1503                     jsc.indent();
1504                     jsc.add("if (!thcycle) { org.castor.core.util.CycleBreaker.releaseCycleHandle(this."
1505                             + name + "); };");
1506                     jsc.add("if (!tmcycle) { org.castor.core.util.CycleBreaker.releaseCycleHandle(temp."
1507                             + name + "); };");
1508                     jsc.add("return false;");
1509                     jsc.unindent();
1510                     jsc.add("}"); // end of unequal cycle point test
1511                     jsc.add("if (!thcycle) {");
1512                     jsc.indent();
1513                 }
1514                 jsc.add("if (!");
1515 
1516                 // Special handling for comparing arrays
1517                 if (temp.getType().isArray()) {
1518                     jsc.append("java.util.Arrays.equals(this.");
1519                     jsc.append(name);
1520                     jsc.append(", temp.");
1521                     jsc.append(name);
1522                     jsc.append(")");
1523                 } else {
1524                     jsc.append("this.");
1525                     jsc.append(name);
1526                     jsc.append(".equals(temp.");
1527                     jsc.append(name);
1528                     jsc.append(")");
1529                 }
1530 
1531                 if (getConfig().useCycleBreaker()) {
1532                     jsc.append(") {");
1533                 } else {
1534                     jsc.append(") ");
1535                 }
1536                 jsc.indent();
1537 
1538                 if (getConfig().useCycleBreaker()) {
1539                     jsc.add("org.castor.core.util.CycleBreaker.releaseCycleHandle(this." + name + ");");
1540                     jsc.add("org.castor.core.util.CycleBreaker.releaseCycleHandle(temp." + name + ");");
1541                 }
1542                 jsc.add("return false;");
1543                 jsc.unindent();
1544 
1545                 if (getConfig().useCycleBreaker()) {
1546                     jsc.add("}");
1547 
1548                     jsc.add("org.castor.core.util.CycleBreaker.releaseCycleHandle(this." + name + ");");
1549                     jsc.add("org.castor.core.util.CycleBreaker.releaseCycleHandle(temp." + name + ");");
1550                 }
1551 
1552                 jsc.unindent();
1553 
1554                 if (getConfig().useCycleBreaker()) {
1555                     jsc.add("}"); // end of !thcycle
1556                     jsc.unindent();
1557                     jsc.add("}"); // end of this.name != that.name object constant check
1558                     jsc.unindent();
1559                 }
1560                 jsc.add("} else if (temp."); // end of != null
1561                 jsc.append(name);
1562                 jsc.append(" != null)");
1563             }
1564             jsc.indent();
1565             jsc.add("return false;");
1566             jsc.unindent();
1567         }
1568         jsc.add("return true;");
1569         jsc.unindent();
1570         jsc.add("}");
1571         jsc.add("return false;");
1572      } //CreateEqualsMethod
1573 
1574     /**
1575      * Implement org.castor.xmlctf.CastorTestable im the given JClass.
1576      *
1577      * @param jclass The JClass which will implement the CastorTestable Interface.
1578      * @param state our state, e.g., state of this Factory instance.
1579      */
1580      public void createTestableMethods(final JClass jclass, final FactoryState state) {
1581          if (jclass == null) {
1582             throw new IllegalArgumentException("JClass must not be null");
1583          }
1584 
1585         jclass.addInterface("org.castor.xmlctf.CastorTestable");
1586         jclass.addImport("org.castor.xmlctf.CastorTestable");
1587         jclass.addImport("org.castor.xmlctf.RandomHelper");
1588 
1589         createRandomizeFields(jclass, state); // implementation of randomizeFields
1590         createDumpFields(jclass);             // implementation of dumpFields
1591      } //CreateTestableMethods
1592 
1593      /**
1594       * Creates the randomizeFields method for a class that implements the
1595       * interface org.castor.xmlctf.CastorTestable.
1596       *
1597       * @param jclass The JClass which will implement the CastorTestable Interface.
1598       * @param state
1599       */
1600     private void createRandomizeFields(final JClass jclass, final FactoryState state) {
1601         JMethod jMethod = new JMethod("randomizeFields");
1602         jMethod.addException(new JClass("InstantiationException"),
1603                              "if we try to instantiate an abstract class or interface");
1604         jMethod.addException(new JClass("IllegalAccessException"),
1605                              "if we do not have access to the field, for example if it is private");
1606         jMethod.setComment("implementation of org.castor.xmlctf.CastorTestable");
1607         jclass.addMethod(jMethod);
1608         JSourceCode jsc = jMethod.getSourceCode();
1609         JField[] fields = jclass.getFields();
1610 
1611         for (int i = 0; i < fields.length; i++) {
1612             JField temp = fields[i];
1613             JType type = temp.getType();
1614             String name = temp.getName();
1615 
1616             if (state.getFieldInfoForChoice() != null
1617                     && name.equals(state.getFieldInfoForChoice().getName())) {
1618                 continue;
1619             }
1620             
1621             if (name.startsWith("enumConstants")) {
1622                 continue;
1623             }
1624 
1625             if (name.startsWith("_")) {
1626                 name = getJavaNaming().toJavaClassName(name.substring(1));
1627             } else {
1628                 name = getJavaNaming().toJavaClassName(name);
1629             }
1630 
1631             String setName = "set" + name;
1632             if (name.indexOf("Has") == -1) {
1633                 if (type instanceof JCollectionType) {
1634                     //Collection needs a specific handling
1635                     int listLocat = name.lastIndexOf("List");
1636                     String tempName = name;
1637                     if (listLocat != -1) {
1638                        tempName = tempName.substring(0, listLocat);
1639                     }
1640                     String methodName = getJavaNaming().toJavaClassName(tempName);
1641                     methodName = "get" + methodName;
1642                     JMethod method = jclass.getMethod(methodName, 0);
1643                     // TODO handle the Item introduced in with the group handling
1644                     if (method == null) {
1645                         continue;
1646                     }
1647 
1648                     String componentName = method.getReturnType().getName();
1649 
1650                     jsc.add(temp.getName());
1651                     jsc.append(" = RandomHelper.getRandom(");
1652                     jsc.append(temp.getName());
1653                     jsc.append(", ");
1654                     jsc.append(componentName);
1655                     jsc.append(".class);");
1656                } else if (type.isPrimitive()) {
1657                    // Primitive
1658                    jsc.add(setName);
1659                    jsc.append("(RandomHelper.getRandom(");
1660                    jsc.append(temp.getName());
1661                    jsc.append("));");
1662                } else if (type.isArray()) {
1663                    // Array
1664                    jsc.add(setName);
1665                    jsc.append("((");
1666                    jsc.append(type.toString());
1667                    jsc.append(")RandomHelper.getRandom(");
1668                    jsc.append(temp.getName());
1669                    // Any Class will do, but Array.class seems appropriate
1670                    jsc.append(", java.lang.reflect.Array.class));");
1671                } else {
1672                    // Object
1673                    jsc.add(setName);
1674                    jsc.append("((");
1675                    jsc.append(type.getName());
1676                    jsc.append(")RandomHelper.getRandom(");
1677                    jsc.append(temp.getName());
1678                    jsc.append(", ");
1679                    jsc.append(type.getName());
1680                    jsc.append(".class));");
1681                }
1682                jsc.add("");
1683             }
1684         }
1685     }
1686 
1687     /**
1688      * Creates the dumpFields method for a class that implements the interface
1689      * org.castor.xmlctf.CastorTestable.
1690      *
1691      * @param jclass The JClass which will implement the CastorTestable Interface.
1692      */
1693     private void createDumpFields(final JClass jclass) {
1694         JMethod jMethod = new JMethod("dumpFields", SGTypes.STRING,
1695                 "a String representation of all of the fields for " + jclass.getName());
1696         jMethod.setComment("implementation of org.castor.xmlctf.CastorTestable");
1697         jclass.addMethod(jMethod);
1698         JSourceCode jsc = jMethod.getSourceCode();
1699         jsc.add("StringBuffer stringBuffer = new StringBuffer(\"DumpFields() for element: ");
1700         jsc.append(jclass.getName());
1701         jsc.append("\\n\");");
1702 
1703         JField[] fields = jclass.getFields();
1704         for (int i = 0; i < fields.length; i++) {
1705             JField temp = fields[i];
1706             String name = temp.getName();
1707             if ((temp.getType().isPrimitive())
1708                     || temp.getType().getName().startsWith("java.lang.")) {
1709                 //hack when using the option 'primitivetowrapper'
1710                 //this should not interfere with other cases
1711                 jsc.add("stringBuffer.append(\"Field ");
1712                 jsc.append(name);
1713                 jsc.append(":\" +");
1714                 jsc.append(name);
1715                 jsc.append("+\"\\n\");");
1716             } else if (temp.getType().isArray()) {
1717                 jsc.add("if (");
1718                 jsc.append(name);
1719                 jsc.append(" != null) {");
1720                 jsc.indent();
1721                 jsc.add("stringBuffer.append(\"[\");");
1722                 jsc.add("for (int i = 0; i < ");
1723                 jsc.append(name);
1724                 jsc.append(".length; i++) {");
1725                 jsc.indent();
1726                 jsc.add("stringBuffer.append(");
1727                 jsc.append(name);
1728                 jsc.append("[i] + \" \");");
1729                 jsc.unindent();
1730                 jsc.add("}");
1731                 jsc.add("stringBuffer.append(\"]\");");
1732                 jsc.unindent();
1733                 jsc.add("}");
1734             } else {
1735                 jsc.add("if ( (");
1736                 jsc.append(name);
1737                 jsc.append(" != null) && (");
1738                 jsc.append(name);
1739                 jsc.append(".getClass().isAssignableFrom(CastorTestable.class)))");
1740                 jsc.indent();
1741                 jsc.add("stringBuffer.append(((CastorTestable)");
1742                 jsc.append(name);
1743                 jsc.append(").dumpFields());");
1744                 jsc.unindent();
1745                 jsc.add("else stringBuffer.append(\"Field ");
1746                 jsc.append(name);
1747                 jsc.append(":\" +");
1748                 jsc.append(name);
1749                 jsc.append("+\"\\n\");");
1750             }
1751             jsc.add("");
1752         }
1753         jsc.add("");
1754         jsc.add("return stringBuffer.toString();");
1755     }
1756 
1757     /**
1758      * Creates the Validate methods for the given JClass.
1759      * @param jClass the JClass to create the Validate methods for
1760      */
1761     private void createValidateMethods(final JClass jClass) {
1762         JMethod     jMethod = null;
1763         JSourceCode jsc     = null;
1764 
1765         //-- #validate
1766         jMethod = new JMethod("validate");
1767         jMethod.addException(SGTypes.VALIDATION_EXCEPTION,
1768                              "if this object is an invalid instance according to the schema");
1769 
1770         jClass.addMethod(jMethod);
1771         jsc = jMethod.getSourceCode();
1772         jsc.add("org.exolab.castor.xml.Validator validator = new ");
1773         jsc.append("org.exolab.castor.xml.Validator();");
1774         jsc.add("validator.validate(this);");
1775 
1776         //-- #isValid
1777         jMethod  = new JMethod("isValid", JType.BOOLEAN,
1778                                "true if this object is valid according to the schema");
1779         jsc = jMethod.getSourceCode();
1780         jsc.add("try {");
1781         jsc.indent();
1782         jsc.add("validate();");
1783         jsc.unindent();
1784         jsc.add("} catch (org.exolab.castor.xml.ValidationException vex) {");
1785         jsc.indent();
1786         jsc.add("return false;");
1787         jsc.unindent();
1788         jsc.add("}");
1789         jsc.add("return true;");
1790         jClass.addMethod(jMethod);
1791     } //-- createValidateMethods
1792 
1793     //-------------------/
1794     //- Private Methods -/
1795     //-------------------/
1796 
1797     /**
1798      * Resolves the className out of the given name and the packageName.
1799      *
1800      * @param name the class name
1801      * @param packageName the package name
1802      * @return the full qualified class name.
1803      */
1804     private String resolveClassName(final String name, final String packageName) {
1805         if ((packageName != null) && (packageName.length() > 0)) {
1806             return packageName + "." + name;
1807         }
1808         return name;
1809     } //-- resolveClassName
1810 
1811     //////////////////////////////////////////////
1812     //Process XML Schema structures
1813     //Note: This code is XML specific, it has to be moved somehow in XMLBindingComponent.
1814     //The aim of the SourceFactory is to generate code from a BindingComponent.
1815     ///////////////////////////////////////////////
1816 
1817     /**
1818      * This method handles the processing of AppInfo elements from the input
1819      * schema and adds the information found therein to the specified
1820      * {@link ClassInfo}.
1821      * 
1822      * @param annotated
1823      *            the {@link org.exolab.castor.xml.schema.Structure} holding the
1824      *            {@link AppInfo} annotations.
1825      * @param cInfo
1826      *            the {@link ClassInfo} to store the information found in the
1827      *            AppInfos in.
1828      * @see ClassInfo
1829      * @see AppInfo
1830      * @see Annotated
1831      */
1832     private void processAppInfo(final Annotated annotated, final ClassInfo cInfo) {
1833         Enumeration<Annotation> annotations = annotated.getAnnotations();
1834         while (annotations.hasMoreElements()) {
1835             Annotation ann = annotations.nextElement();
1836             Enumeration<AppInfo> appInfos = ann.getAppInfo();
1837             while (appInfos.hasMoreElements()) {
1838                 AppInfo appInfo = appInfos.nextElement();
1839                 if (appInfo.hasNature(AppInfoJpaNature.class.getName())) {
1840                     AppInfoJpaNature nature = new AppInfoJpaNature(appInfo);
1841                     List<?> content = nature.getContent();
1842                     if (content != null && !content.isEmpty()) {
1843                         Iterator<?> it = content.iterator();
1844                         if (it.hasNext()) {
1845                             cInfo.addNature(JDOClassInfoNature.class.getName());
1846                             JDOClassInfoNature cNature = new JDOClassInfoNature(cInfo);
1847                             while (it.hasNext()) {
1848                                 Object tmpObject = it.next();
1849                                 if (tmpObject instanceof Table) {
1850                                     Table table = (Table) tmpObject;
1851                                     cNature.setTableName(table.getName());
1852                                     cNature.setAccessMode(AccessMode.valueOf("shared"));
1853                                     cNature.setDetachable(table.isDetachable());
1854                                     // TODO: Uncomment next line as soon as Annotation Classes have been updated!
1855                                     //                            cNature.setAccessMode(AccessMode.valueOf(table.getAccessMode().toString()));
1856                                     PrimaryKey pk = table.getPrimaryKey();
1857                                     Iterator<? extends String> pIt = pk.iterateKey();
1858                                     while (pIt.hasNext()) {
1859                                         cNature.addPrimaryKey(pIt.next());
1860                                     }
1861                                 }
1862                             }
1863                         }
1864                     }
1865                 }
1866             }
1867         }
1868     }
1869     
1870     /**
1871      * This method handles the processing of AppInfo elements from the input
1872      * schema and adds the information found therein to the specified
1873      * {@link FieldInfo}.
1874      * 
1875      * @param annotated
1876      *            the {@link org.exolab.castor.xml.schema.Structure} holding the
1877      *            {@link AppInfo} annotations.
1878      * @param fInfo
1879      *            the {@link ClassInfo} to store the information found in the
1880      *            AppInfos in.
1881      * @see FieldInfo
1882      * @see AppInfo
1883      * @see Annotated
1884      */
1885     private void processAppInfo(final Annotated annotated, final FieldInfo fInfo) {
1886         Enumeration<Annotation> annotations = annotated.getAnnotations();
1887         
1888         while (annotations.hasMoreElements()) {
1889             Annotation ann = annotations.nextElement();
1890             Enumeration<AppInfo> appInfos = ann.getAppInfo();
1891             while (appInfos.hasMoreElements()) {
1892                 AppInfo appInfo = appInfos.nextElement();
1893                 
1894                 if (appInfo.hasNature(AppInfoSolrjNature.class.getName())) {
1895                     AppInfoSolrjNature nature = new AppInfoSolrjNature(appInfo);
1896                     Object solrjRawContent = nature.getContent();
1897                     if (solrjRawContent != null) {
1898                         fInfo.addNature(SolrjFieldInfoNature.class.getName());
1899                         SolrjFieldInfoNature solrjNature = new SolrjFieldInfoNature(fInfo);
1900                         if (solrjRawContent instanceof Field) {
1901                             Field solrjField = (Field) solrjRawContent;
1902                             if (StringUtils.isNotBlank(solrjField.getName())) {
1903                                 solrjNature.setFieldName(solrjField.getName());
1904                             }
1905                         }
1906                     }
1907                 }
1908                 
1909                 if (appInfo.hasNature(AppInfoJpaNature.class.getName())) {
1910                     AppInfoJpaNature nature = new AppInfoJpaNature(appInfo);
1911                     List<?> content = nature.getContent();
1912                     if (content != null && !content.isEmpty()) {
1913                         Iterator<?> it = content.iterator();
1914                         if (it.hasNext()) {                 
1915                             while (it.hasNext()) {
1916                                 Object tmpObject = it.next();
1917                                 if (tmpObject instanceof Column) {
1918                                     fInfo.addNature(JDOFieldInfoNature.class.getName());
1919                                     JDOFieldInfoNature fNature = new JDOFieldInfoNature(fInfo);
1920                                     Column column = (Column) tmpObject;
1921                                     fNature.setColumnName(column.getName());
1922                                     fNature.setColumnType(column.getType());
1923                                     fNature.setReadOnly(column.isReadOnly());
1924                                     fNature.setDirty(false);
1925                                     fNature.setDirty(column.getDirty());
1926                                 } else if (tmpObject instanceof OneToOne) {
1927                                     OneToOne relation = (OneToOne) tmpObject;
1928                                     fInfo.addNature(JDOOneToOneNature.class.getName());
1929                                     JDOOneToOneNature oneNature = new JDOOneToOneNature(fInfo);
1930                                     oneNature.addForeignKey(relation.getName());
1931                                     oneNature.setDirty(relation.isDirty());
1932                                     oneNature.setReadOnly(relation.isReadOnly());
1933                                 } else if (tmpObject instanceof OneToMany) {
1934                                     OneToMany relation = (OneToMany) tmpObject;
1935                                     fInfo.addNature(JDOOneToManyNature.class.getName());
1936                                     JDOOneToManyNature manyNature = new JDOOneToManyNature(fInfo);
1937                                     manyNature.addForeignKey(relation.getName());
1938                                     manyNature.setDirty(relation.isDirty());
1939                                     manyNature.setReadOnly(relation.isReadOnly());
1940                                 }
1941                             }
1942                         }
1943                     }
1944                 }
1945             }
1946         }
1947     }
1948     
1949     /**
1950      * Process the attributes contained in this complexType.
1951      * @param binding
1952      * @param complexType the given complex type.
1953      * @param state the given FactoryState
1954      */
1955     private void processAttributes(final ExtendedBinding binding,
1956             final ComplexType complexType,
1957             final FactoryState state) {
1958         if (complexType == null) {
1959             return;
1960         }
1961 
1962         Enumeration<AttributeDecl> enumeration = complexType.getAttributeDecls();
1963         XMLBindingComponent component = new XMLBindingComponent(getConfig(), getGroupNaming());
1964         if (_binding != null) {
1965             component.setBinding(_binding);
1966         }
1967 
1968         while (enumeration.hasMoreElements()) {
1969             AttributeDecl attr = enumeration.nextElement();
1970 
1971             component.setView(attr);
1972 
1973             //-- if we have a new SimpleType...generate ClassInfo
1974             SimpleType sType = attr.getSimpleType();
1975 
1976             // look for simpleType def in base type(s)
1977             XMLType baseXMLType = complexType.getBaseType();
1978             while (sType == null) {
1979                 // If no simple type found: Get the same attribute of the base type.
1980                 // If base type is not complex, forget it; break out of loop now.
1981                 if (baseXMLType == null || !(baseXMLType instanceof ComplexType)) {
1982                     break;
1983                 }
1984 
1985                 // There's a base complexType; get the attribute with the same name
1986                 // as this attribute (=attr) from it
1987                 final ComplexType baseComplexType = (ComplexType) baseXMLType;
1988                 AttributeDecl baseAttribute = baseComplexType.getAttributeDecl(attr.getName());
1989 
1990                 if (baseAttribute != null) {
1991                     // See if this one has a simple-type...
1992                     sType = baseAttribute.getSimpleType();
1993                     if (sType != null) {
1994                         attr.setSimpleType(sType);
1995                         break;
1996                     }
1997                 }
1998 
1999                 // ... if not, go another step higher in the class hierarchy
2000                 baseXMLType = baseXMLType.getBaseType();
2001             }
2002 
2003             // Look for referenced type (if any) for setting type, and use
2004             // it, if found.
2005             if (sType == null && attr.getReference() != null) {
2006                 SimpleType referencedSimpleType = attr.getReference().getSimpleType();
2007                 attr.setSimpleType(referencedSimpleType);
2008                 sType = referencedSimpleType;
2009             }
2010 
2011             if (sType != null && !(SimpleTypesFactory.isBuiltInType(sType.getTypeCode()))) {
2012                 if (sType.getSchema() == component.getSchema() && state.resolve(sType) == null) {
2013                     if (sType.hasFacet(Facet.ENUMERATION)) {
2014                         createSourceCode(component.getBinding(), sType, state.getSGStateInfo());
2015                     }
2016                 }
2017             }
2018 
2019             FieldInfo fieldInfo = _memberFactory.createFieldInfo(component, state, getConfig().useJava50());
2020             handleField(fieldInfo, state, component);
2021         }
2022     }
2023 
2024     /**
2025      * @param complexType the ComplexType to process
2026      * @param state the FactoryState.
2027      */
2028     private void processComplexType(final ComplexType complexType, final FactoryState state) {
2029         XMLBindingComponent component = new XMLBindingComponent(getConfig(), getGroupNaming());
2030         if (_binding != null) {
2031             component.setBinding(_binding);
2032         }
2033         component.setView(complexType);
2034 
2035         String typeName = component.getXMLName();
2036 
2037         ClassInfo classInfo = state.getClassInfo();
2038         XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
2039         xmlNature.setSchemaType(new XSClass(state.getJClass(), typeName));
2040 
2041         /// I don't believe this should be here: kv 20030423
2042         ///classInfo.setNamespaceURI(component.getTargetNamespace());
2043 
2044         //- Handle derived types
2045         XMLType base = complexType.getBaseType();
2046 
2047         //-- if the base is a complexType, we need to process it
2048         if (base != null) {
2049             if (base.isComplexType()) {
2050                 String baseClassName = null;
2051 
2052                 component.setView(base);
2053                 //-- Is this base type from the schema we are currently generating source for?
2054                 //////////////////////////////////////////////////////////
2055                 //NOTE: generate sources if the flag for generating sources
2056                 //from imported schemas in on
2057                 //////////////////////////////////////////////////////////
2058                 if (base.getSchema() == complexType.getSchema()) {
2059                     ClassInfo cInfo = state.resolve(base);
2060                     //--no classInfo yet so no source code available
2061                     //--for the base type: we need to generate it
2062                     if (cInfo == null) {
2063                         JClass[] classes = createSourceCode(component, state.getSGStateInfo());
2064                         cInfo = state.resolve(base);
2065                         baseClassName = classes[0].getName();
2066                     } else {
2067                         baseClassName = cInfo.getJClass().getName();
2068                     }
2069                     //set the base class
2070                     classInfo.setBaseClass(cInfo);
2071                 } else {
2072                     //-- Create qualified class name for a base type class
2073                     //-- from another package
2074                     baseClassName = component.getQualifiedName();
2075                  }
2076                 //-- Set super class
2077                 //-- and reset the view on the current ComplexType
2078                 component.setView(complexType);
2079                 // only set a super class name if the current complexType is not a
2080                 // restriction of a simpleContent (--> no object hierarchy, only content hierarchy)
2081                 /*
2082                  Note: There are times when a simpleContent restriction needs to
2083                  extend the hierarchy, such as a restriction of a restriction, so
2084                  I'm commenting out the following line for now. see bug 1875
2085                  for more details. If this causes any regressions we'll need to
2086                  find a more appropriate solution.
2087                  if (! ( complexType.isRestricted() && ((ComplexType)base).isSimpleContent() ) )
2088                 */
2089                 state.getJClass().setSuperClass(baseClassName);
2090             } //--complexType
2091 
2092             //--if the content type is a simpleType create a field info for it.
2093             if (complexType.getContentType().getType() == ContentType.SIMPLE) {
2094                 SimpleContent simpleContent = (SimpleContent) complexType.getContentType();
2095                 SimpleType temp = simpleContent.getSimpleType();
2096                 SimpleType baseType = (SimpleType) temp.getBaseType();
2097                 XSType xsType = _typeConversion.convertType(
2098                         temp, state.getPackageName(), getConfig().useJava50());
2099 
2100                 FieldInfo fieldInfo = null;
2101                 if ((baseType != null) && extendsSimpleType(state.getJClass(), baseType, state)) {
2102                     if (xsType.isEnumerated()) {
2103                         fieldInfo = _memberFactory.createFieldInfoForContent(
2104                                 component, xsType, getConfig().useJava50());
2105                         fieldInfo.setBound(false);
2106 
2107                         handleField(fieldInfo, state, component);
2108 
2109                         //-- remove getter since we don't need to override the original getter
2110                         String mname = fieldInfo.getReadMethodName();
2111                         JClass jClass = state.getJClass();
2112                         JMethod method = jClass.getMethod(mname, 0);
2113                         jClass.removeMethod(method);
2114 
2115                         //-- update setter method
2116                         mname = fieldInfo.getWriteMethodName();
2117                         method = jClass.getMethod(mname, 0);
2118                         JSourceCode jsc = method.getSourceCode();
2119                         jsc.add("super.");
2120                         jsc.append(mname);
2121                         jsc.append("(this.");
2122                         jsc.append(fieldInfo.getName());
2123                         jsc.append(".toString());");
2124                     }
2125                     //-- else just use superclass setters/getters
2126                     //-- do nothing
2127                 } else {
2128                     // 
2129                     while (temp.getBaseType() != null && !temp.isBuiltInType()) {
2130                         temp = (SimpleType) temp.getBaseType();
2131                     }
2132                     
2133                     xsType = _typeConversion.convertType(
2134                             temp, state.getPackageName(), getConfig().useJava50());
2135                     fieldInfo = _memberFactory.createFieldInfoForContent(
2136                             component, xsType, getConfig().useJava50());
2137                     handleField(fieldInfo, state, component);
2138                 }
2139             }
2140         } //--base not null
2141 
2142         //---------------------/
2143         //- handle attributes -/
2144         //- and mixed content -/
2145         //---------------------/
2146 
2147         if (!state.isCreateGroupItem()) {
2148             processAttributes(component.getBinding(), complexType, state);
2149             //--reset the view on the current ComplexType
2150             component.setView(complexType);
2151             if (complexType.getContentType() == ContentType.mixed) {
2152                 FieldInfo fieldInfo = _memberFactory.createFieldInfoForContent(
2153                         component, new XSString(), getConfig().useJava50());
2154                 handleField(fieldInfo, state, component);
2155             }
2156         }
2157         //--process the contentModelGroup
2158         processContentModel(complexType, state);
2159     } //-- processComplextype
2160 
2161     /**
2162      * Processes the given ContentModelGroup. This method is responsible for
2163      * creating FieldInfos (or sometimes ClassInfos) for elements and
2164      * model group contained in the given ContentModelGroup.
2165      *
2166      * @param model the ContentModelGroup to process
2167      * @param state the current FactoryState.
2168      */
2169     private void processContentModel(final ContentModelGroup model,
2170             final FactoryState state) {
2171         //------------------------------/
2172         //- handle elements and groups -/
2173         //------------------------------/
2174 
2175         ContentModelGroup contentModel = model;
2176         Enumeration<Annotated> enumeration = contentModel.enumerate();
2177 
2178         //-- handle choice item
2179         if (new XMLInfoNature(state.getClassInfo()).isChoice() 
2180                 && state.getFieldInfoForChoice() == null) {
2181             state.setFieldInfoForChoice(_memberFactory.createFieldInfoForChoiceValue());
2182             state.getFieldInfoForChoice().getMemberAndAccessorFactory().createJavaField(
2183                     state.getFieldInfoForChoice(),
2184                     state.getJClass());
2185             state.getFieldInfoForChoice().getMemberAndAccessorFactory().createAccessMethods(
2186                     state.getFieldInfoForChoice(), state.getJClass(), getConfig().useJava50(),
2187                      getConfig().getAnnotationBuilders());
2188         }
2189 
2190         FieldInfo fieldInfo = null;
2191         XMLBindingComponent component = new XMLBindingComponent(getConfig(), getGroupNaming());
2192         if (_binding != null) {
2193             component.setBinding(_binding);
2194         }
2195 
2196         while (enumeration.hasMoreElements()) {
2197             Annotated annotated = enumeration.nextElement();
2198             component.setView(annotated);
2199 
2200             switch (annotated.getStructureType()) {
2201                 case Structure.ELEMENT: //-- handle element declarations
2202                     fieldInfo = _memberFactory.createFieldInfo(
2203                             component, state, getConfig().useJava50());
2204                     //-- Fix for element declarations being used in
2205                     //-- a group with minOccurs = 0;
2206                     //-- (kvisco - 20021007)
2207                     if (contentModel.getMinOccurs() == 0) {
2208                         XMLInfoNature xmlNature = new XMLInfoNature(fieldInfo);
2209                         xmlNature.setRequired(false);
2210                     }
2211 
2212                     handleField(fieldInfo, state, component);
2213                     break;
2214                 case Structure.GROUP: //-- handle groups
2215                     Group group = (Group) annotated;
2216                     //set the compositor
2217                     if ((contentModel instanceof ComplexType)
2218                             || (contentModel instanceof ModelGroup)) {
2219                         if (group.getOrder() == Order.choice) {
2220                             new XMLInfoNature(state.getClassInfo()).getGroupInfo().setAsChoice();
2221                         } else if (group.getOrder() == Order.all) {
2222                             new XMLInfoNature(state.getClassInfo()).getGroupInfo().setAsAll();
2223                         } else if (group.getOrder() == Order.sequence) {
2224                             new XMLInfoNature(state.getClassInfo()).getGroupInfo().setAsSequence();
2225                         }
2226                     }
2227 
2228                     //-- create class member,if necessary
2229                     if (!((contentModel instanceof ComplexType)
2230                             || (contentModel instanceof ModelGroup))) {
2231                         if (contentModel instanceof ModelGroup) {
2232                             ModelGroup mg = (ModelGroup) contentModel;
2233                             if (mg.isReference()) {
2234                                 contentModel = mg.getReference();
2235                             }
2236                         }
2237 
2238                         if (contentModel.getParticleCount() > 0) {
2239                             fieldInfo = _memberFactory.createFieldInfo(
2240                                     component, state.getSGStateInfo(), getConfig().useJava50());
2241                             handleField(fieldInfo, state, component);
2242                         }
2243                     } else {
2244                        //--else we just flatten the group
2245                        processContentModel(group, state);
2246                     }
2247                     break;
2248 
2249                 case Structure.MODELGROUP:
2250                      ModelGroup modelgroup = (ModelGroup) annotated;
2251                      //--a Model Group definition can only referenced
2252                      //--another group at this point.
2253                      //get the contentModel and proccess it
2254                     if (modelgroup.getName() != null) {
2255                         //create the field info for the element
2256                         //that is referring to a model group in order
2257                         //not to loose the Particle information
2258                         if (modelgroup.isReference()) {
2259                             modelgroup = modelgroup.getReference();
2260                         }
2261 
2262                         if (modelgroup.getParticleCount() > 0) {
2263                             fieldInfo = _memberFactory.createFieldInfo(
2264                                     component, state.getSGStateInfo(), getConfig().useJava50());
2265                             handleField(fieldInfo, state, component);
2266                         }
2267                         break;
2268                     }
2269                     //--else we just flatten the group
2270                     processContentModel(modelgroup.getContentModelGroup(), state);
2271                     break;
2272 
2273                 case Structure.WILDCARD:
2274                     Wildcard wildcard = (Wildcard) annotated;
2275                     FieldInfo fieldForAny = _memberFactory.createFieldInfoForAny(
2276                             wildcard, getConfig().useJava50());
2277                     handleField(fieldForAny, state, component);
2278                     break;
2279 
2280                 default:
2281                     break;
2282             }
2283         }
2284 
2285     } //-- process(ContentModelGroup)
2286 
2287     /**
2288      * Creates all the necessary enumeration code from the given Creates all the
2289      * necessary enumeration code from the given SimpleType. Enumerations are
2290      * handled a couple ways.
2291      *
2292      * @param binding CUrrent XML binding
2293      * @param simpleType the SimpleType we are processing an enumeration for
2294      * @param state our current state
2295      * @see #processEnumerationAsBaseType
2296      */
2297     private void processEnumeration(final ExtendedBinding binding,
2298             final SimpleType simpleType, final FactoryState state) {
2299         // Added by robertlaferla at comcast dot net 01/21/2004
2300         if (getConfig().useEnumeratedTypeInterface()) {
2301             state.getJClass().addInterface(ENUM_ACCESS_INTERFACE);
2302         } // end enumTypeInterface
2303 
2304         switch (_enumerationType) {
2305             case BASE_TYPE_ENUMERATION:
2306                 processEnumerationAsBaseType(binding, simpleType, state);
2307                 break;
2308             default:
2309                 processEnumerationAsNewObject(binding, simpleType, state);
2310                 break;
2311         }
2312     } //-- processEnumeration
2313 
2314     /**
2315      * Creates all the necessary enumeration code from the given SimpleType. Delegates
2316      * to EnumerationFactory.
2317      *
2318      * @param binding Current XML binding
2319      * @param simpleType the SimpleType we are processing an enumeration for
2320      * @param state our current state
2321      * @see #processEnumerationAsBaseType
2322      */
2323     private void processEnumerationAsNewObject(final ExtendedBinding binding,
2324             final SimpleType simpleType, final FactoryState state) {
2325         _enumerationFactory.processEnumerationAsNewObject(binding, simpleType, state);
2326         if (_testable && state.getJClass() instanceof JEnum) {
2327             createTestableMethods(state.getJClass(), state);
2328         }
2329     } //-- processEnumerationAsNewObject
2330 
2331     /**
2332      * Delegates creation of enumeration code to EnumerationFactory.
2333      *
2334      * @param binding Current XML binding
2335      * @param simpleType the SimpleType we are processing an enumeration for
2336      * @param state our current state
2337      */
2338     private void processEnumerationAsBaseType(final ExtendedBinding binding,
2339             final SimpleType simpleType, final FactoryState state) {
2340         _enumerationFactory.processEnumerationAsBaseType(binding, simpleType, state);
2341     } //-- processEnumerationAsBaseType
2342 
2343     /**
2344      * Adds a given FieldInfo to the JClass and ClassInfo stored in the given
2345      * FactoryState.
2346      *
2347      * @param fieldInfo The fieldInfo to add
2348      * @param state the current FactoryState
2349      * @param component the current XMLBindingComponent to read AppInfos from.
2350      */
2351     private void handleField(final FieldInfo fieldInfo, final FactoryState state, final XMLBindingComponent component) {
2352         if (fieldInfo == null) {
2353             return;
2354         }
2355 
2356         XMLInfoNature xmlNature = new XMLInfoNature(fieldInfo);
2357         
2358         if (CLASS_METHOD_SUFFIX.equals(fieldInfo.getMethodSuffix())) {
2359             SGStateInfo sInfo = state.getSGStateInfo();
2360             if (!sInfo.getSuppressNonFatalWarnings()) {
2361                 String warn = "warning a field name conflicts with \""
2362                     + CLASS_KEYWORD + "\", please use a binding file to specify "
2363                     + "a different name for the " + xmlNature.getNodeTypeName()
2364                     + " '" + xmlNature.getNodeName() + "'.";
2365                 sInfo.getDialog().notify(warn);
2366             }
2367         } else if (CLASS_KEYWORD.equals(xmlNature.getNodeName())) {
2368             SGStateInfo sInfo = state.getSGStateInfo();
2369             if (!sInfo.getSuppressNonFatalWarnings()) {
2370                 String warn = "warning a field name conflicts with \""
2371                     + CLASS_KEYWORD + "\" and is being replaced by \"clazz\". "
2372                     + "You may use a binding file to specify a different "
2373                     + "name for the " + xmlNature.getNodeTypeName()
2374                     + " '" + xmlNature.getNodeName() + "'.";
2375                 sInfo.getDialog().notify(warn);
2376             }
2377         }
2378         
2379         processAppInfo(component.getAnnotated(), fieldInfo);
2380         
2381         JSourceCode scInitializer = state.getJClass().getConstructor(0).getSourceCode();
2382 
2383         ClassInfo base = state.getClassInfo().getBaseClass();
2384         boolean present = false;
2385         if (base != null) {
2386             switch (new XMLInfoNature(fieldInfo).getNodeType()) {
2387                 case ATTRIBUTE:
2388                     present = (base.getAttributeField(xmlNature.getNodeName()) != null);
2389                     break;
2390                 case ELEMENT:
2391                     String baseNodeName = xmlNature.getNodeName();
2392                     // TODO[WG]: replace this error check with something more meaningful
2393                     if (baseNodeName != null
2394                             && !(baseNodeName.equals(XMLInfo.CHOICE_NODE_NAME_ERROR_INDICATION))) {
2395                         // check whether there is an equally named field in the base
2396                         // class, and don't forget to consider the namspaces as well to 
2397                         // determine whether the fields are really equal.
2398                         FieldInfo inheritedFieldInfo = base.getElementField(baseNodeName);
2399                         
2400                         if (inheritedFieldInfo != null) {
2401                             String namespaceURI = xmlNature.getNamespaceURI();
2402                             if (namespaceURI != null && namespaceURI.equals(new XMLInfoNature(inheritedFieldInfo).getNamespaceURI())) {
2403                                 present = true;
2404                             }
2405                         }
2406                     }
2407                     break;
2408                 default:
2409                     break;
2410             }
2411         }
2412 
2413         state.getClassInfo().addFieldInfo(fieldInfo);
2414         present = present && !xmlNature.isMultivalued();
2415         //create the relevant Java fields only if the field
2416         //info is not yet in the base classInfo or if it is not a collection
2417         if (!present) {
2418             if (state.getFieldInfoForChoice() != null) {
2419                 if (fieldInfo != state.getFieldInfoForChoice()) {
2420                     fieldInfo.setFieldInfoReference(state.getFieldInfoForChoice());
2421                 }
2422             }
2423 
2424             fieldInfo.getMemberAndAccessorFactory().createJavaField(fieldInfo, state.getJClass());
2425             //-- do not create access methods for transient fields
2426             if (!fieldInfo.isTransient()) {
2427                 fieldInfo.getMemberAndAccessorFactory().createAccessMethods(
2428                         fieldInfo, state.getJClass(), getConfig().useJava50(),
2429                         getConfig().getAnnotationBuilders());
2430                 if (fieldInfo.isBound()) {
2431                     state.setBoundProperties(true);
2432                 }
2433             }
2434         }
2435 
2436         //-- Add initialization code
2437         fieldInfo.getMemberAndAccessorFactory().generateInitializerCode(fieldInfo, scInitializer);
2438     } //-- handleField
2439 
2440     /**
2441      * Returns true if the given JClass extends the class represented by the
2442      * given SimpleType.
2443      *
2444      * @param jClass the JClass to check
2445      * @param type the SimpleType to check against
2446      * @param state the FactoryState
2447      *
2448      * @return true if the given JClass extends the class associated with the
2449      *         given SimpleType, otherwise false.
2450      */
2451     private boolean extendsSimpleType(final JClass jClass, final SimpleType type,
2452                                       final FactoryState state) {
2453         String superClassName = jClass.getSuperClassQualifiedName();
2454         if (superClassName != null) {
2455             ClassInfo cInfo = state.resolve(type);
2456             if (cInfo != null) {
2457                return superClassName.equals(cInfo.getJClass().getName());
2458             }
2459         }
2460         return false;
2461     } //-- extendsSimpleType
2462 
2463 } //-- SourceFactory