/* ========================================================================== * Copyright 2005 Mevenide Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ========================================================================= */ package org.codehaus.modello.plugin.jdom; import org.codehaus.modello.ModelloException; import org.codehaus.modello.model.Model; import org.codehaus.modello.model.ModelAssociation; import org.codehaus.modello.model.ModelClass; import org.codehaus.modello.model.ModelDefault; import org.codehaus.modello.model.ModelField; import org.codehaus.modello.plugin.java.javasource.JClass; import org.codehaus.modello.plugin.java.javasource.JConstructor; import org.codehaus.modello.plugin.java.javasource.JField; import org.codehaus.modello.plugin.java.javasource.JMethod; import org.codehaus.modello.plugin.java.javasource.JParameter; import org.codehaus.modello.plugin.java.javasource.JSourceCode; import org.codehaus.modello.plugin.java.javasource.JSourceWriter; import org.codehaus.modello.plugin.java.javasource.JType; import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata; import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata; import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * @author mkleint@codehaus.org */ public class JDOMWriterGenerator extends AbstractJDOMGenerator { private boolean requiresDomSupport; public void generate( Model model, Properties parameters ) throws ModelloException { initialize( model, parameters ); requiresDomSupport = false; try { generateJDOMWriter(); } catch ( IOException ex ) { throw new ModelloException( "Exception while generating JDOM Writer.", ex ); } } private void generateJDOMWriter() throws ModelloException, IOException { Model objectModel = getModel(); String packageName = objectModel.getDefaultPackageName( isPackageWithVersion(), getGeneratedVersion() ) + ".io.jdom"; String marshallerName = getFileName( "JDOMWriter" ); JSourceWriter sourceWriter = newJSourceWriter( packageName, marshallerName ); JClass jClass = new JClass( packageName + '.' + marshallerName ); initHeader( jClass ); suppressAllWarnings( objectModel, jClass ); // ------------------------------------------------------------- // imports now // ------------------------------------------------------------- jClass.addImport( "java.io.OutputStream" ); jClass.addImport( "java.io.OutputStreamWriter" ); jClass.addImport( "java.io.Writer" ); jClass.addImport( "java.text.DateFormat" ); jClass.addImport( "java.util.ArrayList" ); jClass.addImport( "java.util.Collection" ); jClass.addImport( "java.util.Iterator" ); jClass.addImport( "java.util.List" ); jClass.addImport( "java.util.ListIterator" ); jClass.addImport( "java.util.Locale" ); jClass.addImport( "java.util.Map" ); jClass.addImport( "java.util.Properties" ); jClass.addImport( "org.jdom.Content" ); jClass.addImport( "org.jdom.DefaultJDOMFactory" ); jClass.addImport( "org.jdom.Document" ); jClass.addImport( "org.jdom.Element" ); jClass.addImport( "org.jdom.Text" ); jClass.addImport( "org.jdom.output.Format" ); jClass.addImport( "org.jdom.output.XMLOutputter" ); addModelImports( jClass, null ); jClass.addField( new JField( new JClass( "DefaultJDOMFactory" ), "factory" ) ); jClass.addField( new JField( new JClass( "String" ), "lineSeparator" ) ); createCounter( jClass ); // constructor -- JConstructor constructor = jClass.createConstructor(); JSourceCode constCode = constructor.getSourceCode(); constCode.add( "factory = new DefaultJDOMFactory();" ); constCode.add( "lineSeparator = \"\\n\";" ); String root = objectModel.getRoot( getGeneratedVersion() ); ModelClass rootClass = objectModel.getClass( root, getGeneratedVersion() ); String rootElement = resolveTagName( rootClass ); // the public global write method.. jClass.addMethod( generateWriteModel( root, rootElement ) ); jClass.addMethod( generateWriteModel2( root, rootElement ) ); jClass.addMethod( generateWriteModel3( root, rootElement ) ); // the private utility classes; jClass.addMethods( generateUtilityMethods() ); writeAllClasses( objectModel, jClass, rootClass ); if ( requiresDomSupport ) { jClass.addImport( "org.codehaus.plexus.util.xml.Xpp3Dom" ); jClass.addMethods( generateDomMethods() ); } jClass.print( sourceWriter ); sourceWriter.close(); } private void createCounter( final JClass jClass ) throws IllegalArgumentException { // inner counter class JClass counter = jClass.createInnerClass( "Counter" ); counter.getModifiers().setStatic( true ); JField fld = new JField( new JType( "int" ), "currentIndex" ); fld.setInitString( "0" ); counter.addField( fld ); fld = new JField( new JType( "int" ), "level" ); counter.addField( fld ); JConstructor constr = counter.createConstructor( new JParameter[] { new JParameter( new JType( "int" ), "depthLevel" ) } ); constr.getSourceCode().append( "level = depthLevel;" ); JMethod inc = new JMethod( "increaseCount" ); inc.getSourceCode().add( "currentIndex = currentIndex + 1;" ); counter.addMethod( inc ); JMethod getter = new JMethod( "getCurrentIndex", new JType( "int" ), null ); getter.getSourceCode().add( "return currentIndex;" ); counter.addMethod( getter ); getter = new JMethod( "getDepth", new JType( "int" ), null ); getter.getSourceCode().add( "return level;" ); counter.addMethod( getter ); } private JMethod generateWriteModel( String root, String rootElement ) { String variableName = uncapitalise( root ); JMethod marshall = new JMethod( "write" ); marshall.addParameter( new JParameter( new JClass( root ), variableName ) ); marshall.addParameter( new JParameter( new JClass( "Document" ), "document" ) ); marshall.addParameter( new JParameter( new JClass( "OutputStream" ), "stream" ) ); marshall.addException( new JClass( "java.io.IOException" ) ); marshall.getJDocComment().appendComment( "\n@deprecated" ); JSourceCode sc = marshall.getSourceCode(); sc.add( "update" + root + "( " + variableName + ", \"" + rootElement + "\", new Counter( 0 ), document.getRootElement() );" ); sc.add( "XMLOutputter outputter = new XMLOutputter();" ); sc.add( "outputter.setFormat( Format.getPrettyFormat()" ); sc.add( " .setIndent( \" \" )" ); sc.add( " .setLineSeparator( System.getProperty( \"line.separator\" ) ) );" ); sc.add( "outputter.output( document, stream );" ); return marshall; } private JMethod generateWriteModel2( String root, String rootElement ) { String variableName = uncapitalise( root ); JMethod marshall = new JMethod( "write" ); marshall.addParameter( new JParameter( new JClass( root ), variableName ) ); marshall.addParameter( new JParameter( new JClass( "Document" ), "document" ) ); marshall.addParameter( new JParameter( new JClass( "OutputStreamWriter" ), "writer" ) ); marshall.addException( new JClass( "java.io.IOException" ) ); JSourceCode sc = marshall.getSourceCode(); sc.add( "Format format = Format.getRawFormat()" ); sc.add( " .setEncoding( writer.getEncoding() )" ); sc.add( " .setLineSeparator( System.getProperty( \"line.separator\" ) );" ); sc.add( "write( " + variableName + ", document, writer, format );" ); return marshall; } private JMethod generateWriteModel3( String root, String rootElement ) { String variableName = uncapitalise( root ); JMethod marshall = new JMethod( "write" ); marshall.addParameter( new JParameter( new JClass( root ), variableName ) ); marshall.addParameter( new JParameter( new JClass( "Document" ), "document" ) ); marshall.addParameter( new JParameter( new JClass( "Writer" ), "writer" ) ); marshall.addParameter( new JParameter( new JClass( "Format" ), "jdomFormat" ) ); marshall.addException( new JClass( "java.io.IOException" ) ); JSourceCode sc = marshall.getSourceCode(); sc.add( "update" + root + "( " + variableName + ", \"" + rootElement + "\", new Counter( 0 ), document.getRootElement() );" ); sc.add( "XMLOutputter outputter = new XMLOutputter();" ); sc.add( "outputter.setFormat( jdomFormat );" ); sc.add( "outputter.output( document, writer );" ); return marshall; } private JMethod[] generateUtilityMethods() { JMethod findRSElement = new JMethod( "findAndReplaceSimpleElement", new JClass( "Element" ), null ); findRSElement.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); findRSElement.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); findRSElement.addParameter( new JParameter( new JClass( "String" ), "name" ) ); findRSElement.addParameter( new JParameter( new JClass( "String" ), "text" ) ); findRSElement.addParameter( new JParameter( new JClass( "String" ), "defaultValue" ) ); findRSElement.getModifiers().makeProtected(); JSourceCode sc = findRSElement.getSourceCode(); sc.add( "if ( ( defaultValue != null ) && ( text != null ) && defaultValue.equals( text ) )" ); sc.add( "{" ); sc.indent(); sc.add( "Element element = parent.getChild( name, parent.getNamespace() );" ); sc.add( "// if exist and is default value or if doesn't exist.. just keep the way it is.." ); sc.add( "if ( ( element != null && defaultValue.equals( element.getText() ) ) || element == null )" ); sc.add( "{" ); sc.addIndented( "return element;" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "boolean shouldExist = ( text != null ) && ( text.trim().length() > 0 );" ); sc.add( "Element element = updateElement( counter, parent, name, shouldExist );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.addIndented( "element.setText( text );" ); sc.add( "}" ); sc.add( "return element;" ); JMethod updateElement = new JMethod( "updateElement", new JClass( "Element" ), null ); updateElement.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); updateElement.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); updateElement.addParameter( new JParameter( new JClass( "String" ), "name" ) ); updateElement.addParameter( new JParameter( new JType( "boolean" ), "shouldExist" ) ); updateElement.getModifiers().makeProtected(); sc = updateElement.getSourceCode(); sc.add( "Element element = parent.getChild( name, parent.getNamespace() );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.indent(); sc.add( "if ( element == null )" ); sc.add( "{" ); sc.indent(); sc.add( "element = factory.element( name, parent.getNamespace() );" ); sc.add( "insertAtPreferredLocation( parent, element, counter );" ); sc.unindent(); sc.add( "}" ); sc.add( "counter.increaseCount();" ); sc.unindent(); sc.add( "}" ); sc.add( "else if ( element != null )" ); sc.add( "{" ); sc.indent(); sc.add( "int index = parent.indexOf( element );" ); sc.add( "if ( index > 0 )" ); sc.add( "{" ); sc.indent(); sc.add( "Content previous = parent.getContent( index - 1 );" ); sc.add( "if ( previous instanceof Text )" ); sc.add( "{" ); sc.indent(); sc.add( "Text txt = (Text) previous;" ); sc.add( "if ( txt.getTextTrim().length() == 0 )" ); sc.add( "{" ); sc.addIndented( "parent.removeContent( txt );" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "parent.removeContent( element );" ); sc.unindent(); sc.add( "}" ); sc.add( "return element;" ); JMethod insAtPref = new JMethod( "insertAtPreferredLocation" ); insAtPref.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); insAtPref.addParameter( new JParameter( new JClass( "Element" ), "child" ) ); insAtPref.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); insAtPref.getModifiers().makeProtected(); sc = insAtPref.getSourceCode(); sc.add( "int contentIndex = 0;" ); sc.add( "int elementCounter = 0;" ); sc.add( "Iterator it = parent.getContent().iterator();" ); sc.add( "Text lastText = null;" ); sc.add( "int offset = 0;" ); sc.add( "while ( it.hasNext() && elementCounter <= counter.getCurrentIndex() )" ); sc.add( "{" ); sc.indent(); sc.add( "Object next = it.next();" ); sc.add( "offset = offset + 1;" ); sc.add( "if ( next instanceof Element )" ); sc.add( "{" ); sc.indent(); sc.add( "elementCounter = elementCounter + 1;" ); sc.add( "contentIndex = contentIndex + offset;" ); sc.add( "offset = 0;" ); sc.unindent(); sc.add( "}" ); sc.add( "if ( next instanceof Text && it.hasNext() )" ); sc.add( "{" ); sc.addIndented( "lastText = (Text) next;" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); // sc.add("if ( lastText == null )" ); // sc.add( "{" ); // sc.indent(); // sc.add( "int index = parent.getParentElement().indexOf( parent );" ); // sc.add( "if ( index > 0 ) "); // sc.add( "{" ); // sc.indent(); // sc.add( "Content cont = parent.getParentElement().getContent( index - 1 );" ); // sc.add( "if ( cont instanceof Text )" ); // sc.add( "{" ); // sc.addIndented( "lastText = (Text) cont;" ); // sc.add( "}" ); // sc.unindent(); // sc.add( "}" ); // sc.unindent(); // sc.add( "}" ); sc.add( "if ( lastText != null && lastText.getTextTrim().length() == 0 )" ); sc.add( "{" ); sc.addIndented( "lastText = (Text) lastText.clone();" ); sc.add( "}" ); sc.add( "else" ); sc.add( "{" ); sc.indent(); sc.add( "String starter = lineSeparator;" ); sc.add( "for ( int i = 0; i < counter.getDepth(); i++ )" ); sc.add( "{" ); sc.addIndented( "starter = starter + \" \"; //TODO make settable?" ); sc.add( "}" ); sc.add( "lastText = factory.text( starter );" ); sc.unindent(); sc.add( "}" ); sc.add( "if ( parent.getContentSize() == 0 )" ); sc.add( "{" ); sc.indent(); sc.add( "Text finalText = (Text) lastText.clone();" ); sc.add( "finalText.setText( finalText.getText().substring( 0, finalText.getText().length() - \" \".length() ) );" ); sc.add( "parent.addContent( contentIndex, finalText );" ); sc.unindent(); sc.add( "}" ); sc.add( "parent.addContent( contentIndex, child );" ); sc.add( "parent.addContent( contentIndex, lastText );" ); JMethod findRSProps = new JMethod( "findAndReplaceProperties", new JClass( "Element" ), null ); findRSProps.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); findRSProps.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); findRSProps.addParameter( new JParameter( new JClass( "String" ), "name" ) ); findRSProps.addParameter( new JParameter( new JClass( "Map" ), "props" ) ); findRSProps.getModifiers().makeProtected(); sc = findRSProps.getSourceCode(); sc.add( "boolean shouldExist = ( props != null ) && ! props.isEmpty();" ); sc.add( "Element element = updateElement( counter, parent, name, shouldExist );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.indent(); sc.add( "Iterator it = props.keySet().iterator();" ); sc.add( "Counter innerCounter = new Counter( counter.getDepth() + 1 );" ); sc.add( "while ( it.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "String key = (String) it.next();" ); sc.add( "findAndReplaceSimpleElement( innerCounter, element, key, (String) props.get( key ), null );" ); sc.unindent(); sc.add( "}" ); sc.add( "ArrayList lst = new ArrayList( props.keySet() );" ); sc.add( "it = element.getChildren().iterator();" ); sc.add( "while ( it.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "Element elem = (Element) it.next();" ); sc.add( "String key = elem.getName();" ); sc.add( "if ( !lst.contains( key ) )" ); sc.add( "{" ); sc.addIndented( "it.remove();" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "return element;" ); JMethod findRSLists = new JMethod( "findAndReplaceSimpleLists", new JClass( "Element" ), null ); findRSLists.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); findRSLists.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); findRSLists.addParameter( new JParameter( new JClass( "java.util.Collection" ), "list" ) ); findRSLists.addParameter( new JParameter( new JClass( "String" ), "parentName" ) ); findRSLists.addParameter( new JParameter( new JClass( "String" ), "childName" ) ); findRSLists.getModifiers().makeProtected(); sc = findRSLists.getSourceCode(); sc.add( "boolean shouldExist = ( list != null ) && ( list.size() > 0 );" ); sc.add( "Element element = updateElement( counter, parent, parentName, shouldExist );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.indent(); sc.add( "Iterator it = list.iterator();" ); sc.add( "Iterator elIt = element.getChildren( childName, element.getNamespace() ).iterator();" ); sc.add( "if ( ! elIt.hasNext() )" ); sc.add( "{" ); sc.addIndented( " elIt = null;" ); sc.add( "}" ); sc.add( "Counter innerCount = new Counter( counter.getDepth() + 1 );" ); sc.add( "while ( it.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "String value = (String) it.next();" ); sc.add( "Element el;" ); sc.add( "if ( elIt != null && elIt.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "el = (Element) elIt.next();" ); sc.add( "if ( ! elIt.hasNext() )" ); sc.add( "{" ); sc.addIndented( "elIt = null;" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "else" ); sc.add( "{" ); sc.indent(); sc.add( "el = factory.element( childName, element.getNamespace() );" ); sc.add( "insertAtPreferredLocation( element, el, innerCount );" ); sc.unindent(); sc.add( "}" ); sc.add( "el.setText( value );" ); sc.add( "innerCount.increaseCount();" ); sc.unindent(); sc.add( "}" ); sc.add( "if ( elIt != null )" ); sc.add( "{" ); sc.indent(); sc.add( "while ( elIt.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "elIt.next();" ); sc.add( "elIt.remove();" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "return element;" ); return new JMethod[] { findRSElement, updateElement, insAtPref, findRSProps, findRSLists }; } private JMethod[] generateDomMethods() { JMethod findRSDom = new JMethod( "findAndReplaceXpp3DOM", new JClass( "Element" ), null ); findRSDom.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); findRSDom.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); findRSDom.addParameter( new JParameter( new JClass( "String" ), "name" ) ); findRSDom.addParameter( new JParameter( new JClass( "Xpp3Dom" ), "dom" ) ); findRSDom.getModifiers().makeProtected(); JSourceCode sc = findRSDom.getSourceCode(); sc.add( "boolean shouldExist = ( dom != null ) && ( dom.getChildCount() > 0 || dom.getValue() != null );" ); sc.add( "Element element = updateElement( counter, parent, name, shouldExist );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.addIndented( "replaceXpp3DOM( element, dom, new Counter( counter.getDepth() + 1 ) );" ); sc.add( "}" ); sc.add( "return element;" ); JMethod findRSDom2 = new JMethod( "replaceXpp3DOM" ); findRSDom2.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); findRSDom2.addParameter( new JParameter( new JClass( "Xpp3Dom" ), "parentDom" ) ); findRSDom2.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); findRSDom2.getModifiers().makeProtected(); sc = findRSDom2.getSourceCode(); sc.add( "if ( parentDom.getChildCount() > 0 )" ); sc.add( "{" ); sc.indent(); sc.add( "Xpp3Dom[] childs = parentDom.getChildren();" ); sc.add( "Collection domChilds = new ArrayList();" ); sc.add( "for ( int i = 0; i < childs.length; i++ )" ); sc.add( "{" ); sc.addIndented( "domChilds.add( childs[i] );" ); sc.add( "}" ); sc.add( "ListIterator it = parent.getChildren().listIterator();" ); sc.add( "while ( it.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "Element elem = (Element) it.next();" ); sc.add( "Iterator it2 = domChilds.iterator();" ); sc.add( "Xpp3Dom corrDom = null;" ); sc.add( "while ( it2.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "Xpp3Dom dm = (Xpp3Dom) it2.next();" ); sc.add( "if ( dm.getName().equals( elem.getName() ) )" ); sc.add( "{" ); sc.indent(); sc.add( "corrDom = dm;" ); sc.add( "break;" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "if ( corrDom != null )" ); sc.add( "{" ); sc.indent(); sc.add( "domChilds.remove( corrDom );" ); sc.add( "replaceXpp3DOM( elem, corrDom, new Counter( counter.getDepth() + 1 ) );" ); sc.add( "counter.increaseCount();" ); sc.unindent(); sc.add( "}" ); sc.add( "else" ); sc.add( "{" ); sc.addIndented( "it.remove();" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "Iterator it2 = domChilds.iterator();" ); sc.add( "while ( it2.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "Xpp3Dom dm = (Xpp3Dom) it2.next();" ); sc.add( "Element elem = factory.element( dm.getName(), parent.getNamespace() );" ); sc.add( "insertAtPreferredLocation( parent, elem, counter );" ); sc.add( "counter.increaseCount();" ); sc.add( "replaceXpp3DOM( elem, dm, new Counter( counter.getDepth() + 1 ) );" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( " else if ( parentDom.getValue() != null )" ); sc.add( "{" ); sc.addIndented( "parent.setText( parentDom.getValue() );" ); sc.add( "}" ); return new JMethod[] { findRSDom, findRSDom2 }; } private void writeAllClasses( Model objectModel, JClass jClass, ModelClass rootClass ) throws ModelloException { List<ModelClass> alwaysExistingElements = new ArrayList<ModelClass>(); alwaysExistingElements.add( rootClass ); for ( ModelClass clazz : getClasses( objectModel ) ) { updateClass( clazz, jClass, alwaysExistingElements ); } } private void updateClass( ModelClass clazz, JClass jClass, List<ModelClass> alwaysExisting ) throws ModelloException { String className = clazz.getName(); String capClassName = capitalise( className ); String uncapClassName = uncapitalise( className ); JMethod marshall = new JMethod( "update" + capClassName ); marshall.addParameter( new JParameter( new JClass( className ), uncapClassName ) ); marshall.addParameter( new JParameter( new JClass( "String" ), "xmlTag" ) ); marshall.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); marshall.addParameter( new JParameter( new JClass( "Element" ), "element" ) ); marshall.getModifiers().makeProtected(); JSourceCode sc = marshall.getSourceCode(); boolean shouldExist = alwaysExisting.contains( clazz ); if ( shouldExist ) { sc.add( "Element root = element;" ); } else { sc.add( "boolean shouldExist = ( " + uncapClassName + " != null );" ); sc.add( "Element root = updateElement( counter, element, xmlTag, shouldExist );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.indent(); } sc.add( "Counter innerCount = new Counter( counter.getDepth() + 1 );" ); List<ModelField> modelFields = getFieldsForXml( clazz, getGeneratedVersion() ); for ( ModelField field : modelFields ) { XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata( XmlFieldMetadata.ID ); JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata( JavaFieldMetadata.ID ); String fieldTagName = resolveTagName( field, xmlFieldMetadata ); String type = field.getType(); String value = uncapClassName + '.' + getPrefix( javaFieldMetadata ) + capitalise( field.getName() ) + "()"; if ( xmlFieldMetadata.isAttribute() ) { continue; } if ( field instanceof ModelAssociation ) { ModelAssociation association = (ModelAssociation) field; ModelClass toClass = association.getToClass(); if ( association.isOneMultiplicity() ) { sc.add( "update" + capitalise( field.getType() ) + "( " + value + ", \"" + fieldTagName + "\", innerCount, root );" ); } else { //MANY_MULTIPLICITY XmlAssociationMetadata xmlAssociationMetadata = (XmlAssociationMetadata) association.getAssociationMetadata( XmlAssociationMetadata.ID ); //String valuesTagName = resolveTagName( fieldTagName, xmlAssociationMetadata ); // // type = association.getType(); // String toType = association.getTo(); // if ( ModelDefault.LIST.equals( type ) || ModelDefault.SET.equals( type ) ) { // type = association.getType(); String toType = association.getTo(); if ( toClass != null ) { if ( xmlAssociationMetadata.isWrappedItems() ) { sc.add( "iterate" + capitalise( toType ) + "( innerCount, root, " + value + ",\"" + field.getName() + "\",\"" + singular( fieldTagName ) + "\" );" ); createIterateMethod( field.getName(), toClass, singular( fieldTagName ), jClass ); } else { //assume flat.. sc.add( "iterate2" + capitalise( toType ) + "( innerCount, root, " + value + ", \"" + singular( fieldTagName ) + "\" );" ); createIterateMethod2( field.getName(), toClass, singular( fieldTagName ), jClass ); } alwaysExisting.add( toClass ); } else { //list of strings? sc.add( "findAndReplaceSimpleLists( innerCount, root, " + value + ", \"" + fieldTagName + "\", \"" + singular( fieldTagName ) + "\" );" ); } } else { //Map or Properties sc.add( "findAndReplaceProperties( innerCount, root, \"" + fieldTagName + "\", " + value + " );" ); } } } else { if ( "DOM".equals( field.getType() ) ) { sc.add( "findAndReplaceXpp3DOM( innerCount, root, \"" + fieldTagName + "\", (Xpp3Dom) " + value + " );" ); requiresDomSupport = true; } else { sc.add( "findAndReplaceSimpleElement( innerCount, root, \"" + fieldTagName + "\", " + getJdomValueChecker( type, value, field ) + getValue( type, value, xmlFieldMetadata ) + ", " + ( field.getDefaultValue() != null ? ( "\"" + field.getDefaultValue() + "\"" ) : "null" ) + " );" ); } } } if ( !shouldExist ) { sc.unindent(); sc.add( "}" ); } jClass.addMethod( marshall ); } private String getJdomValueChecker( String type, String value, ModelField field ) throws ModelloException { if ( "boolean".equals( type ) || "double".equals( type ) || "float".equals( type ) || "int".equals( type ) || "long".equals( type ) || "short".equals( type ) || "byte".equals( type ) || "char".equals( type ) ) { return value + " == " + getJavaDefaultValue( field ) + " ? null : "; } else if ( ModelDefault.LIST.equals( type ) || ModelDefault.SET.equals( type ) || ModelDefault.MAP.equals( type ) || ModelDefault.PROPERTIES.equals( type ) ) { return value + " == null || " + value + ".size() == 0 ? null : "; // } else if ( "String".equals( type ) && field.getDefaultValue() != null ) { // return "" + value + " == null || " + value + ".equals( \"" + field.getDefaultValue() + "\" ) ? null : "; } else if ( "Date".equals( type ) && field.getDefaultValue() != null ) { return "" + value + " == null || " + value + ".equals( " + getJavaDefaultValue( field ) + " ) ? null : "; } else { return value + " == null ? null : "; } } private void createIterateMethod( String field, ModelClass toClass, String childFieldTagName, JClass jClass ) { if ( jClass.getMethod( "iterate" + capitalise( toClass.getName() ), 0 ) != null ) { // System.out.println("method iterate" + capitalise(field) + " already exists"); return; } JMethod toReturn = new JMethod( "iterate" + capitalise( toClass.getName() ) ); toReturn.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); toReturn.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); toReturn.addParameter( new JParameter( new JClass( "java.util.Collection" ), "list" ) ); toReturn.addParameter( new JParameter( new JClass( "java.lang.String" ), "parentTag" ) ); toReturn.addParameter( new JParameter( new JClass( "java.lang.String" ), "childTag" ) ); toReturn.getModifiers().makeProtected(); JSourceCode sc = toReturn.getSourceCode(); sc.add( "boolean shouldExist = ( list != null ) && ( list.size() > 0 );" ); sc.add( "Element element = updateElement( counter, parent, parentTag, shouldExist );" ); sc.add( "if ( shouldExist )" ); sc.add( "{" ); sc.indent(); sc.add( "Iterator it = list.iterator();" ); sc.add( "Iterator elIt = element.getChildren( childTag, element.getNamespace() ).iterator();" ); sc.add( "if ( !elIt.hasNext() )" ); sc.add( "{" ); sc.addIndented( "elIt = null;" ); sc.add( "}" ); sc.add( "Counter innerCount = new Counter( counter.getDepth() + 1 );" ); sc.add( "while ( it.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( toClass.getName() + " value = (" + toClass.getName() + ") it.next();" ); sc.add( "Element el;" ); sc.add( "if ( elIt != null && elIt.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "el = (Element) elIt.next();" ); sc.add( "if ( ! elIt.hasNext() )" ); sc.add( "{" ); sc.addIndented( " elIt = null;" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "else" ); sc.add( "{" ); sc.indent(); sc.add( "el = factory.element( childTag, element.getNamespace() );" ); sc.add( "insertAtPreferredLocation( element, el, innerCount );" ); sc.unindent(); sc.add( "}" ); sc.add( "update" + toClass.getName() + "( value, childTag, innerCount, el );" ); sc.add( "innerCount.increaseCount();" ); sc.unindent(); sc.add( "}" ); sc.add( "if ( elIt != null )" ); sc.add( "{" ); sc.indent(); sc.add( "while ( elIt.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "elIt.next();" ); sc.add( "elIt.remove();" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); jClass.addMethod( toReturn ); } private void createIterateMethod2( String field, ModelClass toClass, String childFieldTagName, JClass jClass ) { if ( jClass.getMethod( "iterate2" + capitalise( toClass.getName() ), 0 ) != null ) { // System.out.println("method iterate" + capitalise(field) + " already exists"); return; } JMethod toReturn = new JMethod( "iterate2" + capitalise( toClass.getName() ) ); toReturn.addParameter( new JParameter( new JClass( "Counter" ), "counter" ) ); toReturn.addParameter( new JParameter( new JClass( "Element" ), "parent" ) ); toReturn.addParameter( new JParameter( new JClass( "java.util.Collection" ), "list" ) ); toReturn.addParameter( new JParameter( new JClass( "java.lang.String" ), "childTag" ) ); toReturn.getModifiers().makeProtected(); JSourceCode sc = toReturn.getSourceCode(); sc.add( "Iterator it = list.iterator();" ); sc.add( "Iterator elIt = parent.getChildren( childTag, parent.getNamespace() ).iterator();" ); sc.add( "if ( !elIt.hasNext() )" ); sc.add( "{" ); sc.addIndented( "elIt = null;" ); sc.add( "}" ); sc.add( "Counter innerCount = new Counter( counter.getDepth() + 1 );" ); sc.add( "while ( it.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( toClass.getName() + " value = (" + toClass.getName() + ") it.next();" ); sc.add( "Element el;" ); sc.add( "if ( elIt != null && elIt.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "el = (Element) elIt.next();" ); sc.add( "if ( ! elIt.hasNext() )" ); sc.add( "{" ); sc.addIndented( "elIt = null;" ); sc.add( "}" ); sc.unindent(); sc.add( "}" ); sc.add( "else" ); sc.add( "{" ); sc.indent(); sc.add( "el = factory.element( childTag, parent.getNamespace() );" ); sc.add( "insertAtPreferredLocation( parent, el, innerCount );" ); sc.unindent(); sc.add( "}" ); sc.add( "update" + toClass.getName() + "( value, childTag, innerCount, el );" ); sc.add( "innerCount.increaseCount();" ); sc.unindent(); sc.add( "}" ); sc.add( "if ( elIt != null )" ); sc.add( "{" ); sc.indent(); sc.add( "while ( elIt.hasNext() )" ); sc.add( "{" ); sc.indent(); sc.add( "elIt.next();" ); sc.add( "elIt.remove();" ); sc.unindent(); sc.add( "}" ); sc.unindent(); sc.add( "}" ); jClass.addMethod( toReturn ); } }