001    /*
002     * Copyright (C) 2009 The CC-XJC Project. All rights reserved.
003     *
004     * Redistribution and use in source and binary forms, with or without
005     * modification, are permitted provided that the following conditions
006     * are met:
007     *
008     *   o Redistributions of source code must retain the above copyright
009     *     notice, this  list of conditions and the following disclaimer.
010     *
011     *   o Redistributions in binary form must reproduce the above copyright
012     *     notice, this list of conditions and the following disclaimer in
013     *     the documentation and/or other materials provided with the
014     *     distribution.
015     *
016     * THIS SOFTWARE IS PROVIDED BY THE CC-XJC PROJECT AND CONTRIBUTORS "AS IS"
017     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
018     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
019     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CC-XJC PROJECT OR
020     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
021     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
022     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
023     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
024     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
025     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
026     * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027     *
028     * $Id: PluginImpl.java 162 2012-03-02 12:00:20Z schulte2005 $
029     */
030    package net.sourceforge.ccxjc;
031    
032    import com.sun.codemodel.JBlock;
033    import com.sun.codemodel.JCatchBlock;
034    import com.sun.codemodel.JClass;
035    import com.sun.codemodel.JConditional;
036    import com.sun.codemodel.JDefinedClass;
037    import com.sun.codemodel.JExpr;
038    import com.sun.codemodel.JExpression;
039    import com.sun.codemodel.JFieldVar;
040    import com.sun.codemodel.JForLoop;
041    import com.sun.codemodel.JInvocation;
042    import com.sun.codemodel.JMethod;
043    import com.sun.codemodel.JMod;
044    import com.sun.codemodel.JOp;
045    import com.sun.codemodel.JTryBlock;
046    import com.sun.codemodel.JType;
047    import com.sun.codemodel.JVar;
048    import com.sun.tools.xjc.BadCommandLineException;
049    import com.sun.tools.xjc.Options;
050    import com.sun.tools.xjc.Plugin;
051    import com.sun.tools.xjc.generator.bean.ImplStructureStrategy;
052    import com.sun.tools.xjc.model.CAdapter;
053    import com.sun.tools.xjc.model.CArrayInfo;
054    import com.sun.tools.xjc.model.CBuiltinLeafInfo;
055    import com.sun.tools.xjc.model.CClassInfo;
056    import com.sun.tools.xjc.model.CCustomizations;
057    import com.sun.tools.xjc.model.CElementInfo;
058    import com.sun.tools.xjc.model.CEnumLeafInfo;
059    import com.sun.tools.xjc.model.CNonElement;
060    import com.sun.tools.xjc.model.CTypeInfo;
061    import com.sun.tools.xjc.model.CWildcardTypeInfo;
062    import com.sun.tools.xjc.model.nav.NType;
063    import com.sun.tools.xjc.outline.Aspect;
064    import com.sun.tools.xjc.outline.ClassOutline;
065    import com.sun.tools.xjc.outline.FieldOutline;
066    import com.sun.tools.xjc.outline.Outline;
067    import com.sun.xml.bind.v2.model.annotation.Locatable;
068    import com.sun.xml.bind.v2.model.core.ID;
069    import com.sun.xml.bind.v2.runtime.Location;
070    import com.sun.xml.xsom.XSComponent;
071    import com.sun.xml.xsom.XmlString;
072    import java.io.BufferedReader;
073    import java.io.ByteArrayInputStream;
074    import java.io.ByteArrayOutputStream;
075    import java.io.File;
076    import java.io.FileReader;
077    import java.io.IOException;
078    import java.io.InvalidClassException;
079    import java.io.NotSerializableException;
080    import java.io.ObjectInputStream;
081    import java.io.ObjectOutputStream;
082    import java.io.OptionalDataException;
083    import java.io.Serializable;
084    import java.io.StreamCorruptedException;
085    import java.lang.reflect.Array;
086    import java.lang.reflect.InvocationTargetException;
087    import java.math.BigDecimal;
088    import java.math.BigInteger;
089    import java.net.URI;
090    import java.net.URL;
091    import java.text.MessageFormat;
092    import java.util.ArrayList;
093    import java.util.Arrays;
094    import java.util.Calendar;
095    import java.util.Collection;
096    import java.util.Collections;
097    import java.util.Comparator;
098    import java.util.Currency;
099    import java.util.Date;
100    import java.util.HashSet;
101    import java.util.Iterator;
102    import java.util.LinkedList;
103    import java.util.List;
104    import java.util.Locale;
105    import java.util.ResourceBundle;
106    import java.util.Set;
107    import java.util.TimeZone;
108    import java.util.UUID;
109    import java.util.logging.Level;
110    import javax.activation.MimeType;
111    import javax.xml.bind.JAXBElement;
112    import javax.xml.datatype.Duration;
113    import javax.xml.datatype.XMLGregorianCalendar;
114    import javax.xml.namespace.QName;
115    import org.w3c.dom.Element;
116    import org.xml.sax.ErrorHandler;
117    import org.xml.sax.Locator;
118    
119    /**
120     * CC-XJC plugin implementation.
121     *
122     * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
123     * @version $Id: PluginImpl.java 162 2012-03-02 12:00:20Z schulte2005 $
124     */
125    public final class PluginImpl extends Plugin
126    {
127    
128        private static final JType[] NO_ARGS = new JType[ 0 ];
129    
130        private static final String MESSAGE_PREFIX = "CC-XJC";
131    
132        private static final String WARNING_PREFIX = MESSAGE_PREFIX + " WARNING";
133    
134        private static final String OPTION_NAME = "copy-constructor";
135    
136        private static final String VISIBILITY_OPTION_NAME = "-cc-visibility";
137    
138        private static final String TARGET_OPTION_NAME = "-cc-target";
139    
140        private static final String NULLABLE_OPTION_NAME = "-cc-nullable";
141    
142        private static final String HIERARCHICAL_OPTION_NAME = "-cc-hierarchical";
143    
144        private static final String IMMUTABLE_TYPES_OPTION_NAME = "-cc-immutable-types";
145    
146        private static final String CLONEABLE_TYPES_OPTION_NAME = "-cc-cloneable-types";
147    
148        private static final String STRING_TYPES_OPTION_NAME = "-cc-string-types";
149    
150        private static final String ELEMENT_SEPARATOR = ":";
151    
152        private static final List<String> DEFAULT_IMMUTABLE_TYPES = Arrays.asList( new String[]
153            {
154                Boolean.class.getName(),
155                Byte.class.getName(),
156                Character.class.getName(),
157                Double.class.getName(),
158                Enum.class.getName(),
159                Float.class.getName(),
160                Integer.class.getName(),
161                Long.class.getName(),
162                Short.class.getName(),
163                String.class.getName(),
164                BigDecimal.class.getName(),
165                BigInteger.class.getName(),
166                UUID.class.getName(),
167                QName.class.getName(),
168                Duration.class.getName(),
169                Currency.class.getName()
170            } );
171    
172        private static final List<String> DEFAULT_CLONEABLE_TYPES = Arrays.asList( new String[]
173            {
174                XMLGregorianCalendar.class.getName(),
175                Date.class.getName(),
176                Calendar.class.getName(),
177                TimeZone.class.getName(),
178                Locale.class.getName()
179            } );
180    
181        private static final List<String> DEFAULT_STRING_TYPES = Arrays.asList( new String[]
182            {
183                File.class.getName(),
184                URI.class.getName(),
185                URL.class.getName(),
186                MimeType.class.getName()
187            } );
188    
189        private static final Class<?>[] PRIMITIVE_ARRAY_TYPES =
190        {
191            boolean[].class,
192            byte[].class,
193            char[].class,
194            double[].class,
195            float[].class,
196            int[].class,
197            long[].class,
198            short[].class
199        };
200    
201        private static final String[] VISIBILITY_ARGUMENTS =
202        {
203            "private", "package", "protected", "public"
204        };
205    
206        private static final String[] TARGET_ARGUMENTS =
207        {
208            "1.5", "1.6", "1.7"
209        };
210    
211        private static final int TARGET_1_5 = 5;
212    
213        private static final int TARGET_1_6 = 6;
214    
215        private static final int TARGET_1_7 = 7;
216    
217        private boolean success;
218    
219        private Options options;
220    
221        private String visibility = "private";
222    
223        private int targetJdk = TARGET_1_5;
224    
225        private boolean nullable = false;
226    
227        private boolean hierarchical = false;
228    
229        private final List<String> immutableTypes = new ArrayList<String>( 64 );
230    
231        private final List<String> cloneableTypes = new ArrayList<String>( 64 );
232    
233        private final List<String> stringTypes = new ArrayList<String>( 64 );
234    
235        private BigInteger methodCount;
236    
237        private BigInteger constructorCount;
238    
239        private BigInteger expressionCount;
240    
241        private final Set<Class<?>> contextExceptions = new HashSet<Class<?>>();
242    
243        private boolean tryCatchCopyExpression = false;
244    
245        @Override
246        public String getOptionName()
247        {
248            return OPTION_NAME;
249        }
250    
251        @Override
252        public String getUsage()
253        {
254            final String n = System.getProperty( "line.separator", "\n" );
255    
256            return new StringBuilder( 1024 ).append( "  -" ).append( OPTION_NAME ).append( "  :  " ).
257                append( getMessage( "usage" ) ).append( n ).
258                append( "  " ).append( VISIBILITY_OPTION_NAME ).append( "     :  " ).
259                append( getMessage( "visibilityUsage" ) ).append( n ).
260                append( "  " ).append( TARGET_OPTION_NAME ).append( "         :  " ).
261                append( getMessage( "targetUsage" ) ).append( n ).
262                append( "  " ).append( NULLABLE_OPTION_NAME ).append( "       :  " ).
263                append( getMessage( "nullableUsage" ) ).append( n ).
264                append( "  " ).append( HIERARCHICAL_OPTION_NAME ).append( "   :  " ).
265                append( getMessage( "hierarchicalUsage" ) ).append( n ).
266                append( "  " ).append( CLONEABLE_TYPES_OPTION_NAME ).append( ":  " ).
267                append( getMessage( "cloneableTypesUsage", ELEMENT_SEPARATOR ) ).append( n ).
268                append( "  " ).append( IMMUTABLE_TYPES_OPTION_NAME ).append( ":  " ).
269                append( getMessage( "immutableTypesUsage", ELEMENT_SEPARATOR ) ).append( n ).
270                append( "  " ).append( STRING_TYPES_OPTION_NAME ).append( "   :  " ).
271                append( getMessage( "stringTypesUsage", ELEMENT_SEPARATOR ) ).toString();
272    
273        }
274    
275        @Override
276        public int parseArgument( final Options opt, final String[] args, final int i )
277            throws BadCommandLineException, IOException
278        {
279            final StringBuilder supportedVisibilities = new StringBuilder( 1024 ).append( '[' );
280            for ( Iterator<String> it = Arrays.asList( VISIBILITY_ARGUMENTS ).iterator(); it.hasNext(); )
281            {
282                supportedVisibilities.append( it.next() );
283                if ( it.hasNext() )
284                {
285                    supportedVisibilities.append( ", " );
286                }
287            }
288    
289            final StringBuilder supportedTargets = new StringBuilder( 512 ).append( '[' );
290            for ( Iterator<String> it = Arrays.asList( TARGET_ARGUMENTS ).iterator(); it.hasNext(); )
291            {
292                supportedTargets.append( it.next() );
293                if ( it.hasNext() )
294                {
295                    supportedTargets.append( ", " );
296                }
297            }
298    
299            if ( args[i].startsWith( VISIBILITY_OPTION_NAME ) )
300            {
301                if ( i + 1 >= args.length )
302                {
303                    final String missingOptionArgument = getMessage( "missingOptionArgument", VISIBILITY_OPTION_NAME );
304                    final String expectedOptionArgument = getMessage( "expectedOptionArgument",
305                                                                      supportedVisibilities.append( ']' ).toString() );
306    
307                    throw new BadCommandLineException( missingOptionArgument + " " + expectedOptionArgument );
308                }
309    
310                this.visibility = args[i + 1].trim();
311    
312                boolean supported = false;
313                for ( String argument : VISIBILITY_ARGUMENTS )
314                {
315                    if ( argument.equals( this.visibility ) )
316                    {
317                        supported = true;
318                        break;
319                    }
320                }
321    
322                if ( !supported )
323                {
324                    final String expectedOptionArgument = getMessage( "expectedOptionArgument",
325                                                                      supportedVisibilities.append( ']' ).toString() );
326    
327                    throw new BadCommandLineException( expectedOptionArgument );
328                }
329    
330                return 2;
331            }
332    
333            if ( args[i].startsWith( TARGET_OPTION_NAME ) )
334            {
335                if ( i + 1 >= args.length )
336                {
337                    final String missingOptionArgument = getMessage( "missingOptionArgument", TARGET_OPTION_NAME );
338                    final String expectedOptionArgument = getMessage( "expectedOptionArgument",
339                                                                      supportedTargets.append( ']' ).toString() );
340    
341                    throw new BadCommandLineException( missingOptionArgument + " " + expectedOptionArgument );
342                }
343    
344                final String targetArg = args[i + 1].trim();
345    
346                boolean supported = false;
347                for ( String argument : TARGET_ARGUMENTS )
348                {
349                    if ( argument.equals( targetArg ) )
350                    {
351                        supported = true;
352                        break;
353                    }
354                }
355    
356                if ( !supported )
357                {
358                    final String expectedOptionArgument = getMessage( "expectedOptionArgument",
359                                                                      supportedTargets.append( ']' ).toString() );
360    
361                    throw new BadCommandLineException( expectedOptionArgument );
362                }
363    
364                if ( targetArg.equals( "1.5" ) )
365                {
366                    this.targetJdk = TARGET_1_5;
367                }
368                else if ( targetArg.equals( "1.6" ) )
369                {
370                    this.targetJdk = TARGET_1_6;
371                }
372                else if ( targetArg.equals( "1.7" ) )
373                {
374                    this.targetJdk = TARGET_1_7;
375                }
376    
377                return 2;
378            }
379    
380            if ( args[i].startsWith( NULLABLE_OPTION_NAME ) )
381            {
382                this.nullable = true;
383                return 1;
384            }
385    
386            if ( args[i].startsWith( HIERARCHICAL_OPTION_NAME ) )
387            {
388                this.hierarchical = true;
389                return 1;
390            }
391    
392            if ( args[i].startsWith( IMMUTABLE_TYPES_OPTION_NAME ) )
393            {
394                if ( i + 1 >= args.length )
395                {
396                    throw new BadCommandLineException( getMessage( "missingOptionArgument", IMMUTABLE_TYPES_OPTION_NAME ) );
397                }
398    
399                final Collection<String> types = Arrays.asList( args[i + 1].split( ELEMENT_SEPARATOR ) );
400                for ( String type : types )
401                {
402                    if ( type.startsWith( "@" ) )
403                    {
404                        this.immutableTypes.addAll( this.readTypes( type.substring( 1 ) ) );
405                    }
406                    else if ( type.trim().length() > 0 )
407                    {
408                        this.immutableTypes.add( type );
409                    }
410                }
411    
412                return 2;
413            }
414    
415            if ( args[i].startsWith( CLONEABLE_TYPES_OPTION_NAME ) )
416            {
417                if ( i + 1 >= args.length )
418                {
419                    throw new BadCommandLineException( getMessage( "missingOptionArgument", CLONEABLE_TYPES_OPTION_NAME ) );
420                }
421    
422                final Collection<String> types = Arrays.asList( args[i + 1].split( ELEMENT_SEPARATOR ) );
423    
424                for ( String type : types )
425                {
426                    if ( type.startsWith( "@" ) )
427                    {
428                        this.cloneableTypes.addAll( this.readTypes( type.substring( 1 ) ) );
429                    }
430                    else if ( type.trim().length() > 0 )
431                    {
432                        this.cloneableTypes.add( type );
433                    }
434                }
435    
436                return 2;
437            }
438    
439            if ( args[i].startsWith( STRING_TYPES_OPTION_NAME ) )
440            {
441                if ( i + 1 >= args.length )
442                {
443                    throw new BadCommandLineException( getMessage( "missingOptionArgument", STRING_TYPES_OPTION_NAME ) );
444                }
445    
446                final Collection<String> types = Arrays.asList( args[i + 1].split( ELEMENT_SEPARATOR ) );
447    
448                for ( String type : types )
449                {
450                    if ( type.startsWith( "@" ) )
451                    {
452                        this.stringTypes.addAll( this.readTypes( type.substring( 1 ) ) );
453                    }
454                    else if ( type.trim().length() > 0 )
455                    {
456                        this.stringTypes.add( type );
457                    }
458                }
459    
460                return 2;
461            }
462    
463            return 0;
464        }
465    
466        @Override
467        public boolean run( final Outline model, final Options options, final ErrorHandler errorHandler )
468        {
469            this.success = true;
470            this.options = options;
471            this.methodCount = BigInteger.ZERO;
472            this.constructorCount = BigInteger.ZERO;
473            this.expressionCount = BigInteger.ZERO;
474    
475            this.cloneableTypes.removeAll( DEFAULT_CLONEABLE_TYPES );
476            this.cloneableTypes.addAll( DEFAULT_CLONEABLE_TYPES );
477            this.immutableTypes.removeAll( DEFAULT_IMMUTABLE_TYPES );
478            this.immutableTypes.addAll( DEFAULT_IMMUTABLE_TYPES );
479            this.stringTypes.removeAll( DEFAULT_STRING_TYPES );
480            this.stringTypes.addAll( DEFAULT_STRING_TYPES );
481    
482            this.log( Level.INFO, "title" );
483            this.log( Level.INFO, "visibilityReport", this.visibility );
484    
485            final StringBuilder cloneableInfo = new StringBuilder( 1024 );
486            final StringBuilder immutableInfo = new StringBuilder( 1024 );
487            final StringBuilder stringInfo = new StringBuilder( 1024 );
488    
489            for ( String name : this.cloneableTypes )
490            {
491                cloneableInfo.append( System.getProperty( "line.separator", "\n" ) ).append( "\t" ).append( name );
492            }
493    
494            for ( String name : this.immutableTypes )
495            {
496                immutableInfo.append( System.getProperty( "line.separator", "\n" ) ).append( "\t" ).append( name );
497            }
498    
499            for ( String name : this.stringTypes )
500            {
501                stringInfo.append( System.getProperty( "line.separator", "\n" ) ).append( "\t" ).append( name );
502            }
503    
504            this.log( Level.INFO, "cloneableTypesInfo", cloneableInfo.toString() );
505            this.log( Level.INFO, "immutableTypesInfo", immutableInfo.toString() );
506            this.log( Level.INFO, "stringTypesInfo", stringInfo.toString() );
507    
508            for ( ClassOutline clazz : model.getClasses() )
509            {
510                this.warnOnReferencedSupertypes( clazz );
511    
512                if ( this.getStandardConstructor( clazz ) == null )
513                {
514                    this.log( Level.WARNING, "couldNotAddStdCtor", clazz.implClass.binaryName() );
515                }
516    
517                if ( this.getCopyConstructor( clazz ) == null )
518                {
519                    this.log( Level.WARNING, "couldNotAddCopyCtor", clazz.implClass.binaryName() );
520                }
521    
522                if ( this.getCloneMethod( clazz ) == null )
523                {
524                    this.log( Level.WARNING, "couldNotAddMethod", "clone", clazz.implClass.binaryName() );
525                }
526            }
527    
528            this.log( Level.INFO, "report", this.methodCount, this.constructorCount, this.expressionCount );
529    
530            this.options = null;
531            return this.success;
532        }
533    
534        private int getVisibilityModifier()
535        {
536            if ( "private".equals( this.visibility ) )
537            {
538                return JMod.PRIVATE;
539            }
540            else if ( "protected".equals( this.visibility ) )
541            {
542                return JMod.PROTECTED;
543            }
544            else if ( "public".equals( this.visibility ) )
545            {
546                return JMod.PUBLIC;
547            }
548    
549            return JMod.NONE;
550        }
551    
552        private boolean isTargetSupported( final int target )
553        {
554            return target <= this.targetJdk;
555        }
556    
557        private JMethod getStandardConstructor( final ClassOutline clazz )
558        {
559            JMethod ctor = clazz.implClass.getConstructor( NO_ARGS );
560            if ( ctor == null )
561            {
562                ctor = this.generateStandardConstructor( clazz );
563            }
564            else
565            {
566                this.log( Level.WARNING, "standardCtorExists", clazz.implClass.binaryName() );
567            }
568    
569            return ctor;
570        }
571    
572        private JMethod getCopyConstructor( final ClassOutline clazz )
573        {
574            JMethod ctor = clazz.implClass.getConstructor( new JType[]
575                {
576                    clazz.implClass
577                } );
578    
579            if ( ctor == null )
580            {
581                ctor = this.generateCopyConstructor( clazz );
582            }
583            else
584            {
585                this.log( Level.WARNING, "copyCtorExists", clazz.implClass.binaryName() );
586            }
587    
588            return ctor;
589        }
590    
591        private JMethod getCloneMethod( final ClassOutline clazz )
592        {
593            JMethod clone = clazz.implClass.getMethod( "clone", NO_ARGS );
594            if ( clone == null )
595            {
596                clone = this.generateCloneMethod( clazz );
597            }
598            else
599            {
600                this.log( Level.WARNING, "methodExists", "clone", clazz.implClass.binaryName() );
601            }
602    
603            return clone;
604        }
605    
606        private JMethod getPropertyGetter( final FieldOutline f )
607        {
608            final JDefinedClass clazz = f.parent().implClass;
609            final String name = f.getPropertyInfo().getName( true );
610            JMethod getter = clazz.getMethod( "get" + name, NO_ARGS );
611    
612            if ( getter == null )
613            {
614                getter = clazz.getMethod( "is" + name, NO_ARGS );
615            }
616    
617            return getter;
618        }
619    
620        private FieldOutline getFieldOutline( final ClassOutline clazz, final String fieldName )
621        {
622            for ( FieldOutline f : clazz.getDeclaredFields() )
623            {
624                if ( f.getPropertyInfo().getName( false ).equals( fieldName ) )
625                {
626                    return f;
627                }
628            }
629    
630            return null;
631        }
632    
633        private JInvocation getCopyOfJaxbElementInvocation( final ClassOutline clazz )
634        {
635            final JClass jaxbElement = clazz.parent().getCodeModel().ref( JAXBElement.class );
636            final JType[] signature =
637            {
638                jaxbElement
639            };
640    
641            final String methodName = "copyOf";
642            final int mod = this.getVisibilityModifier();
643    
644            if ( mod != JMod.PRIVATE )
645            {
646                for ( JMethod m : clazz._package().objectFactory().methods() )
647                {
648                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
649                    {
650                        return clazz._package().objectFactory().staticInvoke( m );
651                    }
652                }
653            }
654            else
655            {
656                for ( JMethod m : clazz.implClass.methods() )
657                {
658                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
659                    {
660                        return JExpr.invoke( m );
661                    }
662                }
663            }
664    
665            final JMethod m =
666                ( mod != JMod.PRIVATE
667                  ? clazz._package().objectFactory().method( JMod.STATIC | mod, JAXBElement.class, methodName )
668                  : clazz.implClass.method( JMod.STATIC | mod, JAXBElement.class, methodName ) );
669    
670            final JVar element = m.param( JMod.FINAL, jaxbElement, "element" );
671    
672            m.javadoc().append( "Creates and returns a deep copy of a given {@code JAXBElement} instance." );
673            m.javadoc().addParam( element ).append( "The instance to copy or {@code null}." );
674            m.javadoc().addReturn().append(
675                "A deep copy of {@code element} or {@code null} if {@code element} is {@code null}." );
676    
677            m.annotate( SuppressWarnings.class ).param( "value", "unchecked" );
678            m.body().directStatement( "// " + getMessage( "title" ) );
679    
680            final JConditional isNotNull = m.body()._if( element.ne( JExpr._null() ) );
681            final JExpression newElement = JExpr._new( jaxbElement ).
682                arg( JExpr.invoke( element, "getName" ) ).
683                arg( JExpr.invoke( element, "getDeclaredType" ) ).
684                arg( JExpr.invoke( element, "getScope" ) ).
685                arg( JExpr.invoke( element, "getValue" ) );
686    
687            final JVar copy = isNotNull._then().decl( JMod.FINAL, jaxbElement, "copy", newElement );
688            isNotNull._then().add( copy.invoke( "setNil" ).arg( element.invoke( "isNil" ) ) );
689            isNotNull._then().add( copy.invoke( "setValue" ).arg( this.getCopyOfObjectInvocation( clazz ).
690                arg( JExpr.invoke( copy, "getValue" ) ) ) );
691    
692            isNotNull._then()._return( copy );
693            m.body()._return( JExpr._null() );
694            this.methodCount = this.methodCount.add( BigInteger.ONE );
695            return ( mod != JMod.PRIVATE ? clazz._package().objectFactory().staticInvoke( m ) : JExpr.invoke( m ) );
696        }
697    
698        private JExpression getCopyOfPrimitiveArrayExpression( final ClassOutline classOutline, final JClass arrayType,
699                                                               final JExpression source )
700        {
701            if ( this.isTargetSupported( TARGET_1_6 ) )
702            {
703                final JClass arrays = classOutline.parent().getCodeModel().ref( Arrays.class );
704                return JOp.cond( source.eq( JExpr._null() ), JExpr._null(), arrays.staticInvoke( "copyOf" ).
705                    arg( source ).arg( source.ref( "length" ) ) );
706    
707            }
708    
709            final JClass array = classOutline.parent().getCodeModel().ref( Array.class );
710            final JClass system = classOutline.parent().getCodeModel().ref( System.class );
711    
712            final int mod = this.getVisibilityModifier();
713            final String methodName = "copyOf";
714            final JType[] signature = new JType[]
715            {
716                arrayType
717            };
718    
719            if ( mod != JMod.PRIVATE )
720            {
721                for ( JMethod m : classOutline._package().objectFactory().methods() )
722                {
723                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
724                    {
725                        return classOutline._package().objectFactory().staticInvoke( m ).arg( source );
726                    }
727                }
728            }
729            else
730            {
731                for ( JMethod m : classOutline.implClass.methods() )
732                {
733                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
734                    {
735                        return JExpr.invoke( m ).arg( source );
736                    }
737                }
738            }
739    
740            final JMethod m =
741                ( mod != JMod.PRIVATE
742                  ? classOutline._package().objectFactory().method( JMod.STATIC | mod, arrayType, methodName )
743                  : classOutline.implClass.method( JMod.STATIC | mod, arrayType, methodName ) );
744    
745            final JVar arrayParam = m.param( JMod.FINAL, arrayType, "array" );
746    
747            m.javadoc().append( "Creates and returns a deep copy of a given array." );
748            m.javadoc().addParam( arrayParam ).append( "The array to copy or {@code null}." );
749            m.javadoc().addReturn().append(
750                "A deep copy of {@code array} or {@code null} if {@code array} is {@code null}." );
751    
752            m.body().directStatement( "// " + getMessage( "title" ) );
753    
754            final JConditional arrayNotNull = m.body()._if( arrayParam.ne( JExpr._null() ) );
755            final JVar copy = arrayNotNull._then().decl(
756                JMod.FINAL, arrayType, "copy", JExpr.cast( arrayType, array.staticInvoke( "newInstance" ).arg(
757                arrayParam.invoke( "getClass" ).invoke( "getComponentType" ) ).arg( arrayParam.ref( "length" ) ) ) );
758    
759            arrayNotNull._then().add( system.staticInvoke( "arraycopy" ).arg( arrayParam ).arg( JExpr.lit( 0 ) ).
760                arg( copy ).arg( JExpr.lit( 0 ) ).arg( arrayParam.ref( "length" ) ) );
761    
762            arrayNotNull._then()._return( copy );
763    
764            m.body()._return( JExpr._null() );
765    
766            this.methodCount = this.methodCount.add( BigInteger.ONE );
767            return ( mod != JMod.PRIVATE ? classOutline._package().objectFactory().staticInvoke( m ).arg( source )
768                     : JExpr.invoke( m ).arg( source ) );
769    
770        }
771    
772        private JInvocation getCopyOfArrayInvocation( final ClassOutline clazz )
773        {
774            final JClass object = clazz.parent().getCodeModel().ref( Object.class );
775            final JClass array = clazz.parent().getCodeModel().ref( Array.class );
776            final JType[] signature =
777            {
778                object
779            };
780    
781            final String methodName = "copyOfArray";
782            final int mod = this.getVisibilityModifier();
783    
784            if ( mod != JMod.PRIVATE )
785            {
786                for ( JMethod m : clazz._package().objectFactory().methods() )
787                {
788                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
789                    {
790                        return clazz._package().objectFactory().staticInvoke( m );
791                    }
792                }
793            }
794            else
795            {
796                for ( JMethod m : clazz.implClass.methods() )
797                {
798                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
799                    {
800                        return JExpr.invoke( m );
801                    }
802                }
803            }
804    
805            final JMethod m =
806                ( mod != JMod.PRIVATE
807                  ? clazz._package().objectFactory().method( JMod.STATIC | mod, object, methodName )
808                  : clazz.implClass.method( JMod.STATIC | mod, object, methodName ) );
809    
810            final JVar arrayArg = m.param( JMod.FINAL, object, "array" );
811    
812            m.javadoc().append( "Creates and returns a deep copy of a given array." );
813            m.javadoc().addParam( arrayArg ).append( "The array to copy or {@code null}." );
814            m.javadoc().addReturn().append(
815                "A deep copy of {@code array} or {@code null} if {@code array} is {@code null}." );
816    
817            m.body().directStatement( "// " + getMessage( "title" ) );
818    
819            final JConditional arrayNotNull = m.body()._if( arrayArg.ne( JExpr._null() ) );
820    
821            for ( Class<?> a : PRIMITIVE_ARRAY_TYPES )
822            {
823                final JClass primitiveArray = clazz.parent().getCodeModel().ref( a );
824                final JConditional isArrayOfPrimitive =
825                    arrayNotNull._then()._if( arrayArg.invoke( "getClass" ).eq( primitiveArray.dotclass() ) );
826    
827                isArrayOfPrimitive._then()._return( this.getCopyOfPrimitiveArrayExpression(
828                    clazz, primitiveArray, JExpr.cast( primitiveArray, arrayArg ) ) );
829    
830            }
831    
832            final JVar len = arrayNotNull._then().decl(
833                JMod.FINAL, clazz.parent().getCodeModel().INT, "len", array.staticInvoke( "getLength" ).
834                arg( arrayArg ) );
835    
836            final JVar copy = arrayNotNull._then().decl( JMod.FINAL, object, "copy", array.staticInvoke( "newInstance" ).
837                arg( arrayArg.invoke( "getClass" ).invoke( "getComponentType" ) ).arg( len ) );
838    
839            final JForLoop forEachRef = arrayNotNull._then()._for();
840            final JVar i = forEachRef.init( clazz.parent().getCodeModel().INT, "i", len.minus( JExpr.lit( 1 ) ) );
841            forEachRef.test( i.gte( JExpr.lit( 0 ) ) );
842            forEachRef.update( i.decr() );
843            forEachRef.body().add( array.staticInvoke( "set" ).arg( copy ).arg( i ).
844                arg( this.getCopyOfObjectInvocation( clazz ).arg( array.staticInvoke( "get" ).
845                arg( arrayArg ).arg( i ) ) ) );
846    
847            arrayNotNull._then()._return( copy );
848            m.body()._return( JExpr._null() );
849            this.methodCount = this.methodCount.add( BigInteger.ONE );
850            return ( mod != JMod.PRIVATE ? clazz._package().objectFactory().staticInvoke( m ) : JExpr.invoke( m ) );
851        }
852    
853        private JInvocation getCopyOfSerializableInvocation( final ClassOutline clazz )
854        {
855            final JClass serializable = clazz.parent().getCodeModel().ref( Serializable.class );
856            final JClass byteArrayOutputStream = clazz.parent().getCodeModel().ref( ByteArrayOutputStream.class );
857            final JClass byteArrayInputStream = clazz.parent().getCodeModel().ref( ByteArrayInputStream.class );
858            final JClass objectOutputStream = clazz.parent().getCodeModel().ref( ObjectOutputStream.class );
859            final JClass objectInputStream = clazz.parent().getCodeModel().ref( ObjectInputStream.class );
860            final JClass ioException = clazz.parent().getCodeModel().ref( IOException.class );
861            final JClass invalidClass = clazz.parent().getCodeModel().ref( InvalidClassException.class );
862            final JClass notSerializable = clazz.parent().getCodeModel().ref( NotSerializableException.class );
863            final JClass streamCorrupted = clazz.parent().getCodeModel().ref( StreamCorruptedException.class );
864            final JClass securityException = clazz.parent().getCodeModel().ref( SecurityException.class );
865            final JClass optionalData = clazz.parent().getCodeModel().ref( OptionalDataException.class );
866            final JClass classNotFound = clazz.parent().getCodeModel().ref( ClassNotFoundException.class );
867            final JClass assertionError = clazz.parent().getCodeModel().ref( AssertionError.class );
868            final JType[] signature =
869            {
870                serializable
871            };
872    
873            final String methodName = "copyOf";
874            final int mod = this.getVisibilityModifier();
875    
876            if ( mod != JMod.PRIVATE )
877            {
878                for ( JMethod m : clazz._package().objectFactory().methods() )
879                {
880                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
881                    {
882                        return clazz._package().objectFactory().staticInvoke( m );
883                    }
884                }
885            }
886            else
887            {
888                for ( JMethod m : clazz.implClass.methods() )
889                {
890                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
891                    {
892                        return JExpr.invoke( m );
893                    }
894                }
895            }
896    
897            final JMethod m =
898                ( mod != JMod.PRIVATE
899                  ? clazz._package().objectFactory().method( JMod.STATIC | mod, serializable, methodName )
900                  : clazz.implClass.method( JMod.STATIC | mod, serializable, methodName ) );
901    
902            final JVar s = m.param( JMod.FINAL, serializable, "serializable" );
903    
904            m.javadoc().append( "Creates and returns a deep copy of a given {@code Serializable}." );
905            m.javadoc().addParam( s ).append( "The instance to copy or {@code null}." );
906            m.javadoc().addReturn().append(
907                "A deep copy of {@code serializable} or {@code null} if {@code serializable} is {@code null}." );
908    
909            m.body().directStatement( "// " + getMessage( "title" ) );
910    
911            final JConditional sNotNull = m.body()._if( s.ne( JExpr._null() ) );
912            final JTryBlock tryClone = sNotNull._then()._try();
913    
914            final JVar byteArrayOutput = tryClone.body().decl(
915                JMod.FINAL, byteArrayOutputStream, "byteArrayOutput", JExpr._new( byteArrayOutputStream ) );
916    
917            final JVar objectOutput = tryClone.body().decl(
918                JMod.FINAL, objectOutputStream, "out", JExpr._new( objectOutputStream ).arg( byteArrayOutput ) );
919    
920            tryClone.body().add( objectOutput.invoke( "writeObject" ).arg( s ) );
921            tryClone.body().add( objectOutput.invoke( "close" ) );
922    
923            final JVar byteArrayInput = tryClone.body().decl(
924                JMod.FINAL, byteArrayInputStream, "byteArrayInput",
925                JExpr._new( byteArrayInputStream ).arg( byteArrayOutput.invoke( "toByteArray" ) ) );
926    
927            final JVar objectInput = tryClone.body().decl(
928                JMod.FINAL, objectInputStream, "in", JExpr._new( objectInputStream ).arg( byteArrayInput ) );
929    
930            final JVar copy = tryClone.body().decl(
931                JMod.FINAL, serializable, "copy", JExpr.cast( serializable, objectInput.invoke( "readObject" ) ) );
932    
933            tryClone.body().invoke( objectInput, "close" );
934            tryClone.body()._return( copy );
935    
936            final JExpression assertionErrorMsg =
937                JExpr.lit( "Unexpected instance during copying object '" ).plus( s ).plus( JExpr.lit( "'." ) );
938    
939            final JCatchBlock catchSecurityException = tryClone._catch( securityException );
940            catchSecurityException.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
941                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchSecurityException.param( "e" ) ) ) );
942    
943            final JCatchBlock catchClassNotFound = tryClone._catch( classNotFound );
944            catchClassNotFound.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
945                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchClassNotFound.param( "e" ) ) ) );
946    
947            final JCatchBlock catchInvalidClass = tryClone._catch( invalidClass );
948            catchInvalidClass.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
949                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchInvalidClass.param( "e" ) ) ) );
950    
951            final JCatchBlock catchNotSerializable = tryClone._catch( notSerializable );
952            catchNotSerializable.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
953                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchNotSerializable.param( "e" ) ) ) );
954    
955            final JCatchBlock catchStreamCorrupted = tryClone._catch( streamCorrupted );
956            catchStreamCorrupted.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
957                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchStreamCorrupted.param( "e" ) ) ) );
958    
959            final JCatchBlock catchOptionalData = tryClone._catch( optionalData );
960            catchOptionalData.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
961                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchOptionalData.param( "e" ) ) ) );
962    
963            final JCatchBlock catchIOException = tryClone._catch( ioException );
964            catchIOException.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
965                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchIOException.param( "e" ) ) ) );
966    
967            m.body()._return( JExpr._null() );
968            this.methodCount = this.methodCount.add( BigInteger.ONE );
969            return ( mod != JMod.PRIVATE ? clazz._package().objectFactory().staticInvoke( m ) : JExpr.invoke( m ) );
970        }
971    
972        private JInvocation getCopyOfObjectInvocation( final ClassOutline clazz )
973        {
974            final JClass object = clazz.parent().getCodeModel().ref( Object.class );
975            final JClass element = clazz.parent().getCodeModel().ref( Element.class );
976            final JClass jaxbElement = clazz.parent().getCodeModel().ref( JAXBElement.class );
977            final JClass noSuchMethod = clazz.parent().getCodeModel().ref( NoSuchMethodException.class );
978            final JClass illegalAccess = clazz.parent().getCodeModel().ref( IllegalAccessException.class );
979            final JClass invocationTarget = clazz.parent().getCodeModel().ref( InvocationTargetException.class );
980            final JClass securityException = clazz.parent().getCodeModel().ref( SecurityException.class );
981            final JClass illegalArgument = clazz.parent().getCodeModel().ref( IllegalArgumentException.class );
982            final JClass initializerError = clazz.parent().getCodeModel().ref( ExceptionInInitializerError.class );
983            final JClass assertionError = clazz.parent().getCodeModel().ref( AssertionError.class );
984            final JClass classArray = clazz.parent().getCodeModel().ref( Class[].class );
985            final JClass objectArray = clazz.parent().getCodeModel().ref( Object[].class );
986            final JClass serializable = clazz.parent().getCodeModel().ref( Serializable.class );
987    
988            final String methodName = "copyOf";
989            final int mod = this.getVisibilityModifier();
990            final JType[] signature = new JType[]
991            {
992                object
993            };
994    
995            if ( mod != JMod.PRIVATE )
996            {
997                for ( JMethod m : clazz._package().objectFactory().methods() )
998                {
999                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1000                    {
1001                        return clazz._package().objectFactory().staticInvoke( m );
1002                    }
1003                }
1004            }
1005            else
1006            {
1007                for ( JMethod m : clazz.implClass.methods() )
1008                {
1009                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1010                    {
1011                        return JExpr.invoke( m );
1012                    }
1013                }
1014            }
1015    
1016            final JMethod m =
1017                ( mod != JMod.PRIVATE
1018                  ? clazz._package().objectFactory().method( JMod.STATIC | mod, object, methodName )
1019                  : clazz.implClass.method( JMod.STATIC | mod, object, methodName ) );
1020    
1021            final JVar o = m.param( JMod.FINAL, object, "o" );
1022            final Set<Class<?>> exceptions = new HashSet<Class<?>>();
1023    
1024            m.javadoc().append( "Creates and returns a deep copy of a given object." );
1025            m.javadoc().addParam( o ).append( "The instance to copy or {@code null}." );
1026            m.javadoc().addReturn().append( "A deep copy of {@code o} or {@code null} if {@code o} is {@code null}." );
1027            m.annotate( SuppressWarnings.class ).param( "value", "unchecked" );
1028    
1029            m.body().directStatement( "// " + getMessage( "title" ) );
1030    
1031            final JBlock copyBlock = new JBlock( false, false );
1032            final JConditional objectNotNull = copyBlock._if( o.ne( JExpr._null() ) );
1033    
1034            final JConditional isPrimitive =
1035                objectNotNull._then()._if( JExpr.invoke( JExpr.invoke( o, "getClass" ), "isPrimitive" ) );
1036    
1037            isPrimitive._then()._return( o );
1038    
1039            final JConditional isArray =
1040                objectNotNull._then()._if( JExpr.invoke( JExpr.invoke( o, "getClass" ), "isArray" ) );
1041    
1042            isArray._then()._return( this.getCopyOfArrayInvocation( clazz ).arg( o ) );
1043    
1044            objectNotNull._then().directStatement( "// Immutable types." );
1045    
1046            for ( String immutableType : this.immutableTypes )
1047            {
1048                final JClass immutable = clazz.parent().getCodeModel().ref( immutableType );
1049                objectNotNull._then()._if( o._instanceof( immutable ) )._then()._return( o );
1050            }
1051    
1052            objectNotNull._then().directStatement( "// String based types." );
1053    
1054            for ( String stringType : this.stringTypes )
1055            {
1056                final JClass string = clazz.parent().getCodeModel().ref( stringType );
1057                final Class<?> c = this.getClass( stringType );
1058    
1059                if ( c != null )
1060                {
1061                    try
1062                    {
1063                        exceptions.addAll( Arrays.asList( c.getConstructor( String.class ).getExceptionTypes() ) );
1064                    }
1065                    catch ( final NoSuchMethodException e )
1066                    {
1067                        // Generated code won't compile.
1068                    }
1069                }
1070    
1071                objectNotNull._then()._if( o._instanceof( string ) )._then()._return(
1072                    JExpr._new( string ).arg( o.invoke( "toString" ) ) );
1073    
1074            }
1075    
1076            objectNotNull._then().directStatement( "// Cloneable types." );
1077    
1078            for ( String cloneableType : this.cloneableTypes )
1079            {
1080                final JClass cloneable = clazz.parent().getCodeModel().ref( cloneableType );
1081                final Class<?> c = this.getClass( cloneableType );
1082    
1083                if ( c != null )
1084                {
1085                    try
1086                    {
1087                        exceptions.addAll( Arrays.asList( c.getMethod( "clone" ).getExceptionTypes() ) );
1088                    }
1089                    catch ( final NoSuchMethodException e )
1090                    {
1091                        // Generated code won't compile.
1092                    }
1093                }
1094    
1095                objectNotNull._then()._if( o._instanceof( cloneable ) )._then()._return(
1096                    JExpr.invoke( JExpr.cast( cloneable, o ), ( "clone" ) ) );
1097    
1098            }
1099    
1100            final JConditional instanceOfDOMElement = objectNotNull._then()._if( o._instanceof( element ) );
1101            instanceOfDOMElement._then()._return( JExpr.cast( element, JExpr.invoke(
1102                JExpr.cast( element, o ), "cloneNode" ).arg( JExpr.TRUE ) ) );
1103    
1104            final JConditional instanceOfElement = objectNotNull._then()._if( o._instanceof( jaxbElement ) );
1105            instanceOfElement._then()._return( this.getCopyOfJaxbElementInvocation( clazz ).
1106                arg( JExpr.cast( jaxbElement, o ) ) );
1107    
1108            final JTryBlock tryCloneMethod = objectNotNull._then()._try();
1109            tryCloneMethod.body()._return( JExpr.invoke( JExpr.invoke( JExpr.invoke( o, "getClass" ), "getMethod" ).
1110                arg( "clone" ).arg( JExpr.cast( classArray, JExpr._null() ) ), "invoke" ).arg( o ).
1111                arg( JExpr.cast( objectArray, JExpr._null() ) ) );
1112    
1113            final JExpression assertionErrorMsg =
1114                JExpr.lit( "Unexpected instance during copying object '" ).plus( o ).plus( JExpr.lit( "'." ) );
1115    
1116            final JCatchBlock catchNoSuchMethod = tryCloneMethod._catch( noSuchMethod );
1117            final JConditional instanceOfSerializable = catchNoSuchMethod.body()._if( o._instanceof( serializable ) );
1118            instanceOfSerializable._then()._return( this.getCopyOfSerializableInvocation( clazz ).
1119                arg( JExpr.cast( serializable, o ) ) );
1120    
1121            catchNoSuchMethod.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1122    
1123            catchNoSuchMethod.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1124                arg( assertionErrorMsg ).invoke( "initCause" ).
1125                arg( catchNoSuchMethod.param( "e" ) ) ) );
1126    
1127            final JCatchBlock catchIllegalAccess = tryCloneMethod._catch( illegalAccess );
1128            catchIllegalAccess.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1129    
1130            catchIllegalAccess.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1131                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchIllegalAccess.param( "e" ) ) ) );
1132    
1133            final JCatchBlock catchInvocationTarget = tryCloneMethod._catch( invocationTarget );
1134            catchInvocationTarget.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1135    
1136            catchInvocationTarget.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1137                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchInvocationTarget.param( "e" ) ) ) );
1138    
1139            final JCatchBlock catchSecurityException = tryCloneMethod._catch( securityException );
1140            catchSecurityException.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1141    
1142            catchSecurityException.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1143                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchSecurityException.param( "e" ) ) ) );
1144    
1145            final JCatchBlock catchIllegalArgument = tryCloneMethod._catch( illegalArgument );
1146            catchIllegalArgument.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1147    
1148            catchIllegalArgument.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1149                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchIllegalArgument.param( "e" ) ) ) );
1150    
1151            final JCatchBlock catchInitializerError = tryCloneMethod._catch( initializerError );
1152            catchInitializerError.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1153    
1154            catchInitializerError.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1155                arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchInitializerError.param( "e" ) ) ) );
1156    
1157            copyBlock._return( JExpr._null() );
1158    
1159            if ( !exceptions.isEmpty() )
1160            {
1161                final JTryBlock tryCopy = m.body()._try();
1162                tryCopy.body().add( copyBlock );
1163    
1164                for ( Class<?> e : exceptions )
1165                {
1166                    final JCatchBlock catchBlock = tryCopy._catch( clazz.parent().getCodeModel().ref( e ) );
1167                    catchBlock.body()._throw( JExpr.cast( assertionError, JExpr._new( assertionError ).
1168                        arg( assertionErrorMsg ).invoke( "initCause" ).arg( catchBlock.param( "e" ) ) ) );
1169    
1170                }
1171            }
1172            else
1173            {
1174                m.body().add( copyBlock );
1175            }
1176    
1177            this.methodCount = this.methodCount.add( BigInteger.ONE );
1178            return ( mod != JMod.PRIVATE ? clazz._package().objectFactory().staticInvoke( m ) : JExpr.invoke( m ) );
1179        }
1180    
1181        private JInvocation getCopyOfElementInfoInvocation( final FieldOutline fieldOutline, final CElementInfo element )
1182        {
1183            final JType elementType = element.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION );
1184            final JType[] signature =
1185            {
1186                elementType
1187            };
1188    
1189            final String methodName;
1190            if ( element.hasClass() )
1191            {
1192                methodName = "copyOf" + element.shortName();
1193            }
1194            else
1195            {
1196                methodName = "copyOf" + this.getMethodNamePart(
1197                    element.getContentType().toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ) ) + "Element";
1198    
1199            }
1200    
1201            final int mod = this.getVisibilityModifier();
1202            boolean needsToCatchException = false;
1203    
1204            if ( mod != JMod.PRIVATE )
1205            {
1206                for ( JMethod m : fieldOutline.parent()._package().objectFactory().methods() )
1207                {
1208                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1209                    {
1210                        return fieldOutline.parent()._package().objectFactory().staticInvoke( m );
1211                    }
1212                }
1213            }
1214            else
1215            {
1216                for ( JMethod m : fieldOutline.parent().implClass.methods() )
1217                {
1218                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1219                    {
1220                        return JExpr.invoke( m );
1221                    }
1222                }
1223            }
1224    
1225            final JMethod m =
1226                ( mod != JMod.PRIVATE
1227                  ? fieldOutline.parent()._package().objectFactory().method( JMod.STATIC | mod, elementType, methodName )
1228                  : fieldOutline.parent().implClass.method( JMod.STATIC | mod, elementType, methodName ) );
1229    
1230            final JVar e = m.param( JMod.FINAL, elementType, "e" );
1231    
1232            m.javadoc().append( "Creates and returns a deep copy of a given {@code " + elementType.binaryName()
1233                                + "} instance." );
1234    
1235            m.javadoc().addParam( e ).append( "The instance to copy or {@code null}." );
1236            m.javadoc().addReturn().append( "A deep copy of {@code e} or {@code null} if {@code e} is {@code null}." );
1237            m.annotate( SuppressWarnings.class ).param( "value", "unchecked" );
1238    
1239            final JBlock body = new JBlock( false, false );
1240            body.directStatement( "// " + getMessage( "title" ) );
1241    
1242            final JConditional elementNotNull = body._if( e.ne( JExpr._null() ) );
1243    
1244            final JExpression newElement;
1245            if ( element.hasClass() )
1246            {
1247                newElement = JExpr._new( elementType ).arg( this.getCopyExpression(
1248                    fieldOutline, element.getContentType(), elementNotNull._then(),
1249                    JExpr.cast( element.getContentType().toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ),
1250                                JExpr.invoke( e, "getValue" ) ), true ) );
1251    
1252                needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1253            }
1254            else
1255            {
1256                newElement = JExpr._new( elementType ).
1257                    arg( JExpr.invoke( e, "getName" ) ).
1258                    arg( JExpr.invoke( e, "getDeclaredType" ) ).
1259                    arg( JExpr.invoke( e, "getScope" ) ).
1260                    arg( JExpr.invoke( e, "getValue" ) );
1261    
1262            }
1263    
1264            final JVar copy = elementNotNull._then().decl( JMod.FINAL, elementType, "copy", newElement );
1265            elementNotNull._then().add( copy.invoke( "setNil" ).arg( e.invoke( "isNil" ) ) );
1266    
1267            if ( !element.hasClass() )
1268            {
1269                elementNotNull._then().add( copy.invoke( "setValue" ).arg( this.getCopyExpression(
1270                    fieldOutline, element.getContentType(), elementNotNull._then(),
1271                    JExpr.cast( element.getContentType().toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ),
1272                                copy.invoke( "getValue" ) ), true ) ) );
1273    
1274                needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1275            }
1276    
1277            elementNotNull._then()._return( copy );
1278            body._return( JExpr._null() );
1279    
1280            if ( needsToCatchException )
1281            {
1282                final JTryBlock tryCopy = m.body()._try();
1283                tryCopy.body().add( body );
1284    
1285                final JCatchBlock catchException =
1286                    tryCopy._catch( fieldOutline.parent().parent().getCodeModel().ref( Exception.class ) );
1287    
1288                final JVar ex = catchException.param( "e" );
1289                catchException.body()._throw( JExpr._new( fieldOutline.parent().parent().getCodeModel().
1290                    ref( AssertionError.class ) ).arg( ex ) );
1291    
1292            }
1293            else
1294            {
1295                m.body().add( body );
1296            }
1297    
1298            this.methodCount = this.methodCount.add( BigInteger.ONE );
1299            return ( mod != JMod.PRIVATE
1300                     ? fieldOutline.parent()._package().objectFactory().staticInvoke( m ) : JExpr.invoke( m ) );
1301    
1302        }
1303    
1304        private JInvocation getCopyOfArrayInfoInvocation( final FieldOutline fieldOutline, final CArrayInfo array )
1305        {
1306            final JType arrayType =
1307                ( array.getAdapterUse() != null && array.getAdapterUse().customType != null
1308                  ? array.getAdapterUse().customType.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION )
1309                  : array.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ) );
1310    
1311            final JType itemType = array.getItemType().toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION );
1312            final JType[] signature =
1313            {
1314                arrayType
1315            };
1316    
1317            final String methodName = "copyOf" + fieldOutline.getPropertyInfo().getName( true );
1318            final int mod = this.getVisibilityModifier();
1319            boolean needsToCatchException = false;
1320    
1321            if ( mod != JMod.PRIVATE )
1322            {
1323                for ( JMethod m : fieldOutline.parent()._package().objectFactory().methods() )
1324                {
1325                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1326                    {
1327                        return fieldOutline.parent()._package().objectFactory().staticInvoke( m );
1328                    }
1329                }
1330            }
1331            else
1332            {
1333                for ( JMethod m : fieldOutline.parent().implClass.methods() )
1334                {
1335                    if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1336                    {
1337                        return JExpr.invoke( m );
1338                    }
1339                }
1340            }
1341    
1342            final JMethod m =
1343                ( mod != JMod.PRIVATE
1344                  ? fieldOutline.parent()._package().objectFactory().method( JMod.STATIC | mod, arrayType, methodName )
1345                  : fieldOutline.parent().implClass.method( JMod.STATIC | mod, arrayType, methodName ) );
1346    
1347            final JVar a = m.param( JMod.FINAL, arrayType, "array" );
1348    
1349            m.javadoc().append(
1350                "Creates and returns a deep copy of a given {@code " + arrayType.binaryName() + "} instance." );
1351    
1352            m.javadoc().addParam( a ).append( "The instance to copy or {@code null}." );
1353            m.javadoc().addReturn().append(
1354                "A deep copy of {@code array} or {@code null} if {@code array} is {@code null}." );
1355    
1356            final JBlock body = new JBlock( false, false );
1357            body.directStatement( "// " + getMessage( "title" ) );
1358    
1359            final JConditional arrayNotNull = body._if( a.ne( JExpr._null() ) );
1360            final JVar copy = arrayNotNull._then().decl( arrayType, "copy", JExpr.newArray( itemType, a.ref( "length" ) ) );
1361            final JForLoop forEachItem = arrayNotNull._then()._for();
1362            final JVar i = forEachItem.init(
1363                fieldOutline.parent().parent().getCodeModel().INT, "i", a.ref( "length" ).minus( JExpr.lit( 1 ) ) );
1364    
1365            forEachItem.test( i.gte( JExpr.lit( 0 ) ) );
1366            forEachItem.update( i.decr() );
1367    
1368            final JExpression copyExpr = this.getCopyExpression(
1369                fieldOutline, array.getItemType(), forEachItem.body(), a.component( i ), true );
1370    
1371            needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1372    
1373            forEachItem.body().assign( copy.component( i ), copyExpr );
1374            arrayNotNull._then()._return( copy );
1375            body._return( JExpr._null() );
1376    
1377            if ( needsToCatchException )
1378            {
1379                final JTryBlock tryCopy = m.body()._try();
1380                tryCopy.body().add( body );
1381    
1382                final JCatchBlock catchException =
1383                    tryCopy._catch( fieldOutline.parent().parent().getCodeModel().ref( Exception.class ) );
1384    
1385                final JVar ex = catchException.param( "e" );
1386                catchException.body()._throw( JExpr._new( fieldOutline.parent().parent().getCodeModel().
1387                    ref( AssertionError.class ) ).arg( ex ) );
1388    
1389            }
1390            else
1391            {
1392                m.body().add( body );
1393            }
1394    
1395            this.methodCount = this.methodCount.add( BigInteger.ONE );
1396            return ( mod != JMod.PRIVATE
1397                     ? fieldOutline.parent()._package().objectFactory().staticInvoke( m ) : JExpr.invoke( m ) );
1398    
1399        }
1400    
1401        private JMethod getCopyOfPropertyMethod( final FieldOutline field )
1402        {
1403            final String methodName = "copyOf" + field.getPropertyInfo().getName( true );
1404            final JType[] signature = new JType[]
1405            {
1406                field.getRawType()
1407            };
1408    
1409            for ( JMethod m : field.parent().implClass.methods() )
1410            {
1411                if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1412                {
1413                    return m;
1414                }
1415            }
1416    
1417            final JClass jaxbElement = field.parent().parent().getCodeModel().ref( JAXBElement.class );
1418            final JClass assertionError = field.parent().parent().getCodeModel().ref( AssertionError.class );
1419            final JMethod m = field.parent().implClass.method(
1420                this.getVisibilityModifier() | JMod.STATIC, field.getRawType(), methodName );
1421    
1422            final JVar source = m.param( JMod.FINAL, field.getRawType(), "source" );
1423            m.javadoc().append( "Creates and returns a deep copy of property {@code "
1424                                + field.getPropertyInfo().getName( true ) + "}." );
1425    
1426            m.javadoc().addParam( source ).append( "The source to copy from or {@code null}." );
1427            m.javadoc().addReturn().append(
1428                "A deep copy of {@code source} or {@code null} if {@code source} is {@code null}." );
1429    
1430            m.annotate( SuppressWarnings.class ).param( "value", "unchecked" );
1431    
1432            final JBlock body = new JBlock( false, false );
1433            body.directStatement( "// " + getMessage( "title" ) );
1434    
1435            final JConditional sourceNotNull = body._if( source.ne( JExpr._null() ) );
1436    
1437    //        m.body()._if( source.eq( JExpr._null() ) )._then()._throw( JExpr._new( nullPointerException ).arg( "source" ) );
1438    //        m.body()._if( target.eq( JExpr._null() ) )._then()._throw( JExpr._new( nullPointerException ).arg( "target" ) );
1439    
1440            final List<CClassInfo> referencedClassInfos =
1441                new ArrayList<CClassInfo>( field.getPropertyInfo().ref().size() );
1442    
1443            final List<CElementInfo> referencedElementInfos =
1444                new ArrayList<CElementInfo>( field.getPropertyInfo().ref().size() );
1445    
1446            final List<CElementInfo> referencedElementInfosWithClass =
1447                new ArrayList<CElementInfo>( field.getPropertyInfo().ref().size() );
1448    
1449            final List<CTypeInfo> referencedTypeInfos =
1450                new ArrayList<CTypeInfo>( field.getPropertyInfo().ref().size() );
1451    
1452            final List<JType> referencedClassTypes =
1453                new ArrayList<JType>( field.getPropertyInfo().ref().size() );
1454    
1455            final List<JType> referencedContentTypes =
1456                new ArrayList<JType>( field.getPropertyInfo().ref().size() );
1457    
1458            final List<JType> referencedTypes =
1459                new ArrayList<JType>( field.getPropertyInfo().ref().size() );
1460    
1461            for ( CTypeInfo type : field.getPropertyInfo().ref() )
1462            {
1463                if ( type instanceof CElementInfo )
1464                {
1465                    final CElementInfo e = (CElementInfo) type;
1466                    if ( e.hasClass() )
1467                    {
1468                        referencedElementInfosWithClass.add( e );
1469                    }
1470                    else
1471                    {
1472                        final JType contentType =
1473                            e.getContentType().toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1474    
1475                        if ( !referencedContentTypes.contains( contentType ) )
1476                        {
1477                            referencedContentTypes.add( contentType );
1478                            referencedElementInfos.add( e );
1479                        }
1480                    }
1481                }
1482                else if ( type instanceof CClassInfo )
1483                {
1484                    final CClassInfo c = (CClassInfo) type;
1485                    final JClass classType = c.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1486    
1487                    if ( !referencedClassTypes.contains( classType ) )
1488                    {
1489                        referencedClassTypes.add( classType );
1490                        referencedClassInfos.add( c );
1491                    }
1492                }
1493                else
1494                {
1495                    final JType javaType = type.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1496                    if ( !referencedTypes.contains( javaType ) )
1497                    {
1498                        referencedTypes.add( javaType );
1499                        referencedTypeInfos.add( type );
1500                    }
1501                }
1502            }
1503    
1504            Collections.sort( referencedClassInfos, new CClassInfoComparator( field.parent().parent() ) );
1505            Collections.sort( referencedElementInfos, new CElementInfoComparator( field.parent().parent(), false ) );
1506            Collections.sort( referencedElementInfosWithClass, new CElementInfoComparator( field.parent().parent(), true ) );
1507            Collections.sort( referencedTypeInfos, new CTypeInfoComparator( field.parent().parent() ) );
1508            Collections.reverse( referencedClassInfos );
1509            Collections.reverse( referencedElementInfos );
1510            Collections.reverse( referencedElementInfosWithClass );
1511            Collections.reverse( referencedTypeInfos );
1512    
1513            boolean needsToCatchException = false;
1514    
1515            if ( !( referencedElementInfos.isEmpty() && referencedElementInfosWithClass.isEmpty() ) )
1516            {
1517                final JBlock elementBlock = sourceNotNull._then()._if( source._instanceof( jaxbElement ) )._then();
1518                if ( !referencedElementInfosWithClass.isEmpty() )
1519                {
1520                    elementBlock.directStatement( "// Referenced elements with classes." );
1521                    for ( CElementInfo elementInfo : referencedElementInfosWithClass )
1522                    {
1523                        final JType elementType = elementInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1524                        final JConditional ifInstanceOf = elementBlock._if( source._instanceof( elementType ) );
1525                        final JExpression copyExpr = this.getCopyExpression(
1526                            field, elementInfo, ifInstanceOf._then(), JExpr.cast( elementType, source ), false );
1527    
1528                        needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1529    
1530                        if ( copyExpr == null )
1531                        {
1532                            this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1533                                      field.parent().implClass.binaryName() );
1534    
1535                        }
1536                        else
1537                        {
1538                            ifInstanceOf._then()._return( copyExpr );
1539                        }
1540                    }
1541                }
1542    
1543                if ( !referencedElementInfos.isEmpty() )
1544                {
1545                    elementBlock.directStatement( "// Referenced elements without classes." );
1546                    for ( CElementInfo elementInfo : referencedElementInfos )
1547                    {
1548                        final JType contentType =
1549                            ( elementInfo.getAdapterUse() != null && elementInfo.getAdapterUse().customType != null
1550                              ? elementInfo.getAdapterUse().customType.toType( field.parent().parent(),
1551                                                                               Aspect.IMPLEMENTATION )
1552                              : elementInfo.getContentType().toType( field.parent().parent(), Aspect.IMPLEMENTATION ) );
1553    
1554                        final JConditional ifInstanceOf = elementBlock._if( JExpr.invoke( JExpr.cast(
1555                            jaxbElement, source ), "getValue" )._instanceof( contentType ) );
1556    
1557                        final JExpression copyExpr = this.getCopyExpression(
1558                            field, elementInfo, ifInstanceOf._then(), JExpr.cast( jaxbElement, source ), false );
1559    
1560                        needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1561    
1562                        if ( copyExpr == null )
1563                        {
1564                            this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1565                                      field.parent().implClass.binaryName() );
1566    
1567                        }
1568                        else
1569                        {
1570                            ifInstanceOf._then()._return( copyExpr );
1571                        }
1572                    }
1573                }
1574            }
1575    
1576            for ( CClassInfo classInfo : referencedClassInfos )
1577            {
1578                final JType javaType =
1579                    ( classInfo.getAdapterUse() != null && classInfo.getAdapterUse().customType != null
1580                      ? classInfo.getAdapterUse().customType.toType( field.parent().parent(), Aspect.IMPLEMENTATION )
1581                      : classInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION ) );
1582    
1583                final JConditional ifInstanceOf = sourceNotNull._then()._if( source._instanceof( javaType ) );
1584    
1585                final JExpression copyExpr =
1586                    this.getCopyExpression( field, classInfo, ifInstanceOf._then(), JExpr.cast( javaType, source ), false );
1587    
1588                needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1589    
1590                if ( copyExpr == null )
1591                {
1592                    this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1593                              field.parent().implClass.binaryName() );
1594    
1595                }
1596                else
1597                {
1598                    ifInstanceOf._then()._return( copyExpr );
1599                }
1600            }
1601    
1602            for ( CTypeInfo typeInfo : referencedTypeInfos )
1603            {
1604                final JType javaType = typeInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1605                final JConditional ifInstanceOf = sourceNotNull._then()._if( source._instanceof( javaType ) );
1606                final JExpression copyExpr =
1607                    this.getCopyExpression( field, typeInfo, ifInstanceOf._then(), JExpr.cast( javaType, source ), false );
1608    
1609                needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1610    
1611                if ( copyExpr == null )
1612                {
1613                    this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1614                              field.parent().implClass.binaryName() );
1615    
1616                }
1617                else
1618                {
1619                    ifInstanceOf._then()._return( copyExpr );
1620                }
1621            }
1622    
1623            sourceNotNull._then().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1624            sourceNotNull._then()._throw( JExpr._new( assertionError ).arg( JExpr.lit( "Unexpected instance '" ).
1625                plus( source ).plus( JExpr.lit( "' for property '" + field.getPropertyInfo().getName( true )
1626                                                + "' of class '" + field.parent().implClass.binaryName() + "'." ) ) ) );
1627    
1628            body._return( JExpr._null() );
1629    
1630            if ( needsToCatchException )
1631            {
1632                final JTryBlock tryCopy = m.body()._try();
1633                tryCopy.body().add( body );
1634    
1635                final JCatchBlock catchException =
1636                    tryCopy._catch( field.parent().parent().getCodeModel().ref( Exception.class ) );
1637    
1638                final JVar ex = catchException.param( "e" );
1639                catchException.body()._throw( JExpr._new( field.parent().parent().getCodeModel().
1640                    ref( AssertionError.class ) ).arg( ex ) );
1641    
1642            }
1643            else
1644            {
1645                m.body().add( body );
1646            }
1647    
1648            this.methodCount = this.methodCount.add( BigInteger.ONE );
1649            return m;
1650        }
1651    
1652        private JMethod getCopyOfCollectionMethod( final FieldOutline field )
1653        {
1654            final String methodName;
1655            final JType[] signature;
1656    
1657            if ( field.getRawType().isArray() )
1658            {
1659                methodName = "copyOf" + field.getPropertyInfo().getName( true );
1660                signature = new JType[]
1661                {
1662                    field.getRawType()
1663                };
1664    
1665            }
1666            else
1667            {
1668                methodName = "copy" + field.getPropertyInfo().getName( true );
1669                signature = new JType[]
1670                {
1671                    field.getRawType(),
1672                    field.getRawType()
1673                };
1674    
1675            }
1676    
1677            for ( JMethod m : field.parent().implClass.methods() )
1678            {
1679                if ( m.name().equals( methodName ) && m.hasSignature( signature ) )
1680                {
1681                    return m;
1682                }
1683            }
1684    
1685            final JClass object = field.parent().parent().getCodeModel().ref( Object.class );
1686            final JClass array = field.parent().parent().getCodeModel().ref( Array.class );
1687            final JClass jaxbElement = field.parent().parent().getCodeModel().ref( JAXBElement.class );
1688            final JClass nullPointerException = field.parent().parent().getCodeModel().ref( NullPointerException.class );
1689            final JClass assertionError = field.parent().parent().getCodeModel().ref( AssertionError.class );
1690    
1691            final JMethod m;
1692            if ( field.getRawType().isArray() )
1693            {
1694                m = field.parent().implClass.method( this.getVisibilityModifier() | JMod.STATIC, field.getRawType(),
1695                                                     methodName );
1696    
1697            }
1698            else
1699            {
1700                m = field.parent().implClass.method( this.getVisibilityModifier() | JMod.STATIC, Void.TYPE, methodName );
1701            }
1702    
1703            final JVar source = m.param( JMod.FINAL, field.getRawType(), "source" );
1704            final JVar target = field.getRawType().isArray() ? null : m.param( JMod.FINAL, field.getRawType(), "target" );
1705    
1706            m.body().directStatement( "// " + getMessage( "title" ) );
1707    
1708            m.javadoc().append( "Copies all values of property {@code " + field.getPropertyInfo().getName( true )
1709                                + "} deeply." );
1710    
1711            m.javadoc().addParam( source ).append( "The source to copy from." );
1712    
1713            if ( !field.getRawType().isArray() )
1714            {
1715                m.javadoc().addParam( target ).append( "The target to copy {@code source} to." );
1716                m.javadoc().addThrows( nullPointerException ).append( "if {@code target} is {@code null}." );
1717    //            m.body()._if( target.eq( JExpr._null() ) )._then()._throw(
1718    //                JExpr._new( nullPointerException ).arg( "target" ) );
1719    
1720            }
1721            else
1722            {
1723                m.javadoc().addReturn().append( "A deep copy of {@code source} or {@code null}." );
1724            }
1725    
1726            m.annotate( SuppressWarnings.class ).param( "value", "unchecked" );
1727    
1728            final JBlock body = new JBlock( false, false );
1729    
1730    //        m.body()._if( source.eq( JExpr._null() ) )._then()._throw( JExpr._new( nullPointerException ).arg( "source" ) );
1731    //        m.body()._if( target.eq( JExpr._null() ) )._then()._throw( JExpr._new( nullPointerException ).arg( "target" ) );
1732    
1733            final List<CClassInfo> referencedClassInfos =
1734                new ArrayList<CClassInfo>( field.getPropertyInfo().ref().size() );
1735    
1736            final List<CElementInfo> referencedElementInfos =
1737                new ArrayList<CElementInfo>( field.getPropertyInfo().ref().size() );
1738    
1739            final List<CElementInfo> referencedElementInfosWithClass =
1740                new ArrayList<CElementInfo>( field.getPropertyInfo().ref().size() );
1741    
1742            final List<CTypeInfo> referencedTypeInfos =
1743                new ArrayList<CTypeInfo>( field.getPropertyInfo().ref().size() );
1744    
1745            final List<JType> referencedClassTypes =
1746                new ArrayList<JType>( field.getPropertyInfo().ref().size() );
1747    
1748            final List<JType> referencedContentTypes =
1749                new ArrayList<JType>( field.getPropertyInfo().ref().size() );
1750    
1751            final List<JType> referencedTypes =
1752                new ArrayList<JType>( field.getPropertyInfo().ref().size() );
1753    
1754            for ( CTypeInfo type : field.getPropertyInfo().ref() )
1755            {
1756                if ( type instanceof CElementInfo )
1757                {
1758                    final CElementInfo e = (CElementInfo) type;
1759                    if ( e.hasClass() )
1760                    {
1761                        referencedElementInfosWithClass.add( e );
1762                    }
1763                    else
1764                    {
1765                        final JType contentType =
1766                            e.getContentType().toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1767    
1768                        if ( !referencedContentTypes.contains( contentType ) )
1769                        {
1770                            referencedContentTypes.add( contentType );
1771                            referencedElementInfos.add( e );
1772                        }
1773                    }
1774                }
1775                else if ( type instanceof CClassInfo )
1776                {
1777                    final CClassInfo c = (CClassInfo) type;
1778                    final JClass classType = c.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1779    
1780                    if ( !referencedClassTypes.contains( classType ) )
1781                    {
1782                        referencedClassTypes.add( classType );
1783                        referencedClassInfos.add( c );
1784                    }
1785                }
1786                else
1787                {
1788                    final JType javaType = type.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1789                    if ( !referencedTypes.contains( javaType ) )
1790                    {
1791                        referencedTypes.add( javaType );
1792                        referencedTypeInfos.add( type );
1793                    }
1794                }
1795            }
1796    
1797            Collections.sort( referencedClassInfos, new CClassInfoComparator( field.parent().parent() ) );
1798            Collections.sort( referencedElementInfos, new CElementInfoComparator( field.parent().parent(), false ) );
1799            Collections.sort( referencedElementInfosWithClass, new CElementInfoComparator( field.parent().parent(), true ) );
1800            Collections.sort( referencedTypeInfos, new CTypeInfoComparator( field.parent().parent() ) );
1801            Collections.reverse( referencedClassInfos );
1802            Collections.reverse( referencedElementInfos );
1803            Collections.reverse( referencedElementInfosWithClass );
1804            Collections.reverse( referencedTypeInfos );
1805    
1806            boolean needsToCatchException = false;
1807    
1808            final JForLoop copyLoop;
1809            final JVar it;
1810            final JVar next;
1811            final JVar copy;
1812            final JConditional sourceNotEmpty;
1813    
1814            if ( field.getRawType().isArray() )
1815            {
1816                sourceNotEmpty = body._if( source.ne( JExpr._null() ).cand( source.ref( "length" ).gt( JExpr.lit( 0 ) ) ) );
1817                copy = sourceNotEmpty._then().decl( JMod.FINAL, source.type(), "copy", JExpr.cast(
1818                    source.type(), array.staticInvoke( "newInstance" ).
1819                    arg( source.invoke( "getClass" ).invoke( "getComponentType" ) ).arg( source.ref( "length" ) ) ) );
1820    
1821                copyLoop = sourceNotEmpty._then()._for();
1822                it = copyLoop.init( field.parent().parent().getCodeModel().INT, "i",
1823                                    source.ref( "length" ).minus( JExpr.lit( 1 ) ) );
1824    
1825                copyLoop.test( it.gte( JExpr.lit( 0 ) ) );
1826                copyLoop.update( it.decr() );
1827                next = copyLoop.body().decl( JMod.FINAL, object, "next", source.component( it ) );
1828            }
1829            else
1830            {
1831                sourceNotEmpty = body._if( source.ne( JExpr._null() ).cand( JExpr.invoke( source, "isEmpty" ).not() ) );
1832                copyLoop = sourceNotEmpty._then()._for();
1833                it = copyLoop.init( JMod.FINAL, field.parent().parent().getCodeModel().ref( Iterator.class ).
1834                    narrow( field.parent().parent().getCodeModel().wildcard() ), "it", source.invoke( "iterator" ) );
1835    
1836                copyLoop.test( JExpr.invoke( it, "hasNext" ) );
1837                next = copyLoop.body().decl( JMod.FINAL, object, "next", JExpr.invoke( it, "next" ) );
1838                copy = null;
1839            }
1840    
1841            if ( !( referencedElementInfos.isEmpty() && referencedElementInfosWithClass.isEmpty() ) )
1842            {
1843                final JBlock copyBlock = copyLoop.body()._if( next._instanceof( jaxbElement ) )._then();
1844                if ( !referencedElementInfosWithClass.isEmpty() )
1845                {
1846                    copyBlock.directStatement( "// Referenced elements with classes." );
1847                    for ( CElementInfo elementInfo : referencedElementInfosWithClass )
1848                    {
1849                        final JType elementType = elementInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1850                        final JConditional ifInstanceOf = copyBlock._if( next._instanceof( elementType ) );
1851                        final JExpression copyExpr = this.getCopyExpression(
1852                            field, elementInfo, ifInstanceOf._then(), JExpr.cast( elementType, next ), false );
1853    
1854                        needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1855    
1856                        if ( copyExpr == null )
1857                        {
1858                            this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1859                                      field.parent().implClass.binaryName() );
1860    
1861                        }
1862                        else
1863                        {
1864                            if ( field.getRawType().isArray() )
1865                            {
1866                                ifInstanceOf._then().assign( copy.component( it ), copyExpr );
1867                            }
1868                            else
1869                            {
1870                                ifInstanceOf._then().invoke( target, "add" ).arg( copyExpr );
1871                            }
1872    
1873                            ifInstanceOf._then()._continue();
1874                        }
1875                    }
1876                }
1877    
1878                if ( !referencedElementInfos.isEmpty() )
1879                {
1880                    copyBlock.directStatement( "// Referenced elements without classes." );
1881                    for ( CElementInfo elementInfo : referencedElementInfos )
1882                    {
1883                        final JType contentType =
1884                            ( elementInfo.getAdapterUse() != null && elementInfo.getAdapterUse().customType != null
1885                              ? elementInfo.getAdapterUse().customType.toType( field.parent().parent(),
1886                                                                               Aspect.IMPLEMENTATION )
1887                              : elementInfo.getContentType().toType( field.parent().parent(), Aspect.IMPLEMENTATION ) );
1888    
1889                        final JConditional ifInstanceOf = copyBlock._if( JExpr.invoke( JExpr.cast(
1890                            jaxbElement, next ), "getValue" )._instanceof( contentType ) );
1891    
1892                        final JExpression copyExpr = this.getCopyExpression(
1893                            field, elementInfo, ifInstanceOf._then(), JExpr.cast( jaxbElement, next ), false );
1894    
1895                        needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1896    
1897                        if ( copyExpr == null )
1898                        {
1899                            this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1900                                      field.parent().implClass.binaryName() );
1901    
1902                        }
1903                        else
1904                        {
1905                            if ( field.getRawType().isArray() )
1906                            {
1907                                ifInstanceOf._then().assign( copy.component( it ), copyExpr );
1908                            }
1909                            else
1910                            {
1911                                ifInstanceOf._then().invoke( target, "add" ).arg( copyExpr );
1912                            }
1913                        }
1914    
1915                        ifInstanceOf._then()._continue();
1916                    }
1917                }
1918            }
1919    
1920            for ( CClassInfo classInfo : referencedClassInfos )
1921            {
1922                final JType javaType =
1923                    ( classInfo.getAdapterUse() != null && classInfo.getAdapterUse().customType != null
1924                      ? classInfo.getAdapterUse().customType.toType( field.parent().parent(), Aspect.IMPLEMENTATION )
1925                      : classInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION ) );
1926    
1927                final JConditional ifInstanceOf = copyLoop.body()._if( next._instanceof( javaType ) );
1928    
1929                final JExpression copyExpr = this.getCopyExpression(
1930                    field, classInfo, ifInstanceOf._then(), JExpr.cast( javaType, next ), false );
1931    
1932                needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1933    
1934                if ( copyExpr == null )
1935                {
1936                    this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1937                              field.parent().implClass.binaryName() );
1938    
1939                }
1940                else
1941                {
1942                    if ( field.getRawType().isArray() )
1943                    {
1944                        ifInstanceOf._then().assign( copy.component( it ), copyExpr );
1945                    }
1946                    else
1947                    {
1948                        ifInstanceOf._then().invoke( target, "add" ).arg( copyExpr );
1949                    }
1950                }
1951    
1952                ifInstanceOf._then()._continue();
1953            }
1954    
1955            for ( CTypeInfo typeInfo : referencedTypeInfos )
1956            {
1957                final JType javaType = typeInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
1958                final JConditional ifInstanceOf = copyLoop.body()._if( next._instanceof( javaType ) );
1959                final JExpression copyExpr = this.getCopyExpression(
1960                    field, typeInfo, ifInstanceOf._then(), JExpr.cast( javaType, next ), false );
1961    
1962                needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
1963    
1964                if ( copyExpr == null )
1965                {
1966                    this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
1967                              field.parent().implClass.binaryName() );
1968    
1969                }
1970                else
1971                {
1972                    if ( field.getRawType().isArray() )
1973                    {
1974                        ifInstanceOf._then().assign( copy.component( it ), copyExpr );
1975                    }
1976                    else
1977                    {
1978                        ifInstanceOf._then().invoke( target, "add" ).arg( copyExpr );
1979                    }
1980                }
1981    
1982                ifInstanceOf._then()._continue();
1983            }
1984    
1985            copyLoop.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
1986            copyLoop.body()._throw( JExpr._new( assertionError ).arg( JExpr.lit( "Unexpected instance '" ).plus(
1987                next ).plus( JExpr.lit( "' for property '" + field.getPropertyInfo().getName( true ) + "' of class '"
1988                                        + field.parent().implClass.binaryName() + "'." ) ) ) );
1989    
1990            if ( field.getRawType().isArray() )
1991            {
1992                sourceNotEmpty._then()._return( copy );
1993                body._return( JExpr._null() );
1994            }
1995    
1996            if ( needsToCatchException )
1997            {
1998                final JTryBlock tryCopy = m.body()._try();
1999                tryCopy.body().add( body );
2000    
2001                final JCatchBlock catchException =
2002                    tryCopy._catch( field.parent().parent().getCodeModel().ref( Exception.class ) );
2003    
2004                final JVar ex = catchException.param( "e" );
2005                catchException.body()._throw( JExpr._new( field.parent().parent().getCodeModel().
2006                    ref( AssertionError.class ) ).arg( ex ) );
2007    
2008            }
2009            else
2010            {
2011                m.body().add( body );
2012            }
2013    
2014            this.methodCount = this.methodCount.add( BigInteger.ONE );
2015            return m;
2016        }
2017    
2018        private JExpression getCopyExpression( final FieldOutline fieldOutline, final CTypeInfo type,
2019                                               final JBlock block, final JExpression sourceExpr,
2020                                               final boolean sourceMaybeNull )
2021        {
2022            JExpression expr = null;
2023            this.tryCatchCopyExpression = false;
2024    
2025            if ( type instanceof CBuiltinLeafInfo )
2026            {
2027                expr = this.getBuiltinCopyExpression(
2028                    fieldOutline, (CBuiltinLeafInfo) type, block, sourceExpr, sourceMaybeNull );
2029    
2030            }
2031            else if ( type instanceof CWildcardTypeInfo )
2032            {
2033                expr = this.getWildcardCopyExpression(
2034                    fieldOutline, (CWildcardTypeInfo) type, block, sourceExpr, sourceMaybeNull );
2035    
2036            }
2037            else if ( type instanceof CClassInfo )
2038            {
2039                expr = this.getClassInfoCopyExpression(
2040                    fieldOutline, (CClassInfo) type, block, sourceExpr, sourceMaybeNull );
2041    
2042            }
2043            else if ( type instanceof CEnumLeafInfo )
2044            {
2045                expr = this.getEnumLeafInfoCopyExpression( fieldOutline, (CEnumLeafInfo) type, block, sourceExpr );
2046            }
2047            else if ( type instanceof CArrayInfo )
2048            {
2049                expr = this.getArrayCopyExpression( fieldOutline, (CArrayInfo) type, block, sourceExpr );
2050            }
2051            else if ( type instanceof CElementInfo )
2052            {
2053                expr = this.getElementCopyExpression( fieldOutline, (CElementInfo) type, block, sourceExpr );
2054            }
2055            else if ( type instanceof CNonElement )
2056            {
2057                expr = this.getNonElementCopyExpression(
2058                    fieldOutline, (CNonElement) type, block, sourceExpr, sourceMaybeNull );
2059    
2060            }
2061            else if ( type instanceof CAdapterInfo )
2062            {
2063                expr = this.getAdapterInfoCopyExpression( fieldOutline, (CAdapterInfo) type, block, sourceExpr );
2064            }
2065    
2066            if ( expr != null )
2067            {
2068                this.expressionCount = this.expressionCount.add( BigInteger.ONE );
2069            }
2070    
2071            return expr;
2072        }
2073    
2074        private JExpression getBuiltinCopyExpression( final FieldOutline fieldOutline, final CBuiltinLeafInfo type,
2075                                                      final JBlock block, final JExpression sourceExpr,
2076                                                      final boolean sourceMaybeNull )
2077        {
2078            JExpression expr = null;
2079    
2080            block.directStatement( "// CBuiltinLeafInfo: " + type.toType( fieldOutline.parent().parent(),
2081                                                                          Aspect.IMPLEMENTATION ).binaryName() );
2082    
2083            if ( type == CBuiltinLeafInfo.ANYTYPE )
2084            {
2085                expr = this.getCopyOfObjectInvocation( fieldOutline.parent() ).arg( sourceExpr );
2086            }
2087            else if ( type == CBuiltinLeafInfo.BASE64_BYTE_ARRAY )
2088            {
2089                final JClass byteArray = fieldOutline.parent().parent().getCodeModel().ref( byte[].class );
2090                expr = this.getCopyOfPrimitiveArrayExpression( fieldOutline.parent(), byteArray, sourceExpr );
2091            }
2092            else if ( type == CBuiltinLeafInfo.BIG_DECIMAL || type == CBuiltinLeafInfo.BIG_INTEGER
2093                      || type == CBuiltinLeafInfo.STRING || type == CBuiltinLeafInfo.BOOLEAN || type == CBuiltinLeafInfo.INT
2094                      || type == CBuiltinLeafInfo.LONG || type == CBuiltinLeafInfo.BYTE || type == CBuiltinLeafInfo.SHORT
2095                      || type == CBuiltinLeafInfo.FLOAT || type == CBuiltinLeafInfo.DOUBLE )
2096            {
2097                expr = sourceExpr;
2098            }
2099            else if ( type == CBuiltinLeafInfo.QNAME )
2100            {
2101                expr = sourceExpr;
2102            }
2103            else if ( type == CBuiltinLeafInfo.CALENDAR )
2104            {
2105                final JClass xmlCal = fieldOutline.parent().parent().getCodeModel().ref( XMLGregorianCalendar.class );
2106                if ( sourceMaybeNull )
2107                {
2108                    expr = JOp.cond( sourceExpr.eq( JExpr._null() ), JExpr._null(),
2109                                     JExpr.cast( xmlCal, sourceExpr.invoke( "clone" ) ) );
2110    
2111                }
2112                else
2113                {
2114                    expr = JExpr.cast( xmlCal, sourceExpr.invoke( "clone" ) );
2115                }
2116            }
2117            else if ( type == CBuiltinLeafInfo.DURATION )
2118            {
2119                expr = sourceExpr;
2120            }
2121            else if ( type == CBuiltinLeafInfo.DATA_HANDLER || type == CBuiltinLeafInfo.IMAGE
2122                      || type == CBuiltinLeafInfo.XML_SOURCE )
2123            {
2124                this.log( Level.WARNING, "cannotCopyType",
2125                          type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ).fullName(),
2126                          fieldOutline.getPropertyInfo().getName( true ), fieldOutline.parent().implClass.fullName() );
2127    
2128                expr = sourceExpr;
2129            }
2130    
2131            return expr;
2132        }
2133    
2134        private JExpression getWildcardCopyExpression( final FieldOutline fieldOutline, final CWildcardTypeInfo type,
2135                                                       final JBlock block, final JExpression sourceExpr,
2136                                                       final boolean sourceMaybeNull )
2137        {
2138            block.directStatement( "// CWildcardTypeInfo: " + type.toType( fieldOutline.parent().parent(),
2139                                                                           Aspect.IMPLEMENTATION ).binaryName() );
2140    
2141            if ( sourceMaybeNull )
2142            {
2143    
2144                return JOp.cond( sourceExpr.eq( JExpr._null() ), JExpr._null(),
2145                                 JExpr.cast( fieldOutline.parent().parent().getCodeModel().ref( Element.class ),
2146                                             sourceExpr.invoke( "cloneNode" ).arg( JExpr.TRUE ) ) );
2147    
2148            }
2149            else
2150            {
2151                return JExpr.cast( fieldOutline.parent().parent().getCodeModel().ref( Element.class ),
2152                                   sourceExpr.invoke( "cloneNode" ).arg( JExpr.TRUE ) );
2153    
2154            }
2155        }
2156    
2157        private JExpression getClassInfoCopyExpression( final FieldOutline fieldOutline, final CClassInfo type,
2158                                                        final JBlock block, final JExpression sourceExpr,
2159                                                        final boolean sourceMaybeNull )
2160        {
2161            block.directStatement(
2162                "// CClassInfo: " + type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ).binaryName() );
2163    
2164            if ( sourceMaybeNull )
2165            {
2166                return JOp.cond( sourceExpr.eq( JExpr._null() ), JExpr._null(), sourceExpr.invoke( "clone" ) );
2167            }
2168            else
2169            {
2170                return sourceExpr.invoke( "clone" );
2171            }
2172        }
2173    
2174        private JExpression getNonElementCopyExpression( final FieldOutline fieldOutline, final CNonElement type,
2175                                                         final JBlock block, final JExpression sourceExpr,
2176                                                         final boolean sourceMaybeNull )
2177        {
2178            final JType jType = type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION );
2179            block.directStatement( "// CNonElement: " + jType.binaryName() );
2180    
2181            block.directStatement( "// " + WARNING_PREFIX + ": " + "The '" + jType.binaryName() + "'" );
2182            block.directStatement( "// " + WARNING_PREFIX + ": type was not part of the compilation unit." );
2183    
2184            block.directStatement( "// " + WARNING_PREFIX + ": "
2185                                   + "The CC-XJC plugin assumes that type to declare a 'public Object clone()' method." );
2186    
2187            block.directStatement( "// " + WARNING_PREFIX + ": "
2188                                   + "If this warning is part of an 'if instanceof' block, the order of 'if instanceof'" );
2189    
2190            block.directStatement( "// " + WARNING_PREFIX + ": "
2191                                   + "statements may be wrong and must be verified." );
2192    
2193            this.log( Level.WARNING, "nonElementWarning",
2194                      fieldOutline.parent().implClass.fullName(), fieldOutline.getPropertyInfo().getName( true ),
2195                      jType.binaryName(), WARNING_PREFIX );
2196    
2197            this.tryCatchCopyExpression = true;
2198    
2199            if ( sourceMaybeNull )
2200            {
2201                return JOp.cond( sourceExpr.eq( JExpr._null() ), JExpr._null(),
2202                                 JExpr.cast( jType, sourceExpr.invoke( "clone" ) ) );
2203    
2204            }
2205            else
2206            {
2207                return JExpr.cast( jType, sourceExpr.invoke( "clone" ) );
2208            }
2209        }
2210    
2211        private JExpression getArrayCopyExpression( final FieldOutline fieldOutline, final CArrayInfo type,
2212                                                    final JBlock block, final JExpression sourceExpr )
2213        {
2214            block.directStatement( "// CArrayInfo: " + type.fullName() );
2215            return this.getCopyOfArrayInfoInvocation( fieldOutline, type ).arg( sourceExpr );
2216        }
2217    
2218        private JExpression getElementCopyExpression( final FieldOutline fieldOutline, final CElementInfo type,
2219                                                      final JBlock block, final JExpression sourceExpr )
2220        {
2221            block.directStatement( "// CElementInfo: "
2222                                   + type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ).binaryName() );
2223    
2224            return this.getCopyOfElementInfoInvocation( fieldOutline, type ).arg( sourceExpr );
2225        }
2226    
2227        private JExpression getEnumLeafInfoCopyExpression( final FieldOutline fieldOutline, final CEnumLeafInfo type,
2228                                                           final JBlock block, final JExpression sourceExpr )
2229        {
2230            block.directStatement(
2231                "// CEnumLeafInfo: " + type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ).binaryName() );
2232    
2233            return sourceExpr;
2234        }
2235    
2236        private JExpression getAdapterInfoCopyExpression( final FieldOutline fieldOutline, final CAdapterInfo type,
2237                                                          final JBlock block, final JExpression source )
2238        {
2239            block.directStatement( "// CAdapterInfo: "
2240                                   + type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION ).binaryName() );
2241    
2242            final JType jType = type.toType( fieldOutline.parent().parent(), Aspect.IMPLEMENTATION );
2243            return JExpr.cast( jType, this.getCopyOfObjectInvocation( fieldOutline.parent() ).arg( source ) );
2244        }
2245    
2246        private JMethod generateStandardConstructor( final ClassOutline clazz )
2247        {
2248            final JMethod ctor = clazz.implClass.constructor( JMod.PUBLIC );
2249            ctor.body().directStatement( "// " + getMessage( "title" ) );
2250            ctor.body().invoke( "super" );
2251            ctor.javadoc().add( "Creates a new {@code " + clazz.implClass.name() + "} instance." );
2252            this.constructorCount = this.constructorCount.add( BigInteger.ONE );
2253            return ctor;
2254        }
2255    
2256        private JMethod generateCopyConstructor( final ClassOutline clazz )
2257        {
2258            final JMethod ctor = clazz.implClass.constructor( JMod.PUBLIC );
2259            final JClass paramClass = this.hierarchical ? this.getSupertype( clazz.implClass ) : clazz.implClass;
2260            final JVar o = ctor.param( JMod.FINAL, paramClass, "o" );
2261            final boolean superTypeParam = !clazz.implClass.equals( paramClass );
2262    
2263            ctor.javadoc().add( "Creates a new {@code " + clazz.implClass.name()
2264                                + "} instance by deeply copying a given {@code " + paramClass.name() + "} instance.\n" );
2265    
2266            if ( !this.nullable )
2267            {
2268                ctor.javadoc().addParam( o ).add( "The instance to copy." );
2269                ctor.javadoc().addThrows( NullPointerException.class ).append( "if {@code o} is {@code null}." );
2270            }
2271            else
2272            {
2273                ctor.javadoc().addParam( o ).add( "The instance to copy or {@code null}." );
2274            }
2275    
2276            ctor.body().directStatement( "// " + getMessage( "title" ) );
2277    
2278            if ( this.needsWarningOnReferencedSupertypes( clazz ) )
2279            {
2280                ctor.body().directStatement(
2281                    "// " + WARNING_PREFIX + ": A super-class of this class was not part of the compilation unit." );
2282    
2283                ctor.body().directStatement( "// " + WARNING_PREFIX
2284                                             + ": The plugin assumes this super-class to directly extend class "
2285                                             + "'java.lang.Object'." );
2286    
2287                ctor.body().directStatement( "// " + WARNING_PREFIX
2288                                             + ": The type of the constructor arguments (type of o) in the hierarchy "
2289                                             + "this constructor is part" );
2290    
2291                ctor.body().directStatement( "// " + WARNING_PREFIX + ": of may be wrong and must be verified." );
2292            }
2293    
2294            if ( clazz.getSuperClass() != null
2295                 || ( clazz.implClass._extends() != null
2296                      && !clazz.implClass._extends().binaryName().equals( "java.lang.Object" ) ) )
2297            {
2298                ctor.body().invoke( "super" ).arg( o );
2299            }
2300            else
2301            {
2302                ctor.body().invoke( "super" );
2303            }
2304    
2305            if ( !this.nullable )
2306            {
2307                ctor.body()._if( o.eq( JExpr._null() ) )._then()._throw(
2308                    JExpr._new( clazz.parent().getCodeModel().ref( NullPointerException.class ) ).
2309                    arg( "Cannot create a copy of '" + clazz.implClass.name() + "' from 'null'." ) );
2310    
2311            }
2312    
2313            this.contextExceptions.clear();
2314    
2315            boolean hasFields = false;
2316            if ( !clazz.implClass.fields().isEmpty() )
2317            {
2318                final JBlock copyBlock = new JBlock( false, false );
2319                final JExpression source = superTypeParam ? JExpr.cast( clazz.implClass, o ) : o;
2320    
2321                for ( FieldOutline field : clazz.getDeclaredFields() )
2322                {
2323                    hasFields = true;
2324                    this.generateCopyOfProperty( field, JExpr._this(), source, copyBlock, false );
2325                }
2326    
2327                for ( JFieldVar field : clazz.implClass.fields().values() )
2328                {
2329                    if ( ( field.mods().getValue() & JMod.STATIC ) == JMod.STATIC )
2330                    {
2331                        continue;
2332                    }
2333    
2334                    hasFields = true;
2335                    final FieldOutline fieldOutline = this.getFieldOutline( clazz, field.name() );
2336                    if ( fieldOutline == null )
2337                    {
2338                        if ( field.type().isPrimitive() )
2339                        {
2340                            copyBlock.directStatement( "// Unknown primitive field '" + field.name() + "'." );
2341                            copyBlock.assign( JExpr.refthis( field.name() ), source.ref( field ) );
2342                            this.log( Level.WARNING, "fieldWithoutProperties", field.name(), clazz.implClass.name() );
2343                        }
2344                        else
2345                        {
2346                            if ( field.name().equals( "otherAttributes" ) && clazz.target.declaresAttributeWildcard() )
2347                            {
2348                                copyBlock.directStatement( "// Other attributes." );
2349                                copyBlock.add(
2350                                    JExpr.refthis( field.name() ).invoke( "putAll" ).arg( source.ref( field ) ) );
2351    
2352                            }
2353                            else
2354                            {
2355                                copyBlock.directStatement( "// Unknown reference field '" + field.name() + "'." );
2356                                copyBlock.assign( JExpr.refthis( field.name() ), JExpr.cast(
2357                                    field.type(), this.getCopyOfObjectInvocation( clazz ).arg( source.ref( field ) ) ) );
2358    
2359                                this.log( Level.WARNING, "fieldWithoutProperties", field.name(), clazz.implClass.name() );
2360                            }
2361                        }
2362                    }
2363                }
2364    
2365                if ( hasFields )
2366                {
2367                    JBlock effective = ctor.body();
2368    
2369                    if ( !this.contextExceptions.isEmpty() )
2370                    {
2371                        final JTryBlock tryCopy = ctor.body()._try();
2372                        effective = tryCopy.body();
2373    
2374                        if ( this.contextExceptions.contains( Exception.class ) )
2375                        {
2376                            this.contextExceptions.retainAll( Arrays.asList( new Class<?>[]
2377                                {
2378                                    Exception.class
2379                                } ) );
2380    
2381                        }
2382    
2383                        for ( Class<?> e : this.contextExceptions )
2384                        {
2385                            final JCatchBlock catchBlock = tryCopy._catch( clazz.parent().getCodeModel().ref( e ) );
2386                            catchBlock.body().directStatement(
2387                                "// Please report this at " + getMessage( "bugtrackerUrl" ) );
2388    
2389                            catchBlock.body()._throw( JExpr._new( clazz.parent().getCodeModel().
2390                                ref( AssertionError.class ) ).arg( catchBlock.param( "e" ) ) );
2391    
2392                        }
2393                    }
2394    
2395                    if ( superTypeParam )
2396                    {
2397                        effective._if( o._instanceof( clazz.implClass ) )._then().add( copyBlock );
2398                    }
2399                    else if ( this.nullable )
2400                    {
2401                        effective._if( o.ne( JExpr._null() ) )._then().add( copyBlock );
2402                    }
2403                    else
2404                    {
2405                        effective.add( copyBlock );
2406                    }
2407                }
2408            }
2409    
2410            this.constructorCount = this.constructorCount.add( BigInteger.ONE );
2411            return ctor;
2412        }
2413    
2414        private void warnOnReferencedSupertypes( final ClassOutline clazz )
2415        {
2416            if ( clazz.getSuperClass() == null && clazz.implClass._extends() != null
2417                 && !clazz.implClass._extends().binaryName().equals( "java.lang.Object" ) )
2418            {
2419                this.log( Level.WARNING, "referencedSupertypeWarning", clazz.implClass.fullName(),
2420                          clazz.implClass._extends().binaryName(), WARNING_PREFIX );
2421    
2422            }
2423    
2424            if ( clazz.getSuperClass() != null )
2425            {
2426                this.warnOnReferencedSupertypes( clazz.getSuperClass() );
2427            }
2428        }
2429    
2430        private boolean needsWarningOnReferencedSupertypes( final ClassOutline clazz )
2431        {
2432            if ( clazz.getSuperClass() == null && ( clazz.implClass._extends() != null && !clazz.implClass._extends().
2433                binaryName().equals( "java.lang.Object" ) ) )
2434            {
2435                return true;
2436            }
2437    
2438            if ( clazz.getSuperClass() != null )
2439            {
2440                return this.needsWarningOnReferencedSupertypes( clazz.getSuperClass() );
2441            }
2442    
2443            return false;
2444        }
2445    
2446        private JClass getSupertype( final JClass clazz )
2447        {
2448            if ( clazz._extends() != null && !clazz._extends().binaryName().equals( "java.lang.Object" ) )
2449            {
2450                return this.getSupertype( clazz._extends() );
2451            }
2452    
2453            return clazz;
2454        }
2455    
2456        private JMethod generateCloneMethod( final ClassOutline clazz )
2457        {
2458            final JMethod cloneMethod = clazz.implClass.method( JMod.PUBLIC, clazz.implClass, "clone" );
2459            cloneMethod.annotate( Override.class );
2460            clazz.implClass._implements( clazz.parent().getCodeModel().ref( Cloneable.class ) );
2461            cloneMethod.javadoc().append( "Creates and returns a deep copy of this object.\n" );
2462            cloneMethod.javadoc().addReturn().append( "A deep copy of this object." );
2463            this.contextExceptions.clear();
2464    
2465            if ( ( clazz.implClass._extends() != null
2466                   && clazz.implClass._extends().binaryName().equals( "java.lang.Object" ) )
2467                 || ( clazz.getSuperClass() != null
2468                      && clazz.getSuperClass().implClass.binaryName().equals( "java.lang.Object" ) ) )
2469            {
2470                // Cannot check the super classes 'clone' method throwing a 'CloneNotSupportedException'.
2471                this.contextExceptions.add( CloneNotSupportedException.class );
2472            }
2473    
2474            final JBlock copyBlock = new JBlock( false, false );
2475            copyBlock.directStatement( "// " + getMessage( "title" ) );
2476            final JVar clone = copyBlock.decl( JMod.FINAL, clazz.implClass, "clone",
2477                                               JExpr.cast( clazz.implClass, JExpr._super().invoke( "clone" ) ) );
2478    
2479            for ( FieldOutline field : clazz.getDeclaredFields() )
2480            {
2481                this.generateCopyOfProperty( field, clone, JExpr._this(), copyBlock, true );
2482            }
2483    
2484            for ( JFieldVar field : clazz.implClass.fields().values() )
2485            {
2486                if ( ( field.mods().getValue() & JMod.STATIC ) == JMod.STATIC )
2487                {
2488                    continue;
2489                }
2490    
2491                final FieldOutline fieldOutline = this.getFieldOutline( clazz, field.name() );
2492                if ( fieldOutline == null )
2493                {
2494                    if ( field.type().isPrimitive() )
2495                    {
2496                        copyBlock.directStatement( "// Unknown primitive field '" + field.name() + "'." );
2497                        copyBlock.assign( clone.ref( field.name() ), JExpr.refthis( field.name() ) );
2498    //                    this.log( Level.WARNING, "fieldWithoutProperties", field.name(), clazz.implClass.name() );
2499                    }
2500                    else
2501                    {
2502                        if ( field.name().equals( "otherAttributes" ) && clazz.target.declaresAttributeWildcard() )
2503                        {
2504                            copyBlock.directStatement( "// Other attributes." );
2505                            copyBlock.add( clone.ref( field.name() ).invoke( "putAll" ).
2506                                arg( JExpr.refthis( field.name() ) ) );
2507    
2508                        }
2509                        else
2510                        {
2511                            copyBlock.directStatement( "// Unknown reference field '" + field.name() + "'." );
2512                            copyBlock.assign( clone.ref( field.name() ), JExpr.cast(
2513                                field.type(), this.getCopyOfObjectInvocation( clazz ).arg(
2514                                JExpr.refthis( field.name() ) ) ) );
2515    
2516    //                        this.log( Level.WARNING, "fieldWithoutProperties", field.name(), clazz.implClass.name() );
2517                        }
2518                    }
2519                }
2520            }
2521    
2522            copyBlock._return( clone );
2523    
2524            if ( !this.contextExceptions.isEmpty() )
2525            {
2526                final JTryBlock tryCopy = cloneMethod.body()._try();
2527                tryCopy.body().add( copyBlock );
2528    
2529                if ( this.contextExceptions.contains( Exception.class ) )
2530                {
2531                    this.contextExceptions.retainAll( Arrays.asList( new Class<?>[]
2532                        {
2533                            Exception.class
2534                        } ) );
2535    
2536                }
2537    
2538                for ( Class<?> e : this.contextExceptions )
2539                {
2540                    final JCatchBlock catchBlock = tryCopy._catch( clazz.parent().getCodeModel().ref( e ) );
2541                    catchBlock.body().directStatement( "// Please report this at " + getMessage( "bugtrackerUrl" ) );
2542                    catchBlock.body()._throw( JExpr._new( clazz.parent().getCodeModel().
2543                        ref( AssertionError.class ) ).arg( catchBlock.param( "e" ) ) );
2544    
2545                }
2546            }
2547            else
2548            {
2549                cloneMethod.body().add( copyBlock );
2550            }
2551    
2552            this.methodCount = this.methodCount.add( BigInteger.ONE );
2553            return cloneMethod;
2554        }
2555    
2556        private void generateCopyOfProperty( final FieldOutline field, final JExpression targetExpr,
2557                                             final JExpression sourceExpr, final JBlock block, final boolean cloneMethod )
2558        {
2559            final JMethod getter = this.getPropertyGetter( field );
2560    
2561            if ( getter != null )
2562            {
2563                if ( field.getPropertyInfo().isCollection() )
2564                {
2565                    if ( field.getRawType().isArray() )
2566                    {
2567                        block.directStatement( "// '" + field.getPropertyInfo().getName( true ) + "' array." );
2568                        final JConditional fieldNotNull = block._if(
2569                            JExpr.ref( sourceExpr, field.getPropertyInfo().getName( false ) ).ne( JExpr._null() ) );
2570    
2571                        fieldNotNull._then().assign(
2572                            targetExpr.ref( field.getPropertyInfo().getName( false ) ),
2573                            JExpr.invoke( this.getCopyOfCollectionMethod( field ) ).
2574                            arg( JExpr.invoke( sourceExpr, getter ) ) );
2575    
2576                    }
2577                    else
2578                    {
2579                        block.directStatement( "// '" + field.getPropertyInfo().getName( true ) + "' collection." );
2580                        final JConditional fieldNotNull = block._if(
2581                            JExpr.ref( sourceExpr, field.getPropertyInfo().getName( false ) ).ne( JExpr._null() ) );
2582    
2583                        if ( cloneMethod )
2584                        {
2585                            fieldNotNull._then().assign( JExpr.ref( targetExpr, field.getPropertyInfo().getName( false ) ),
2586                                                         JExpr._null() );
2587    
2588                        }
2589    
2590                        fieldNotNull._then().invoke( this.getCopyOfCollectionMethod( field ) ).
2591                            arg( JExpr.invoke( sourceExpr, getter ) ).arg( JExpr.invoke( targetExpr, getter ) );
2592    
2593                    }
2594                }
2595                else
2596                {
2597                    final JExpression copyExpr;
2598                    boolean needsToCatchException = false;
2599    
2600                    if ( field.getPropertyInfo().ref().size() != 1 )
2601                    {
2602                        block.directStatement( "// '" + field.getPropertyInfo().getName( true ) + "' property." );
2603                        copyExpr = JExpr.invoke( this.getCopyOfPropertyMethod( field ) ).
2604                            arg( sourceExpr.invoke( getter ) );
2605    
2606                    }
2607                    else
2608                    {
2609                        CTypeInfo typeInfo = null;
2610    
2611                        if ( field.getPropertyInfo().getAdapter() != null
2612                             && field.getPropertyInfo().getAdapter().customType != null )
2613                        {
2614                            typeInfo = field.parent().parent().getModel().getTypeInfo(
2615                                field.getPropertyInfo().getAdapter().customType );
2616    
2617                            if ( typeInfo == null )
2618                            {
2619                                typeInfo = new CAdapterInfo( field.getPropertyInfo().getAdapter() );
2620                            }
2621                        }
2622                        else
2623                        {
2624                            typeInfo = field.getPropertyInfo().ref().iterator().next();
2625                        }
2626    
2627                        final JType javaType = typeInfo.toType( field.parent().parent(), Aspect.IMPLEMENTATION );
2628    
2629                        final JExpression source =
2630                            field.parent().parent().getModel().strategy == ImplStructureStrategy.BEAN_ONLY
2631                            ? JExpr.invoke( sourceExpr, getter )
2632                            : JExpr.cast( javaType, JExpr.invoke( sourceExpr, getter ) );
2633    
2634                        copyExpr = this.getCopyExpression( field, typeInfo, block, source, true );
2635                        needsToCatchException = needsToCatchException || this.tryCatchCopyExpression;
2636                    }
2637    
2638                    if ( copyExpr == null )
2639                    {
2640                        this.log( Level.SEVERE, "cannotCopyProperty", field.getPropertyInfo().getName( true ),
2641                                  field.parent().implClass.binaryName() );
2642    
2643                    }
2644                    else
2645                    {
2646                        JBlock copyBlock = block;
2647                        if ( needsToCatchException )
2648                        {
2649                            final JTryBlock tryCopy = block._try();
2650                            copyBlock = tryCopy.body();
2651    
2652                            final JCatchBlock catchException =
2653                                tryCopy._catch( field.parent().parent().getCodeModel().ref( Exception.class ) );
2654    
2655                            final JVar e = catchException.param( "e" );
2656                            catchException.body()._throw( JExpr._new( field.parent().parent().getCodeModel().
2657                                ref( AssertionError.class ) ).arg( e ) );
2658    
2659                        }
2660    
2661                        if ( field.getRawType().isPrimitive() )
2662                        {
2663                            copyBlock.assign( targetExpr.ref( field.getPropertyInfo().getName( false ) ), copyExpr );
2664                        }
2665                        else
2666                        {
2667                            copyBlock.assign( targetExpr.ref( field.getPropertyInfo().getName( false ) ),
2668                                              JOp.cond( JExpr.ref( sourceExpr, field.getPropertyInfo().getName( false ) ).
2669                                eq( JExpr._null() ), JExpr._null(), copyExpr ) );
2670    
2671                        }
2672                    }
2673                }
2674            }
2675            else
2676            {
2677                throw new AssertionError( getMessage( "getterNotFound", field.getPropertyInfo().getName( true ),
2678                                                      field.parent().implClass.binaryName() ) );
2679    
2680            }
2681        }
2682    
2683        private String getMethodNamePart( final JType type )
2684        {
2685            String methodName = type.name();
2686            if ( type.isArray() )
2687            {
2688                methodName = methodName.replace( "[]", "s" );
2689            }
2690    
2691            methodName = methodName.replace( ".", "" );
2692            final char[] c = methodName.toCharArray();
2693            c[0] = Character.toUpperCase( c[0] );
2694            methodName = String.valueOf( c );
2695            return methodName;
2696        }
2697    
2698        private static String getMessage( final String key, final Object... args )
2699        {
2700            return MessageFormat.format(
2701                ResourceBundle.getBundle( "net/sourceforge/ccxjc/PluginImpl" ).getString( key ), args );
2702    
2703        }
2704    
2705        private Class<?> getClass( final String binaryName )
2706        {
2707            try
2708            {
2709                return Class.forName( binaryName );
2710            }
2711            catch ( final ClassNotFoundException e )
2712            {
2713                return null;
2714            }
2715        }
2716    
2717        private Collection<String> readTypes( final String fileName ) throws IOException
2718        {
2719            final Collection<String> types = new LinkedList<String>();
2720            final BufferedReader reader = new BufferedReader( new FileReader( fileName ) );
2721            String line;
2722    
2723            while ( ( line = reader.readLine() ) != null )
2724            {
2725                if ( line.indexOf( '#' ) > -1 )
2726                {
2727                    continue;
2728                }
2729    
2730                if ( line.trim().length() > 0 )
2731                {
2732                    types.add( line.trim() );
2733                }
2734            }
2735    
2736            return Collections.unmodifiableCollection( types );
2737        }
2738    
2739        private void log( final Level level, final String key, final Object... args )
2740        {
2741            final StringBuilder b = new StringBuilder( 512 ).append( "[" ).append( MESSAGE_PREFIX ).append( "] [" ).
2742                append( level.getLocalizedName() ).append( "] " ).append( getMessage( key, args ) );
2743    
2744            int logLevel = Level.WARNING.intValue();
2745            if ( this.options != null && !this.options.quiet )
2746            {
2747                if ( this.options.verbose )
2748                {
2749                    logLevel = Level.INFO.intValue();
2750                }
2751                if ( this.options.debugMode )
2752                {
2753                    logLevel = Level.ALL.intValue();
2754                }
2755            }
2756    
2757            if ( level.intValue() >= logLevel )
2758            {
2759                if ( level.intValue() <= Level.INFO.intValue() )
2760                {
2761                    System.out.println( b.toString() );
2762                }
2763                else
2764                {
2765                    System.err.println( b.toString() );
2766                }
2767            }
2768        }
2769    
2770    }
2771    
2772    class CClassInfoComparator implements Comparator<CClassInfo>
2773    {
2774    
2775        private final Outline outline;
2776    
2777        CClassInfoComparator( final Outline outline )
2778        {
2779            this.outline = outline;
2780        }
2781    
2782        public int compare( final CClassInfo o1, final CClassInfo o2 )
2783        {
2784            final JClass javaClass1 = o1.toType( this.outline, Aspect.IMPLEMENTATION );
2785            final JClass javaClass2 = o2.toType( this.outline, Aspect.IMPLEMENTATION );
2786    
2787            int ret = 0;
2788    
2789            if ( !javaClass1.binaryName().equals( javaClass2.binaryName() ) )
2790            {
2791                if ( javaClass1.isAssignableFrom( javaClass2 ) )
2792                {
2793                    ret = -1;
2794                }
2795                else if ( javaClass2.isAssignableFrom( javaClass1 ) )
2796                {
2797                    ret = 1;
2798                }
2799            }
2800    
2801            return ret;
2802        }
2803    
2804    }
2805    
2806    class CElementInfoComparator implements Comparator<CElementInfo>
2807    {
2808    
2809        private final Outline outline;
2810    
2811        private final boolean hasClass;
2812    
2813        CElementInfoComparator( final Outline outline, final boolean hasClass )
2814        {
2815            this.outline = outline;
2816            this.hasClass = hasClass;
2817        }
2818    
2819        public int compare( final CElementInfo o1, final CElementInfo o2 )
2820        {
2821            final JClass javaClass1;
2822            final JClass javaClass2;
2823    
2824            if ( this.hasClass )
2825            {
2826                javaClass1 = (JClass) o1.toType( this.outline, Aspect.IMPLEMENTATION );
2827                javaClass2 = (JClass) o2.toType( this.outline, Aspect.IMPLEMENTATION );
2828            }
2829            else
2830            {
2831                javaClass1 = (JClass) o1.getContentType().toType( this.outline, Aspect.IMPLEMENTATION );
2832                javaClass2 = (JClass) o2.getContentType().toType( this.outline, Aspect.IMPLEMENTATION );
2833            }
2834    
2835            int ret = 0;
2836    
2837            if ( !javaClass1.binaryName().equals( javaClass2.binaryName() ) )
2838            {
2839                if ( javaClass1.isAssignableFrom( javaClass2 ) )
2840                {
2841                    ret = -1;
2842                }
2843                else if ( javaClass2.isAssignableFrom( javaClass1 ) )
2844                {
2845                    ret = 1;
2846                }
2847            }
2848    
2849            return ret;
2850        }
2851    
2852    }
2853    
2854    class CTypeInfoComparator implements Comparator<CTypeInfo>
2855    {
2856    
2857        private final Outline outline;
2858    
2859        CTypeInfoComparator( final Outline outline )
2860        {
2861            this.outline = outline;
2862        }
2863    
2864        public int compare( final CTypeInfo o1, final CTypeInfo o2 )
2865        {
2866            final JType javaType1 = o1.toType( this.outline, Aspect.IMPLEMENTATION );
2867            final JType javaType2 = o2.toType( this.outline, Aspect.IMPLEMENTATION );
2868    
2869            int ret = 0;
2870    
2871            if ( !javaType1.binaryName().equals( javaType2.binaryName() ) && javaType1 instanceof JClass
2872                 && javaType2 instanceof JClass )
2873            {
2874                if ( ( (JClass) javaType1 ).isAssignableFrom( (JClass) javaType2 ) )
2875                {
2876                    ret = -1;
2877                }
2878                else if ( ( (JClass) javaType2 ).isAssignableFrom( (JClass) javaType1 ) )
2879                {
2880                    ret = 1;
2881                }
2882            }
2883    
2884            return ret;
2885        }
2886    
2887    }
2888    
2889    class CAdapterInfo implements CTypeInfo
2890    {
2891    
2892        private final CAdapter adapter;
2893    
2894        CAdapterInfo( final CAdapter adapter )
2895        {
2896            this.adapter = adapter;
2897        }
2898    
2899        public JType toType( final Outline o, final Aspect aspect )
2900        {
2901            return this.adapter.customType.toType( o, aspect );
2902        }
2903    
2904        public NType getType()
2905        {
2906            return this.adapter.customType;
2907        }
2908    
2909        public boolean canBeReferencedByIDREF()
2910        {
2911            return false;
2912        }
2913    
2914        public Locatable getUpstream()
2915        {
2916            return null;
2917        }
2918    
2919        public Location getLocation()
2920        {
2921            return null;
2922        }
2923    
2924        public CCustomizations getCustomizations()
2925        {
2926            return null;
2927        }
2928    
2929        public Locator getLocator()
2930        {
2931            return null;
2932        }
2933    
2934        public XSComponent getSchemaComponent()
2935        {
2936            return null;
2937        }
2938    
2939        public QName getTypeName()
2940        {
2941            throw new UnsupportedOperationException( "Not supported yet." );
2942        }
2943    
2944        public boolean isSimpleType()
2945        {
2946            throw new UnsupportedOperationException( "Not supported yet." );
2947        }
2948    
2949        public boolean isCollection()
2950        {
2951            return false;
2952        }
2953    
2954        public CAdapter getAdapterUse()
2955        {
2956            return this.adapter;
2957        }
2958    
2959        public CTypeInfo getInfo()
2960        {
2961            return this;
2962        }
2963    
2964        public ID idUse()
2965        {
2966            return null;
2967        }
2968    
2969        public MimeType getExpectedMimeType()
2970        {
2971            return null;
2972        }
2973    
2974        public JExpression createConstant( Outline outline, XmlString lexical )
2975        {
2976            return null;
2977        }
2978    
2979    }