View Javadoc
1   /* ==========================================================================
2    * Copyright 2005 Mevenide Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   * =========================================================================
16   */
17  package org.codehaus.modello.plugin.jdom;
18  
19  import javax.inject.Named;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Properties;
25  
26  import org.codehaus.modello.ModelloException;
27  import org.codehaus.modello.model.Model;
28  import org.codehaus.modello.model.ModelAssociation;
29  import org.codehaus.modello.model.ModelClass;
30  import org.codehaus.modello.model.ModelDefault;
31  import org.codehaus.modello.model.ModelField;
32  import org.codehaus.modello.plugin.java.javasource.JClass;
33  import org.codehaus.modello.plugin.java.javasource.JConstructor;
34  import org.codehaus.modello.plugin.java.javasource.JField;
35  import org.codehaus.modello.plugin.java.javasource.JMethod;
36  import org.codehaus.modello.plugin.java.javasource.JParameter;
37  import org.codehaus.modello.plugin.java.javasource.JSourceCode;
38  import org.codehaus.modello.plugin.java.javasource.JSourceWriter;
39  import org.codehaus.modello.plugin.java.javasource.JType;
40  import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata;
41  import org.codehaus.modello.plugin.model.ModelClassMetadata;
42  import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
43  import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
44  import org.codehaus.modello.plugins.xml.metadata.XmlModelMetadata;
45  
46  /**
47   * @author mkleint@codehaus.org
48   */
49  @Named("jdom-writer")
50  public class JDOMWriterGenerator extends AbstractJDOMGenerator {
51  
52      private boolean requiresDomSupport;
53  
54      public void generate(Model model, Properties parameters) throws ModelloException {
55          initialize(model, parameters);
56  
57          requiresDomSupport = false;
58  
59          try {
60              generateJDOMWriter();
61          } catch (IOException ex) {
62              throw new ModelloException("Exception while generating JDOM Writer.", ex);
63          }
64      }
65  
66      private void generateJDOMWriter() throws ModelloException, IOException {
67          Model objectModel = getModel();
68  
69          String packageName =
70                  objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.jdom";
71  
72          String marshallerName = getFileName("JDOMWriter");
73  
74          JClass jClass = new JClass(packageName + '.' + marshallerName);
75          initHeader(jClass);
76          suppressAllWarnings(objectModel, jClass);
77  
78          // -------------------------------------------------------------
79          // imports now
80          // -------------------------------------------------------------
81          jClass.addImport("java.io.OutputStream");
82          jClass.addImport("java.io.OutputStreamWriter");
83          jClass.addImport("java.io.Writer");
84          jClass.addImport("java.text.DateFormat");
85          jClass.addImport("java.util.ArrayList");
86          jClass.addImport("java.util.Arrays");
87          jClass.addImport("java.util.Collection");
88          jClass.addImport("java.util.Iterator");
89          jClass.addImport("java.util.List");
90          jClass.addImport("java.util.ListIterator");
91          jClass.addImport("java.util.Locale");
92          jClass.addImport("java.util.Map");
93          jClass.addImport("java.util.Properties");
94          jClass.addImport("org.jdom2.Content");
95          jClass.addImport("org.jdom2.DefaultJDOMFactory");
96          jClass.addImport("org.jdom2.Document");
97          jClass.addImport("org.jdom2.Element");
98          jClass.addImport("org.jdom2.JDOMFactory");
99          jClass.addImport("org.jdom2.Namespace");
100         jClass.addImport("org.jdom2.Parent");
101         jClass.addImport("org.jdom2.Text");
102         jClass.addImport("org.jdom2.output.Format");
103         jClass.addImport("org.jdom2.output.XMLOutputter");
104 
105         addModelImports(jClass, null);
106 
107         JField factoryField = new JField(new JClass("JDOMFactory"), "factory");
108         factoryField.getModifiers().setFinal(true);
109         jClass.addField(factoryField);
110 
111         JField lineSeparatorField = new JField(new JClass("String"), "lineSeparator");
112         lineSeparatorField.getModifiers().setFinal(true);
113         jClass.addField(lineSeparatorField);
114 
115         createCounter(jClass);
116 
117         // constructor --
118         JConstructor constructor = jClass.createConstructor();
119         JSourceCode constCode = constructor.getSourceCode();
120         constCode.add("this( new DefaultJDOMFactory() );");
121 
122         constructor = jClass.createConstructor();
123         constructor.addParameter(new JParameter(new JClass("JDOMFactory"), "factory"));
124         constCode = constructor.getSourceCode();
125         constCode.add("this.factory = factory;");
126         constCode.add("this.lineSeparator = \"\\n\";");
127 
128         String root = objectModel.getRoot(getGeneratedVersion());
129 
130         ModelClass rootClass = objectModel.getClass(root, getGeneratedVersion());
131 
132         String rootElement = resolveTagName(rootClass);
133 
134         // the public global write method..
135         jClass.addMethod(generateWriteModel2(root, rootElement));
136         jClass.addMethod(generateWriteModel3(root, rootElement));
137         // the private utility classes;
138         jClass.addMethods(generateUtilityMethods());
139 
140         writeAllClasses(objectModel, jClass, rootClass);
141 
142         if (requiresDomSupport) {
143             jClass.addImport("org.codehaus.plexus.util.xml.Xpp3Dom");
144             jClass.addMethods(generateDomMethods());
145         }
146 
147         try (JSourceWriter sourceWriter = newJSourceWriter(packageName, marshallerName)) {
148             jClass.print(sourceWriter);
149         }
150     }
151 
152     private void createCounter(final JClass jClass) throws IllegalArgumentException {
153         // inner counter class
154         JClass counter = jClass.createInnerClass("Counter");
155         counter.getModifiers().setStatic(true);
156 
157         JField fld = new JField(new JType("int"), "currentIndex");
158         fld.setInitString("0");
159         counter.addField(fld);
160 
161         fld = new JField(new JType("int"), "level");
162         counter.addField(fld);
163 
164         JConstructor constr =
165                 counter.createConstructor(new JParameter[] {new JParameter(new JType("int"), "depthLevel")});
166         constr.getSourceCode().append("level = depthLevel;");
167 
168         JMethod inc = new JMethod("increaseCount");
169         inc.getSourceCode().add("currentIndex = currentIndex + 1;");
170         counter.addMethod(inc);
171 
172         JMethod getter = new JMethod("getCurrentIndex", new JType("int"), null);
173         getter.getSourceCode().add("return currentIndex;");
174         counter.addMethod(getter);
175 
176         getter = new JMethod("getDepth", new JType("int"), null);
177         getter.getSourceCode().add("return level;");
178         counter.addMethod(getter);
179     }
180 
181     private JMethod generateWriteModel2(String root, String rootElement) {
182         String variableName = uncapitalise(root);
183 
184         JMethod marshall = new JMethod("write");
185 
186         marshall.addParameter(new JParameter(new JClass(root), variableName));
187         marshall.addParameter(new JParameter(new JClass("OutputStreamWriter"), "writer"));
188         marshall.addException(new JClass("java.io.IOException"));
189 
190         JSourceCode sc = marshall.getSourceCode();
191         sc.add("Format format = Format.getRawFormat()");
192         sc.add("    .setEncoding( writer.getEncoding() )");
193         sc.add("    .setLineSeparator( System.getProperty( \"line.separator\" ) );");
194         sc.add("write( " + variableName + ", writer, format );");
195         return marshall;
196     }
197 
198     private JMethod generateWriteModel3(String root, String rootElement) {
199         String variableName = uncapitalise(root);
200 
201         JMethod marshall = new JMethod("write");
202 
203         marshall.addParameter(new JParameter(new JClass(root), variableName));
204         marshall.addParameter(new JParameter(new JClass("Writer"), "writer"));
205         marshall.addParameter(new JParameter(new JClass("Format"), "jdomFormat"));
206         marshall.addException(new JClass("java.io.IOException"));
207 
208         JSourceCode sc = marshall.getSourceCode();
209         sc.add("Document document = factory.document( null );");
210         sc.add("update" + root + "( " + variableName + ", \"" + rootElement + "\", new Counter( 0 ), document );");
211         sc.add("XMLOutputter outputter = new XMLOutputter();");
212         sc.add("outputter.setFormat( jdomFormat );");
213         sc.add("outputter.output( document, writer );");
214 
215         return marshall;
216     }
217 
218     private JMethod[] generateUtilityMethods() {
219         JMethod findRSElement = new JMethod("findAndReplaceSimpleElement", new JClass("Element"), null);
220         findRSElement.addParameter(new JParameter(new JClass("Counter"), "counter"));
221         findRSElement.addParameter(new JParameter(new JClass("Element"), "parent"));
222         findRSElement.addParameter(new JParameter(new JClass("String"), "name"));
223         findRSElement.addParameter(new JParameter(new JClass("String"), "text"));
224         findRSElement.addParameter(new JParameter(new JClass("String"), "defaultValue"));
225 
226         findRSElement.getModifiers().makeProtected();
227         JSourceCode sc = findRSElement.getSourceCode();
228         sc.add("if ( ( defaultValue != null ) && ( text != null ) && defaultValue.equals( text ) )");
229         sc.add("{");
230         sc.indent();
231         sc.add("Element element =  parent.getChild( name, parent.getNamespace() );");
232         sc.add("// if exist and is default value or if doesn't exist.. just keep the way it is..");
233         sc.add("if ( ( element != null && defaultValue.equals( element.getText() ) ) || element == null )");
234         sc.add("{");
235         sc.addIndented("return element;");
236         sc.add("}");
237         sc.unindent();
238         sc.add("}");
239 
240         sc.add("boolean shouldExist = ( text != null ) && ( text.trim().length() > 0 );");
241         sc.add("Element element = updateElement( counter, parent, name );");
242         sc.add("if ( shouldExist )");
243         sc.add("{");
244         sc.addIndented("element.setText( text );");
245         sc.add("}");
246         sc.add("return element;");
247 
248         JMethod updateElement = new JMethod("updateElement", new JClass("Element"), null);
249         updateElement.addParameter(new JParameter(new JClass("Counter"), "counter"));
250         updateElement.addParameter(new JParameter(new JClass("Element"), "parent"));
251         updateElement.addParameter(new JParameter(new JClass("String"), "name"));
252         updateElement.getModifiers().makeProtected();
253         sc = updateElement.getSourceCode();
254         sc.add("Element element = factory.element( name, parent.getNamespace() );");
255         sc.add("insertAtPreferredLocation( parent, element, counter );");
256         sc.add("counter.increaseCount();");
257         sc.add("return element;");
258 
259         JMethod insAtPref = new JMethod("insertAtPreferredLocation");
260         insAtPref.addParameter(new JParameter(new JClass("Element"), "parent"));
261         insAtPref.addParameter(new JParameter(new JClass("Element"), "child"));
262         insAtPref.addParameter(new JParameter(new JClass("Counter"), "counter"));
263         insAtPref.getModifiers().makeProtected();
264         sc = insAtPref.getSourceCode();
265         sc.add("int contentIndex = 0;");
266         sc.add("int elementCounter = 0;");
267         sc.add("Iterator it = parent.getContent().iterator();");
268         sc.add("Text lastText = null;");
269         sc.add("int offset = 0;");
270         sc.add("while ( it.hasNext() && elementCounter <= counter.getCurrentIndex() )");
271         sc.add("{");
272         sc.indent();
273         sc.add("Object next = it.next();");
274         sc.add("offset = offset + 1;");
275         sc.add("if ( next instanceof Element )");
276         sc.add("{");
277         sc.indent();
278         sc.add("elementCounter = elementCounter + 1;");
279         sc.add("contentIndex = contentIndex + offset;");
280         sc.add("offset = 0;");
281         sc.unindent();
282         sc.add("}");
283         sc.add("if ( next instanceof Text && it.hasNext() )");
284         sc.add("{");
285         sc.addIndented("lastText = (Text) next;");
286         sc.add("}");
287         sc.unindent();
288         sc.add("}");
289         sc.add("if ( lastText != null && lastText.getTextTrim().length() == 0 )");
290         sc.add("{");
291         sc.addIndented("lastText = (Text) lastText.clone();");
292         sc.add("}");
293         sc.add("else");
294         sc.add("{");
295         sc.indent();
296         sc.add("String starter = lineSeparator;");
297         sc.add("for ( int i = 0; i < counter.getDepth(); i++ )");
298         sc.add("{");
299         sc.addIndented("starter = starter + \"    \"; //TODO make settable?");
300         sc.add("}");
301         sc.add("lastText = factory.text( starter );");
302         sc.unindent();
303         sc.add("}");
304         sc.add("if ( parent.getContentSize() == 0 )");
305         sc.add("{");
306         sc.indent();
307         sc.add("Text finalText = (Text) lastText.clone();");
308         sc.add(
309                 "finalText.setText( finalText.getText().substring( 0, finalText.getText().length() - \"    \".length() ) );");
310         sc.add("parent.addContent( contentIndex, finalText );");
311         sc.unindent();
312         sc.add("}");
313         sc.add("parent.addContent( contentIndex, child );");
314         sc.add("parent.addContent( contentIndex, lastText );");
315 
316         JMethod findRSLists = new JMethod("findAndReplaceSimpleLists", new JClass("Element"), null);
317         findRSLists.addParameter(new JParameter(new JClass("Counter"), "counter"));
318         findRSLists.addParameter(new JParameter(new JClass("Element"), "parent"));
319         findRSLists.addParameter(new JParameter(new JClass("java.util.Collection"), "list"));
320         findRSLists.addParameter(new JParameter(new JClass("String"), "parentName"));
321         findRSLists.addParameter(new JParameter(new JClass("String"), "childName"));
322         findRSLists.getModifiers().makeProtected();
323         sc = findRSLists.getSourceCode();
324         sc.add("boolean shouldExist = ( list != null ) && ( list.size() > 0 );");
325         sc.add("Element element = updateElement( counter, parent, parentName );");
326         sc.add("if ( shouldExist )");
327         sc.add("{");
328         sc.indent();
329         sc.add("Iterator it = list.iterator();");
330         sc.add("Counter innerCount = new Counter( counter.getDepth() + 1 );");
331         sc.add("while ( it.hasNext() )");
332         sc.add("{");
333         sc.indent();
334         sc.add("String value = (String) it.next();");
335         sc.add("Element el = factory.element( childName, element.getNamespace() );");
336         sc.add("insertAtPreferredLocation( element, el, innerCount );");
337         sc.add("el.setText( value );");
338         sc.add("innerCount.increaseCount();");
339         sc.unindent();
340         sc.add("}");
341         sc.add("}");
342         sc.add("return element;");
343 
344         return new JMethod[] {findRSElement, updateElement, insAtPref, findRSLists};
345     }
346 
347     private JMethod[] generateDomMethods() {
348         JMethod findRSDom = new JMethod("findAndReplaceXpp3DOM", new JClass("Element"), null);
349         findRSDom.addParameter(new JParameter(new JClass("Counter"), "counter"));
350         findRSDom.addParameter(new JParameter(new JClass("Element"), "parent"));
351         findRSDom.addParameter(new JParameter(new JClass("String"), "name"));
352         findRSDom.addParameter(new JParameter(new JClass("Xpp3Dom"), "dom"));
353         findRSDom.getModifiers().makeProtected();
354         JSourceCode sc = findRSDom.getSourceCode();
355         sc.add("boolean shouldExist = ( dom != null ) && ( dom.getChildCount() > 0 || dom.getValue() != null );");
356         sc.add("Element element = updateElement( counter, parent, name );");
357         sc.add("if ( shouldExist )");
358         sc.add("{");
359         sc.addIndented("replaceXpp3DOM( element, dom, new Counter( counter.getDepth() + 1 ) );");
360         sc.add("}");
361         sc.add("return element;");
362 
363         JMethod findRSDom2 = new JMethod("replaceXpp3DOM");
364         findRSDom2.addParameter(new JParameter(new JClass("Element"), "parent"));
365         findRSDom2.addParameter(new JParameter(new JClass("Xpp3Dom"), "parentDom"));
366         findRSDom2.addParameter(new JParameter(new JClass("Counter"), "counter"));
367         findRSDom2.getModifiers().makeProtected();
368         sc = findRSDom2.getSourceCode();
369 
370         if (hasJavaSourceSupport(5)) {
371             sc.add("for( String attributeName : parentDom.getAttributeNames() )");
372             sc.add("{");
373             sc.indent();
374         } else {
375             sc.add("for ( Iterator i = Arrays.asList( parentDom.getAttributeNames() ).iterator(); i.hasNext(); )");
376             sc.add("{");
377             sc.indent();
378 
379             sc.add("String attributeName = (String) i.next();");
380         }
381         sc.add("String[] attrDetails = attributeName.split( \":\", 2 );");
382         sc.add("if ( attrDetails.length == 2 )");
383         sc.add("{");
384         sc.addIndented(
385                 "parent.setAttribute( attrDetails[1], parentDom.getAttribute( attributeName ), parent.getNamespace( attrDetails[0] ) );");
386         sc.add("}");
387         sc.add("else ");
388         sc.add("{");
389         sc.addIndented("parent.setAttribute( attributeName, parentDom.getAttribute( attributeName ) );");
390         sc.add("}");
391         sc.unindent();
392         sc.add("}");
393         sc.add("if ( parentDom.getChildCount() > 0 )");
394         sc.add("{");
395         sc.indent();
396         sc.add("Xpp3Dom[] childs = parentDom.getChildren();");
397         sc.add("Collection domChilds = new ArrayList();");
398         sc.add("for ( int i = 0; i < childs.length; i++ )");
399         sc.add("{");
400         sc.addIndented("domChilds.add( childs[i] );");
401         sc.add("}");
402         sc.add("ListIterator it = parent.getChildren().listIterator();");
403         sc.add("while ( it.hasNext() )");
404         sc.add("{");
405         sc.indent();
406         sc.add("Element elem = (Element) it.next();");
407         sc.add("Iterator it2 = domChilds.iterator();");
408         sc.add("Xpp3Dom corrDom = null;");
409         sc.add("while ( it2.hasNext() )");
410         sc.add("{");
411         sc.indent();
412         sc.add("Xpp3Dom dm = (Xpp3Dom) it2.next();");
413         sc.add("if ( dm.getName().equals( elem.getName() ) )");
414         sc.add("{");
415         sc.indent();
416         sc.add("corrDom = dm;");
417         sc.add("break;");
418         sc.unindent();
419         sc.add("}");
420         sc.unindent();
421         sc.add("}");
422         sc.add("if ( corrDom != null )");
423         sc.add("{");
424         sc.indent();
425         sc.add("domChilds.remove( corrDom );");
426         sc.add("replaceXpp3DOM( elem, corrDom, new Counter( counter.getDepth() + 1 ) );");
427         sc.add("counter.increaseCount();");
428         sc.unindent();
429         sc.add("}");
430         sc.add("else");
431         sc.add("{");
432         sc.addIndented("it.remove();");
433         sc.add("}");
434         sc.unindent();
435         sc.add("}");
436         sc.add("Iterator it2 = domChilds.iterator();");
437         sc.add("while ( it2.hasNext() )");
438         sc.add("{");
439         sc.indent();
440         sc.add("Xpp3Dom dm = (Xpp3Dom) it2.next();");
441         sc.add("Element elem = factory.element( dm.getName(), parent.getNamespace() );");
442         sc.add("insertAtPreferredLocation( parent, elem, counter );");
443         sc.add("counter.increaseCount();");
444         sc.add("replaceXpp3DOM( elem, dm, new Counter( counter.getDepth() + 1 ) );");
445         sc.unindent();
446         sc.add("}");
447         sc.unindent();
448         sc.add("}");
449         sc.add(" else if ( parentDom.getValue() != null )");
450         sc.add("{");
451         sc.addIndented("parent.setText( parentDom.getValue() );");
452         sc.add("}");
453 
454         return new JMethod[] {findRSDom, findRSDom2};
455     }
456 
457     private void writeAllClasses(Model objectModel, JClass jClass, ModelClass rootClass) throws ModelloException {
458         List<ModelClass> alwaysExistingElements = new ArrayList<ModelClass>();
459         alwaysExistingElements.add(rootClass);
460 
461         for (ModelClass clazz : getClasses(objectModel)) {
462             updateClass(clazz, jClass, alwaysExistingElements);
463         }
464     }
465 
466     private void updateClass(ModelClass clazz, JClass jClass, List<ModelClass> alwaysExisting) throws ModelloException {
467         String className = clazz.getName();
468 
469         String capClassName = capitalise(className);
470 
471         String uncapClassName = uncapitalise(className);
472 
473         ModelClassMetadata classMetadata = (ModelClassMetadata) clazz.getMetadata(ModelClassMetadata.ID);
474 
475         JMethod marshall = new JMethod("update" + capClassName);
476         marshall.addParameter(new JParameter(new JClass(className), uncapClassName));
477         marshall.addParameter(new JParameter(new JClass("String"), "xmlTag"));
478         marshall.addParameter(new JParameter(new JClass("Counter"), "counter"));
479         if (classMetadata.isRootElement()) {
480             marshall.addParameter(new JParameter(new JClass("Document"), "document"));
481         } else {
482             marshall.addParameter(new JParameter(new JClass("Element"), "element"));
483         }
484         marshall.getModifiers().makeProtected();
485 
486         JSourceCode sc = marshall.getSourceCode();
487         sc.add("if ( " + uncapClassName + " != null )");
488         sc.add("{");
489         sc.indent();
490 
491         if (classMetadata.isRootElement()) {
492             XmlModelMetadata xmlModelMetadata =
493                     (XmlModelMetadata) clazz.getModel().getMetadata(XmlModelMetadata.ID);
494             String namespace = xmlModelMetadata.getNamespace(getGeneratedVersion());
495 
496             if (namespace != null) {
497                 sc.add("Element root = factory.element( xmlTag, \"" + namespace + "\" );");
498                 if (xmlModelMetadata.getSchemaLocation() != null) {
499                     String url = xmlModelMetadata.getSchemaLocation(getGeneratedVersion());
500                     sc.add(
501                             "Namespace xsins = Namespace.getNamespace( \"xsi\", \"http://www.w3.org/2001/XMLSchema-instance\" );");
502                     sc.add("root.setAttribute( \"schemaLocation\", \"" + namespace + " " + url + "\", xsins );");
503                 }
504             } else {
505                 sc.add("Element root = factory.element( xmlTag );");
506             }
507             sc.add("document.setRootElement( root );");
508         } else {
509             sc.add("Element root = updateElement( counter, element, xmlTag );");
510         }
511 
512         sc.add("Counter innerCount = new Counter( counter.getDepth() + 1 );");
513 
514         ModelField contentField = null;
515 
516         String contentValue = null;
517 
518         List<ModelField> modelFields = getFieldsForXml(clazz, getGeneratedVersion());
519 
520         for (ModelField field : modelFields) {
521             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
522             JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
523 
524             String fieldTagName = resolveTagName(field, xmlFieldMetadata);
525 
526             String type = field.getType();
527             String value = uncapClassName + '.' + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
528 
529             if (xmlFieldMetadata.isContent()) {
530                 contentField = field;
531                 contentValue = value;
532                 continue;
533             }
534 
535             if (xmlFieldMetadata.isAttribute()) {
536                 sc.add(getValueChecker(type, value, field));
537                 sc.add("{");
538                 sc.addIndented("root.setAttribute( \"" + fieldTagName + "\", "
539                         + getValue(field.getType(), value, xmlFieldMetadata) + " );");
540                 sc.add("}");
541                 continue;
542             }
543             if (field instanceof ModelAssociation) {
544                 ModelAssociation association = (ModelAssociation) field;
545 
546                 ModelClass toClass = association.getToClass();
547                 if (association.isOneMultiplicity()) {
548                     sc.add(getValueChecker(type, value, field));
549                     sc.add("{");
550                     sc.addIndented("update" + capitalise(field.getType()) + "( " + value + ", \"" + fieldTagName
551                             + "\", innerCount, root );");
552                     sc.add("}");
553                 } else {
554                     // MANY_MULTIPLICITY
555 
556                     XmlAssociationMetadata xmlAssociationMetadata =
557                             (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
558 
559                     String valuesTagName = resolveTagName(fieldTagName, xmlAssociationMetadata);
560                     //
561                     //                    type = association.getType();
562                     //                    String toType = association.getTo();
563                     //
564                     if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
565                         //                        type = association.getType();
566                         String toType = association.getTo();
567                         if (toClass != null) {
568                             if (xmlAssociationMetadata.isWrappedItems()) {
569                                 sc.add("iterate" + capitalise(toType) + "( innerCount, root, " + value + ",\""
570                                         + fieldTagName + "\",\"" + valuesTagName + "\" );");
571                                 createIterateMethod(field.getName(), toClass, singular(fieldTagName), jClass);
572                             } else {
573                                 // assume flat..
574                                 sc.add("iterate2" + capitalise(toType) + "( innerCount, root, " + value + ", \""
575                                         + valuesTagName + "\" );");
576                                 createIterateMethod2(field.getName(), toClass, singular(fieldTagName), jClass);
577                             }
578                         } else {
579                             // list of strings?
580                             sc.add("findAndReplaceSimpleLists( innerCount, root, " + value + ", \"" + fieldTagName
581                                     + "\", \"" + singular(fieldTagName) + "\" );");
582                         }
583                     } else {
584                         // Map or Properties
585                         sc.add(getValueChecker(type, value, field));
586                         sc.add("{");
587                         sc.indent();
588                         sc.add("Element listElement = updateElement( innerCount, root, \"" + fieldTagName + "\" );");
589                         sc.add("Iterator it = " + value + ".keySet().iterator();");
590                         sc.add("Counter propertiesCounter = new Counter( innerCount.getDepth() + 1 );");
591                         sc.add("while ( it.hasNext() )");
592                         sc.add("{");
593                         sc.indent();
594                         sc.add("String key = (String) it.next();");
595                         if (xmlAssociationMetadata.isMapExplode()) {
596                             sc.add("Element propTag = updateElement( propertiesCounter, listElement, \""
597                                     + singular(fieldTagName) + "\" );");
598                             sc.add("Counter propertyCounter = new Counter( propertiesCounter.getDepth() + 1 );");
599                             sc.add("findAndReplaceSimpleElement( propertyCounter, propTag, \"key\", key, null );");
600                             sc.add("findAndReplaceSimpleElement( propertyCounter, propTag, \"value\", (String) " + value
601                                     + ".get( key ), null );");
602                         } else {
603                             sc.add("findAndReplaceSimpleElement( propertiesCounter, listElement, key, (String) " + value
604                                     + ".get( key ), null );");
605                         }
606                         sc.unindent();
607                         sc.add("}");
608                         sc.unindent();
609                         sc.add("}");
610                     }
611                 }
612             } else {
613                 if ("DOM".equals(field.getType())) {
614                     sc.add("findAndReplaceXpp3DOM( innerCount, root, \"" + fieldTagName + "\", (Xpp3Dom) " + value
615                             + " );");
616 
617                     requiresDomSupport = true;
618                 } else {
619                     sc.add(getValueChecker(type, value, field));
620                     sc.add("{");
621                     sc.addIndented("updateElement( innerCount, root,  \"" + fieldTagName + "\" ).setText( "
622                             + getValue(field.getType(), value, xmlFieldMetadata) + " );");
623                     sc.add("}");
624                 }
625             }
626         }
627 
628         if (contentField != null) {
629             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) contentField.getMetadata(XmlFieldMetadata.ID);
630             sc.add("root.setText( " + getValue(contentField.getType(), contentValue, xmlFieldMetadata) + " );");
631         }
632 
633         sc.unindent();
634         sc.add("}");
635 
636         jClass.addMethod(marshall);
637     }
638 
639     private void createIterateMethod(String field, ModelClass toClass, String childFieldTagName, JClass jClass) {
640         if (jClass.getMethod("iterate" + capitalise(toClass.getName()), 0) != null) {
641             return;
642         }
643         JMethod toReturn = new JMethod("iterate" + capitalise(toClass.getName()));
644         toReturn.addParameter(new JParameter(new JClass("Counter"), "counter"));
645         toReturn.addParameter(new JParameter(new JClass("Element"), "parent"));
646         toReturn.addParameter(new JParameter(new JClass("java.util.Collection"), "list"));
647         toReturn.addParameter(new JParameter(new JClass("java.lang.String"), "parentTag"));
648         toReturn.addParameter(new JParameter(new JClass("java.lang.String"), "childTag"));
649         toReturn.getModifiers().makeProtected();
650         JSourceCode sc = toReturn.getSourceCode();
651         sc.add("boolean shouldExist = ( list != null ) && ( list.size() > 0 );");
652         sc.add("Element element = updateElement( counter, parent, parentTag );");
653         sc.add("if ( shouldExist )");
654         sc.add("{");
655         sc.indent();
656         sc.add("Iterator it = list.iterator();");
657         sc.add("Counter innerCount = new Counter( counter.getDepth() + 1 );");
658         sc.add("while ( it.hasNext() )");
659         sc.add("{");
660         sc.indent();
661         sc.add(toClass.getName() + " value = (" + toClass.getName() + ") it.next();");
662         sc.add("update" + toClass.getName() + "( value, childTag, innerCount, element );");
663         sc.add("innerCount.increaseCount();");
664         sc.unindent();
665         sc.add("}");
666         sc.unindent();
667         sc.add("}");
668 
669         jClass.addMethod(toReturn);
670     }
671 
672     private void createIterateMethod2(String field, ModelClass toClass, String childFieldTagName, JClass jClass) {
673         if (jClass.getMethod("iterate2" + capitalise(toClass.getName()), 0) != null) {
674             return;
675         }
676         JMethod toReturn = new JMethod("iterate2" + capitalise(toClass.getName()));
677         toReturn.addParameter(new JParameter(new JClass("Counter"), "counter"));
678         toReturn.addParameter(new JParameter(new JClass("Element"), "parent"));
679         toReturn.addParameter(new JParameter(new JClass("java.util.Collection"), "list"));
680         toReturn.addParameter(new JParameter(new JClass("java.lang.String"), "childTag"));
681         toReturn.getModifiers().makeProtected();
682         JSourceCode sc = toReturn.getSourceCode();
683         sc.add("Iterator it = list.iterator();");
684         sc.add("while ( it.hasNext() )");
685         sc.add("{");
686         sc.indent();
687         sc.add(toClass.getName() + " value = (" + toClass.getName() + ") it.next();");
688         sc.add("update" + toClass.getName() + "( value, childTag, counter, parent );");
689         sc.unindent();
690         sc.add("}");
691 
692         jClass.addMethod(toReturn);
693     }
694 }