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