View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * This file was originally developed by Keith Visco during the course of employment at Intalio Inc.
34   * All portions of this file developed by Keith Visco after Jan 19 2005 are Copyright (C) 2005 Keith
35   * Visco. All Rights Reserverd.
36   *
37   * $Id$
38   */
39  package org.exolab.castor.builder.descriptors;
40  
41  import java.util.Iterator;
42  import java.util.List;
43  
44  import org.exolab.castor.builder.BuilderConfiguration;
45  import org.exolab.castor.builder.SGTypes;
46  import org.exolab.castor.builder.factory.XMLFieldHandlerFactory;
47  import org.exolab.castor.builder.info.ClassInfo;
48  import org.exolab.castor.builder.info.CollectionInfo;
49  import org.exolab.castor.builder.info.FieldInfo;
50  import org.exolab.castor.builder.info.NodeType;
51  import org.exolab.castor.builder.info.XMLInfo;
52  import org.exolab.castor.builder.info.nature.XMLInfoNature;
53  import org.exolab.castor.builder.types.XSList;
54  import org.exolab.castor.builder.types.XSListType;
55  import org.exolab.castor.builder.types.XSType;
56  import org.exolab.castor.mapping.FieldDescriptor;
57  import org.exolab.castor.xml.Validator;
58  import org.exolab.castor.xml.XMLConstants;
59  import org.exolab.castor.xml.XMLFieldDescriptor;
60  import org.exolab.javasource.JClass;
61  import org.exolab.javasource.JConstant;
62  import org.exolab.javasource.JConstructor;
63  import org.exolab.javasource.JNaming;
64  import org.exolab.javasource.JPrimitiveType;
65  import org.exolab.javasource.JSourceCode;
66  import org.exolab.javasource.JType;
67  
68  /**
69   * A factory for creating the source code of descriptor classes.
70   *
71   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
72   * @version $Revision$ $Date: 2006-04-13 07:37:49 -0600 (Thu, 13 Apr 2006) $
73   */
74  public final class DescriptorSourceFactory {
75    /** GeneralizedFieldHandler. */
76    private static final JClass GENERALIZED_FIELD_HANDLER_CLASS =
77        new JClass("org.exolab.castor.mapping.GeneralizedFieldHandler");
78    /** Name of the field validator instance variable in generated code. */
79    private static final String FIELD_VALIDATOR_NAME = "fieldValidator";
80  
81    /** The BuilderConfiguration instance. */
82    private final BuilderConfiguration _config;
83  
84    /** Factory for creating XMLFieldHandler instances embedded in descriptors. */
85    private XMLFieldHandlerFactory _xmlFieldHandlerFactory;
86  
87    /**
88     * Creates a new DescriptorSourceFactory with the given configuration.
89     *
90     * @param config the BuilderConfiguration instance
91     */
92    public DescriptorSourceFactory(final BuilderConfiguration config) {
93      if (config == null) {
94        String err = "The argument 'config' must not be null.";
95        throw new IllegalArgumentException(err);
96      }
97      _config = config;
98      _xmlFieldHandlerFactory = new XMLFieldHandlerFactory(config);
99    } // -- DescriptorSourceFactory
100 
101   /**
102    * Creates the Source code of a MarshalInfo for a given XML Schema element declaration.
103    *
104    * @param classInfo the XML Schema element declaration
105    * @return the JClass representing the MarshalInfo source code
106    */
107   public JClass createSource(final ClassInfo classInfo) {
108     JClass jClass = classInfo.getJClass();
109     String localClassName = jClass.getLocalName();
110 
111     String descriptorClassName = getQualifiedDescriptorClassName(jClass.getName());
112     DescriptorJClass classDesc = new DescriptorJClass(_config, descriptorClassName, jClass);
113 
114     // -- get handle to default constuctor
115     JConstructor cons = classDesc.getConstructor(0);
116     JSourceCode jsc = cons.getSourceCode();
117     XMLInfoNature xmlNature = new XMLInfoNature(classInfo);
118 
119     // -- Set namespace prefix
120     String nsPrefix = xmlNature.getNamespacePrefix();
121     if ((nsPrefix != null) && (nsPrefix.length() > 0)) {
122       jsc.add("_nsPrefix = \"");
123       jsc.append(nsPrefix);
124       jsc.append("\";");
125     }
126 
127     // -- Set namespace URI
128     String nsURI = xmlNature.getNamespaceURI();
129     if ((nsURI != null) && (nsURI.length() > 0)) {
130       jsc.add("_nsURI = \"");
131       jsc.append(nsURI);
132       jsc.append("\";");
133     }
134 
135     // -- set XML Name
136     String xmlName = xmlNature.getNodeName();
137     if (xmlName != null) {
138       jsc.add("_xmlName = \"");
139       jsc.append(xmlName);
140       jsc.append("\";");
141     }
142 
143     // -- set Element Definition flag
144     boolean elementDefinition = xmlNature.isElementDefinition();
145     jsc.add("_elementDefinition = ");
146     jsc.append(Boolean.toString(elementDefinition));
147     jsc.append(";");
148 
149     // -- set grouping compositor
150     if (xmlNature.isChoice()) {
151       jsc.add("");
152       jsc.add("//-- set grouping compositor");
153       jsc.add("setCompositorAsChoice();");
154     } else if (xmlNature.isSequence()) {
155       jsc.add("");
156       jsc.add("//-- set grouping compositor");
157       jsc.add("setCompositorAsSequence();");
158     }
159 
160     // handle substitution groups
161     List<String> substitutionGroups = xmlNature.getSubstitutionGroups();
162     if (!substitutionGroups.isEmpty()) {
163       jsc.add("java.util.List substitutionGroups = new java.util.ArrayList();");
164       Iterator<String> substitutionGroupIter = substitutionGroups.iterator();
165       while (substitutionGroupIter.hasNext()) {
166         String substitutionGroup = substitutionGroupIter.next();
167         jsc.add("substitutionGroups.add(\"");
168         jsc.append(substitutionGroup);
169         jsc.append("\");");
170       }
171       jsc.add("setSubstitutes(substitutionGroups);");
172     }
173 
174     // -- To prevent compiler warnings...make sure
175     // -- we don't declare temp variables if field count is 0;
176     if (classInfo.getFieldCount() == 0) {
177       return classDesc;
178     }
179 
180     // -- declare temp variables
181     jsc.add("org.exolab.castor.xml.util.XMLFieldDescriptorImpl  desc           = null;");
182     jsc.add("org.exolab.castor.mapping.FieldHandler             handler        = null;");
183     jsc.add("org.exolab.castor.xml.FieldValidator               fieldValidator = null;");
184 
185     // -- handle content
186     if (classInfo.allowContent()) {
187       createDescriptor(classDesc, classInfo.getTextField(), localClassName, null, jsc);
188     }
189 
190     ClassInfo base = classInfo.getBaseClass();
191     FieldInfo[] atts = classInfo.getAttributeFields();
192 
193     // --------------------------------/
194     // - Create attribute descriptors -/
195     // --------------------------------/
196 
197     jsc.add("//-- initialize attribute descriptors");
198     jsc.add("");
199 
200     for (FieldInfo member : atts) {
201       // -- skip transient members
202       if (member.isTransient()) {
203         continue;
204       }
205 
206       if (base != null) {
207         String baseNodeName = new XMLInfoNature(member).getNodeName();
208         if (baseNodeName.equals(XMLInfo.CHOICE_NODE_NAME_ERROR_INDICATION)) {
209           createDescriptor(classDesc, member, localClassName, nsURI, jsc);
210         } else {
211           if (base.getAttributeField(baseNodeName) != null) {
212             createRestrictedDescriptor(member, jsc);
213           } else {
214             createDescriptor(classDesc, member, localClassName, nsURI, jsc);
215           }
216         }
217       } else {
218         createDescriptor(classDesc, member, localClassName, nsURI, jsc);
219       }
220     }
221 
222     // ------------------------------/
223     // - Create element descriptors -/
224     // ------------------------------/
225     FieldInfo[] elements = classInfo.getElementFields();
226 
227     jsc.add("//-- initialize element descriptors");
228     jsc.add("");
229 
230     for (FieldInfo member : elements) {
231       XMLInfoNature fieldNature = new XMLInfoNature(member);
232 
233       // -- skip transient members
234       if (member.isTransient()) {
235         continue;
236       }
237 
238       if (base != null) {
239         String baseNodeName = fieldNature.getNodeName();
240         if (baseNodeName == null) {
241           createDescriptor(classDesc, member, localClassName, nsURI, jsc);
242         } else if (baseNodeName.equals(XMLInfo.CHOICE_NODE_NAME_ERROR_INDICATION)) {
243           createDescriptor(classDesc, member, localClassName, nsURI, jsc);
244         } else {
245           if (base.getElementField(baseNodeName) != null) {
246             createRestrictedDescriptor(member, jsc);
247           } else {
248             createDescriptor(classDesc, member, localClassName, nsURI, jsc);
249           }
250         }
251       } else {
252         createDescriptor(classDesc, member, localClassName, nsURI, jsc);
253       }
254     }
255 
256     return classDesc;
257   } // -- createSource
258 
259   // -------------------/
260   // - Private Methods -/
261   // -------------------/
262 
263   /**
264    * Returns the fully-qualified class name of the Descriptor to create. Given the fully-qualified
265    * class name of the class we are creating a Descriptor for, return the correct fully-qualified
266    * name for the Descriptor.
267    *
268    * @param name fully-qualified class name of the class we are describing
269    * @return the fully-qualified class name of the Descriptor to create
270    */
271   private String getQualifiedDescriptorClassName(final String name) {
272     String descPackage = JNaming.getPackageFromClassName(name);
273     String descClassName = JNaming.getLocalNameFromClassName(name);
274 
275     if (descPackage != null && descPackage.length() > 0) {
276       descPackage = descPackage + "." + XMLConstants.DESCRIPTOR_PACKAGE + ".";
277     } else {
278       descPackage = "";
279     }
280     return descPackage + descClassName + XMLConstants.DESCRIPTOR_SUFFIX;
281   }
282 
283   /**
284    * Create special code for handling a member that is a restriction, only changing the validation
285    * code.
286    * 
287    * This basically works by obtaining the {@link FieldDescriptor} instance from the base class, and
288    * setting a new {@link Validator} instance.
289    * 
290    * @param member the restricted member for which we generate the restriction handling.
291    * @param jsc the source code to which we append the validation code.
292    */
293   private static void createRestrictedDescriptor(final FieldInfo member, final JSourceCode jsc) {
294     jsc.add("desc = (org.exolab.castor.xml.util.XMLFieldDescriptorImpl) getFieldDescriptor(\"");
295     XMLInfoNature xmlNature = new XMLInfoNature(member);
296     jsc.append(xmlNature.getNodeName());
297     jsc.append("\"");
298     jsc.append(", _nsURI");
299     NodeType nodeType = xmlNature.getNodeType();
300     if (nodeType == NodeType.ELEMENT) {
301       jsc.append(", org.exolab.castor.xml.NodeType.Element);");
302     } else if (nodeType == NodeType.ATTRIBUTE) {
303       jsc.append(", org.exolab.castor.xml.NodeType.Attribute);");
304     } else {
305       jsc.append("org.exolab.castor.xml.NodeType.Text);");
306     }
307 
308     // -- deal with amended cardinality
309     if (xmlNature.isRequired()) {
310       jsc.add("desc.setRequired(true);");
311     }
312 
313     // --modify the validation code
314     addValidationCode(member, jsc);
315   }
316 
317   /**
318    * Creates a specific descriptor for a given member (whether an attribute or an element)
319    * represented by a given Class name.
320    *
321    * @param classDesc JClass-equivalent descriptor for this Descriptor class
322    * @param member the member for which to create a descriptor
323    * @param localClassName unqualified (no package) name of this class
324    * @param nsURI namespace URI
325    * @param jsc the source code to which we'll add this descriptor
326    */
327   private void createDescriptor(final DescriptorJClass classDesc, final FieldInfo member,
328       final String localClassName, final String nsURI, final JSourceCode jsc) {
329 
330     XMLInfoNature xmlNature = new XMLInfoNature(member);
331 
332     XSType xsType = xmlNature.getSchemaType();
333     XSType xsCollectionType = null;
334 
335     boolean any = false;
336     NodeType nodeType = xmlNature.getNodeType();
337     boolean isElement = (nodeType == NodeType.ELEMENT);
338     boolean isAttribute = (nodeType == NodeType.ATTRIBUTE);
339     boolean isText = (nodeType == NodeType.TEXT);
340 
341     jsc.add("//-- ");
342     jsc.append(member.getName());
343 
344     // -- a hack, I know, I will change later (kv)
345     if (member.getName().equals("_anyObject")) {
346       any = true;
347     }
348 
349     if (xsType.isCollection()) {
350       // Attributes can handle COLLECTION type for NMTOKENS or IDREFS for instance
351       xsCollectionType = xsType;
352       xsType = new XMLInfoNature(((CollectionInfo) member).getContent()).getSchemaType();
353     }
354 
355     // Resolve how the node name parameter to the XMLFieldDescriptorImpl constructor is supplied
356     String nodeName = xmlNature.getNodeName();
357     String nodeNameParam = null;
358     if ((nodeName != null) && (!isText)) {
359       // -- By default the node name parameter is a literal string
360       nodeNameParam = "\"" + nodeName + "\"";
361       if (_config.classDescFieldNames()) {
362         // -- The node name parameter is a reference to a public static final
363         nodeNameParam = nodeName.toUpperCase();
364         // -- Expose node name as public static final (reused by XMLFieldDescriptorImpl)
365         JConstant constant = new JConstant(SGTypes.STRING, nodeNameParam);
366         constant.setInitString("\"" + nodeName + "\"");
367         classDesc.addMember(constant);
368       }
369     }
370 
371     // -- Generate code to new XMLFieldDescriptorImpl instance
372     jsc.add("desc = new org.exolab.castor.xml.util.XMLFieldDescriptorImpl(");
373     jsc.append(classType(xsType.getJType()));
374     jsc.append(", \"");
375     jsc.append(member.getName());
376     jsc.append("\", ");
377     if (nodeNameParam != null) {
378       jsc.append(nodeNameParam);
379     } else if (isText) {
380       jsc.append("\"PCDATA\"");
381     } else {
382       jsc.append("(java.lang.String) null");
383     }
384 
385     if (isElement) {
386       jsc.append(", org.exolab.castor.xml.NodeType.Element);");
387     } else if (isAttribute) {
388       jsc.append(", org.exolab.castor.xml.NodeType.Attribute);");
389     } else if (isText) {
390       jsc.append(", org.exolab.castor.xml.NodeType.Text);");
391     }
392 
393     switch (xsType.getType()) {
394       case XSType.STRING_TYPE:
395         jsc.add("desc.setImmutable(true);");
396         break;
397       // only for attributes
398       case XSType.IDREF_TYPE:
399         jsc.add("desc.setReference(true);");
400         break;
401       case XSType.ID_TYPE:
402         jsc.add("this._identity = desc;");
403         break;
404       case XSType.QNAME_TYPE:
405         jsc.add("desc.setSchemaType(\"QName\");");
406         break;
407       default:
408         break;
409     } // switch
410 
411     // -- handler access methods
412     if (member.getXMLFieldHandler() != null) {
413       String handler = member.getXMLFieldHandler();
414       jsc.add("handler = new " + handler + "();");
415       jsc.add("//-- test for generalized field handler");
416       jsc.add("if (handler instanceof ");
417       jsc.append(GENERALIZED_FIELD_HANDLER_CLASS.getName());
418       jsc.append(")");
419       jsc.add("{");
420       jsc.indent();
421       jsc.add("//-- save reference to user-specified handler");
422       jsc.add(GENERALIZED_FIELD_HANDLER_CLASS.getName());
423       jsc.append(" gfh = (");
424       jsc.append(GENERALIZED_FIELD_HANDLER_CLASS.getName());
425       jsc.append(") handler;");
426       _xmlFieldHandlerFactory.createXMLFieldHandler(member, xsType, localClassName, jsc, true);
427       jsc.add("gfh.setFieldHandler(handler);");
428       jsc.add("handler = gfh;");
429       jsc.unindent();
430       jsc.add("}");
431     } else {
432       _xmlFieldHandlerFactory.createXMLFieldHandler(member, xsType, localClassName, jsc, false);
433       addSpecialHandlerLogic(member, xsType, jsc);
434     }
435 
436     // Add the schema type as defined in the schema
437     if (xsCollectionType == null) {
438       jsc.add("desc.setSchemaType(\"" + xsType.getName() + "\");");
439     } else {
440       jsc.add("desc.setSchemaType(\"list\");");
441       jsc.add("desc.setComponentType(\"" + xsType.getName() + "\");");
442       if (xsCollectionType instanceof XSList && ((XSList) xsCollectionType).isDerivedFromXSList()) {
443         jsc.add("desc.setDerivedFromXSList(true);");
444       }
445     }
446     jsc.add("desc.setHandler(handler);");
447 
448     // -- container
449     if (member.isContainer()) {
450       jsc.add("desc.setContainer(true);");
451       String className = xsType.getName(); // set the class descriptor
452       // Try to prevent endless loop. Note: we only compare the localClassName.
453       // If the packages are different an error can happen here
454       if (className.equals(localClassName)) {
455         jsc.add("desc.setClassDescriptor(this);");
456       } else {
457         String descriptorClassName = getQualifiedDescriptorClassName(className);
458         jsc.add("desc.setClassDescriptor(new " + descriptorClassName + "());");
459       }
460     }
461 
462     // -- Handle namespaces
463     // -- FieldInfo namespace has higher priority than ClassInfo namespace.
464     if (xmlNature.getNamespaceURI() != null) {
465       jsc.add("desc.setNameSpaceURI(\"");
466       jsc.append(xmlNature.getNamespaceURI());
467       jsc.append("\");");
468     }
469 
470     // -- required
471     if (xmlNature.isRequired()) {
472       jsc.add("desc.setRequired(true);");
473     }
474 
475     // -- nillable
476     if (member.isNillable()) {
477       jsc.add("desc.setNillable(true);");
478     }
479 
480     // -- if any it can match all the names
481     if (any) {
482       jsc.add("desc.setMatches(\"*\");");
483     }
484 
485     // -- mark as multi or single valued for elements
486     if (isElement || isAttribute) {
487       jsc.add("desc.setMultivalued(" + xmlNature.isMultivalued());
488       jsc.append(");");
489     }
490 
491     jsc.add("addFieldDescriptor(desc);");
492     if (isElement) {
493       jsc.add("addSequenceElement(desc);");
494     }
495     jsc.add("");
496 
497     if (isElement) {
498       // handle substitution groups
499       addSubstitutionGroups(member, jsc);
500     }
501 
502     // -- Add Validation Code
503     addValidationCode(member, jsc);
504   }
505 
506   /**
507    * Adds substitution groups to the {@link XMLFieldDescriptor} instance .
508    * 
509    * @param member The {@link FieldInfo} instance holding substitution group information
510    * @param jsc The {@link JSourceCode} instance to write the substitution groups to.
511    */
512   private void addSubstitutionGroups(final FieldInfo member, final JSourceCode jsc) {
513     List<String> substitutionGroupMembers = member.getSubstitutionGroupMembers();
514     if (!substitutionGroupMembers.isEmpty()) {
515       jsc.add("// set possible substitutes for member " + member.getName());
516       jsc.add(
517           "java.util.List substitutionGroups" + member.getName() + " = new java.util.ArrayList();");
518       Iterator<String> substitutionGroupIter = substitutionGroupMembers.iterator();
519       while (substitutionGroupIter.hasNext()) {
520         String substitutionGroup = substitutionGroupIter.next();
521         jsc.add("substitutionGroups" + member.getName() + ".add(\"");
522         jsc.append(substitutionGroup);
523         jsc.append("\");");
524       }
525       jsc.add("desc.setSubstitutes(substitutionGroups" + member.getName() + ");");
526     }
527   }
528 
529   /**
530    * Adds additional logic or wrappers around the core handler for special types such as dates,
531    * enumerated types, collections, etc.
532    *
533    * @param member the member for which extra special handler logic may be created
534    * @param xsType the field type for which extra special handler logic may be created
535    * @param jsc the java source code to which this will be written
536    */
537   private void addSpecialHandlerLogic(final FieldInfo member, final XSType xsType,
538       final JSourceCode jsc) {
539     XMLInfoNature xmlNature = new XMLInfoNature(member);
540 
541     if (xsType.isEnumerated()) {
542       jsc.add("handler = new org.exolab.castor.xml.handlers.EnumFieldHandler(");
543       jsc.append(classType(xsType.getJType()));
544       jsc.append(", handler);");
545       jsc.add("desc.setImmutable(true);");
546     } else if (xsType.getType() == XSType.DATETIME_TYPE) {
547       jsc.add("handler = new org.exolab.castor.xml.handlers.DateFieldHandler(");
548       jsc.append("handler);");
549       jsc.add("desc.setImmutable(true);");
550     } else if (xsType.getType() == XSType.DECIMAL_TYPE) {
551       jsc.add("desc.setImmutable(true);");
552     } else if (xmlNature.getSchemaType().isCollection()) {
553       // -- Handle special Collection Types such as NMTOKENS and IDREFS
554       switch (xsType.getType()) {
555         case XSType.NMTOKEN_TYPE:
556         case XSType.NMTOKENS_TYPE:
557           // -- use CollectionFieldHandler
558           jsc.add("handler = new org.exolab.castor.xml.handlers.CollectionFieldHandler(");
559           jsc.append("handler, new org.exolab.castor.xml.validators.NameValidator(");
560           jsc.append("org.exolab.castor.xml.XMLConstants.NAME_TYPE_NMTOKEN));");
561           break;
562         case XSType.QNAME_TYPE:
563           // -- use CollectionFieldHandler
564           jsc.add("handler = new org.exolab.castor.xml.handlers.CollectionFieldHandler(");
565           jsc.append("handler, null);");
566           break;
567         case XSType.IDREF_TYPE:
568         case XSType.IDREFS_TYPE:
569           // -- uses special code in UnmarshalHandler
570           // -- see UnmarshalHandler#processIDREF
571           jsc.add("desc.setMultivalued(");
572           jsc.append("" + xmlNature.isMultivalued());
573           jsc.append(");");
574           break;
575         default:
576           break;
577       }
578     }
579   } // -- addSpecialHandlerLogic
580 
581   /**
582    * Creates the validation code for a given member. This code will be appended to the given
583    * JSourceCode.
584    *
585    * @param member the member for which to create the validation code.
586    * @param jsc the JSourceCode to fill in.
587    */
588   private static void addValidationCode(final FieldInfo member, final JSourceCode jsc) {
589     if (member == null || jsc == null) {
590       return;
591     }
592 
593     jsc.add("//-- validation code for: ");
594     jsc.append(member.getName());
595     String validator = member.getValidator();
596     if (validator != null && validator.length() > 0) {
597       jsc.add("fieldValidator = new " + validator + "();");
598     } else {
599       jsc.add("fieldValidator = new org.exolab.castor.xml.FieldValidator();");
600 
601       // -- a hack, I know, I will change later
602       if (member.getName().equals("_anyObject")) {
603         jsc.add("desc.setValidator(fieldValidator);");
604         return;
605       }
606 
607       XMLInfoNature xmlNature = new XMLInfoNature(member);
608       XSType xsType = xmlNature.getSchemaType();
609       // --handle collections
610       if (xsType.isCollection()) {
611         XSListType xsList = (XSListType) xsType;
612 
613         jsc.add("fieldValidator.setMinOccurs(");
614         jsc.append(Integer.toString(xsList.getMinimumSize()));
615         jsc.append(");");
616         if (xsList.getMaximumSize() > 0) {
617           jsc.add("fieldValidator.setMaxOccurs(");
618           jsc.append(Integer.toString(xsList.getMaximumSize()));
619           jsc.append(");");
620         }
621       } else if (xmlNature.isRequired()) {
622         jsc.add("fieldValidator.setMinOccurs(1);");
623       }
624 
625       jsc.add("{ //-- local scope");
626       jsc.indent();
627       xsType.validationCode(jsc, member.getFixedValue(), FIELD_VALIDATOR_NAME);
628       jsc.unindent();
629       jsc.add("}");
630     }
631     jsc.add("desc.setValidator(fieldValidator);");
632   }
633 
634   /**
635    * Returns the Class type (as a String) for the given XSType.
636    * 
637    * @param jType the JType whose Class type will be returned
638    * @return the Class type (as a String) for the given XSType.
639    */
640   private static String classType(final JType jType) {
641     if (jType.isPrimitive()) {
642       JPrimitiveType primitive = (JPrimitiveType) jType;
643       return primitive.getWrapperName() + ".TYPE";
644     }
645     return jType.toString() + ".class";
646   } // -- classType
647 
648 } // -- DescriptorSourceFactory