001/* 002 * ============================================================================ 003 * Copyright © 2015 Square, Inc. 004 * Copyright for the modifications © 2018-2024 by Thomas Thrien. 005 * ============================================================================ 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019 020package org.tquadrat.foundation.javacomposer.internal; 021 022import static java.lang.String.format; 023import static java.util.Collections.addAll; 024import static javax.lang.model.element.Modifier.ABSTRACT; 025import static javax.lang.model.element.Modifier.NATIVE; 026import static org.apiguardian.api.API.Status.DEPRECATED; 027import static org.apiguardian.api.API.Status.INTERNAL; 028import static org.apiguardian.api.API.Status.STABLE; 029import static org.tquadrat.foundation.javacomposer.internal.TypeNameImpl.VOID_PRIMITIVE; 030import static org.tquadrat.foundation.javacomposer.internal.Util.createDebugOutput; 031import static org.tquadrat.foundation.lang.Objects.checkState; 032import static org.tquadrat.foundation.lang.Objects.hash; 033import static org.tquadrat.foundation.lang.Objects.isNull; 034import static org.tquadrat.foundation.lang.Objects.nonNull; 035import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument; 036import static org.tquadrat.foundation.lang.Objects.requireNotEmptyArgument; 037import static org.tquadrat.foundation.lang.Objects.requireValidArgument; 038import static org.tquadrat.foundation.lang.Objects.requireValidNonNullArgument; 039import static org.tquadrat.foundation.util.JavaUtils.isValidName; 040 041import javax.lang.model.element.ExecutableElement; 042import javax.lang.model.element.Modifier; 043import javax.lang.model.type.DeclaredType; 044import javax.lang.model.util.Types; 045import java.io.UncheckedIOException; 046import java.lang.reflect.Method; 047import java.lang.reflect.Type; 048import java.util.ArrayList; 049import java.util.Arrays; 050import java.util.Collection; 051import java.util.EnumSet; 052import java.util.HashSet; 053import java.util.LinkedHashSet; 054import java.util.List; 055import java.util.Map; 056import java.util.Optional; 057import java.util.SequencedCollection; 058import java.util.Set; 059import java.util.StringJoiner; 060import java.util.TreeSet; 061 062import org.apiguardian.api.API; 063import org.tquadrat.foundation.annotation.ClassVersion; 064import org.tquadrat.foundation.exception.UnexpectedExceptionError; 065import org.tquadrat.foundation.exception.UnsupportedEnumError; 066import org.tquadrat.foundation.exception.ValidationException; 067import org.tquadrat.foundation.javacomposer.AnnotationSpec; 068import org.tquadrat.foundation.javacomposer.ClassName; 069import org.tquadrat.foundation.javacomposer.CodeBlock; 070import org.tquadrat.foundation.javacomposer.JavaComposer; 071import org.tquadrat.foundation.javacomposer.MethodSpec; 072import org.tquadrat.foundation.javacomposer.ParameterSpec; 073import org.tquadrat.foundation.javacomposer.TypeName; 074import org.tquadrat.foundation.javacomposer.TypeVariableName; 075import org.tquadrat.foundation.lang.Lazy; 076import org.tquadrat.foundation.lang.Objects; 077 078/** 079 * The implementation for 080 * {@link MethodSpec}. 081 * 082 * @author Square,Inc. 083 * @modified Thomas Thrien - thomas.thrien@tquadrat.org 084 * @version $Id: MethodSpecImpl.java 1105 2024-02-28 12:58:46Z tquadrat $ 085 * @since 0.0.5 086 * 087 * @UMLGraph.link 088 */ 089@SuppressWarnings( {"ClassWithTooManyFields"} ) 090@ClassVersion( sourceVersion = "$Id: MethodSpecImpl.java 1105 2024-02-28 12:58:46Z tquadrat $" ) 091@API( status = INTERNAL, since = "0.0.5" ) 092public final class MethodSpecImpl implements MethodSpec 093{ 094 /*---------------*\ 095 ====** Inner Classes **==================================================== 096 \*---------------*/ 097 /** 098 * The implementation for 099 * {@link org.tquadrat.foundation.javacomposer.MethodSpec.Builder} 100 * 101 * @author Square,Inc. 102 * @modified Thomas Thrien - thomas.thrien@tquadrat.org 103 * @version $Id: MethodSpecImpl.java 1105 2024-02-28 12:58:46Z tquadrat $ 104 * @since 0.0.5 105 * 106 * @UMLGraph.link 107 */ 108 @ClassVersion( sourceVersion = "$Id: MethodSpecImpl.java 1105 2024-02-28 12:58:46Z tquadrat $" ) 109 @API( status = INTERNAL, since = "0.0.5" ) 110 public static final class BuilderImpl implements MethodSpec.Builder 111 { 112 /*------------*\ 113 ====** Attributes **=================================================== 114 \*------------*/ 115 /** 116 * The annotations for the method. 117 */ 118 private final Collection<AnnotationSpecImpl> m_Annotations = new ArrayList<>(); 119 120 /** 121 * The code for the method. 122 */ 123 @SuppressWarnings( "UseOfConcreteClass" ) 124 private final CodeBlockImpl.BuilderImpl m_Code; 125 126 /** 127 * The reference to the factory. 128 */ 129 @SuppressWarnings( "UseOfConcreteClass" ) 130 private final JavaComposer m_Composer; 131 132 /** 133 * The default value for the method; this is for annotations only. 134 */ 135 @SuppressWarnings( "UseOfConcreteClass" ) 136 private CodeBlockImpl m_DefaultValue; 137 138 /** 139 * The declared exceptions for the method. 140 */ 141 private final Collection<TypeNameImpl> m_Exceptions = new LinkedHashSet<>(); 142 143 /** 144 * The Javadoc comment for the method. 145 */ 146 @SuppressWarnings( "UseOfConcreteClass" ) 147 private final CodeBlockImpl.BuilderImpl m_Javadoc; 148 149 /** 150 * The modifiers for the method. 151 */ 152 private final Set<Modifier> m_Modifiers = EnumSet.noneOf( Modifier.class ); 153 154 /** 155 * The name for the method. 156 */ 157 private final String m_Name; 158 159 /** 160 * The parameters for the method. 161 */ 162 private final List<ParameterSpecImpl> m_Parameters = new ArrayList<>(); 163 164 /** 165 * The comment for the return value for the method. 166 */ 167 @SuppressWarnings( "UseOfConcreteClass" ) 168 private final CodeBlockImpl.BuilderImpl m_ReturnComment; 169 170 /** 171 * The return type for the method. 172 */ 173 @SuppressWarnings( "UseOfConcreteClass" ) 174 private TypeNameImpl m_ReturnType; 175 176 /** 177 * The static imports. 178 */ 179 private final Collection<String> m_StaticImports = new TreeSet<>(); 180 181 /** 182 * The type variables for the method. 183 */ 184 private final Collection<TypeVariableNameImpl> m_TypeVariables = new ArrayList<>(); 185 186 /** 187 * The flag that indicates whether a parameter (the last one) is a 188 * {@code varargs} parameter. 189 */ 190 private boolean m_Varargs = false; 191 192 /*--------------*\ 193 ====** Constructors **================================================= 194 \*--------------*/ 195 /** 196 * Creates a new {@code BuilderImpl} instance. 197 * 198 * @param composer The reference to the factory that created this 199 * builder instance. 200 * @param name The name for the method. 201 */ 202 public BuilderImpl( @SuppressWarnings( "UseOfConcreteClass" ) final JavaComposer composer, final CharSequence name ) 203 { 204 m_Composer = requireNonNullArgument( composer, "composer" ); 205 m_Name = requireValidArgument( requireNotEmptyArgument( name, "name" ), "name", v -> v.equals( CONSTRUCTOR ) || isValidName( v ), $ -> "not a valid name: %s".formatted( name ) ).toString().intern(); 206 m_ReturnType = name.equals( CONSTRUCTOR ) ? null : VOID_PRIMITIVE; 207 208 m_Code = (CodeBlockImpl.BuilderImpl) m_Composer.codeBlockBuilder(); 209 m_Javadoc = (CodeBlockImpl.BuilderImpl) m_Composer.codeBlockBuilder(); 210 m_ReturnComment = (CodeBlockImpl.BuilderImpl) m_Composer.codeBlockBuilder(); 211 } // BuilderImpl() 212 213 /*---------*\ 214 ====** Methods **====================================================== 215 \*---------*/ 216 /** 217 * {@inheritDoc} 218 */ 219 @Override 220 public final BuilderImpl addAnnotation( final AnnotationSpec annotationSpec ) 221 { 222 m_Annotations.add( (AnnotationSpecImpl) requireNonNullArgument( annotationSpec, "annotationSpec" ) ); 223 224 //---* Done *------------------------------------------------------ 225 return this; 226 } // addAnnotation() 227 228 /** 229 * {@inheritDoc} 230 */ 231 @Override 232 public final BuilderImpl addAnnotation( final Class<?> annotation ) 233 { 234 return addAnnotation( ClassNameImpl.from( requireNonNullArgument( annotation, "annotation" ) ) ); 235 } // addAnnotation() 236 237 /** 238 * {@inheritDoc} 239 */ 240 @Override 241 public final BuilderImpl addAnnotation( final ClassName annotationClass ) 242 { 243 final var annotation = (AnnotationSpecImpl) m_Composer.annotationBuilder( requireNonNullArgument( annotationClass, "annotationClass" ) ) 244 .build(); 245 m_Annotations.add( annotation ); 246 247 //---* Done *------------------------------------------------------ 248 return this; 249 } // addAnnotation() 250 251 /** 252 * {@inheritDoc} 253 */ 254 @Override 255 public final BuilderImpl addAnnotations( final Iterable<? extends AnnotationSpec> annotationSpecs ) 256 { 257 for( final var annotationSpec : requireNonNullArgument( annotationSpecs, "annotationSpecs" ) ) 258 { 259 m_Annotations.add( (AnnotationSpecImpl) annotationSpec ); 260 } 261 262 //---* Done *------------------------------------------------------ 263 return this; 264 } // addAnnotations() 265 266 /** 267 * {@inheritDoc} 268 */ 269 @Override 270 public final BuilderImpl addCode( final CodeBlock codeBlock ) 271 { 272 m_Code.add( requireNonNullArgument( codeBlock, "codeBlock" ) ); 273 274 //---* Done *------------------------------------------------------ 275 return this; 276 } // addCode() 277 278 /** 279 * {@inheritDoc} 280 */ 281 @Override 282 public final BuilderImpl addCode( final String format, final Object... args ) 283 { 284 m_Code.add( format, args ); 285 286 //---* Done *------------------------------------------------------ 287 return this; 288 } // addCode() 289 290 /** 291 * {@inheritDoc} 292 */ 293 @Override 294 public final BuilderImpl addComment( final String format, final Object... args ) 295 { 296 m_Code.addWithoutDebugInfo( "// " + requireNonNullArgument( format, "format" ) + "\n", args ); 297 298 //---* Done *------------------------------------------------------ 299 return this; 300 } // addComment() 301 302 /** 303 * {@inheritDoc} 304 */ 305 @Override 306 public final BuilderImpl addException( final Type exception ) 307 { 308 return addException( TypeNameImpl.from( requireNonNullArgument( exception, "exception" ) ) ); 309 } // addException() 310 311 /** 312 * {@inheritDoc} 313 */ 314 @Override 315 public final BuilderImpl addException( final TypeName exception ) 316 { 317 m_Exceptions.add( (TypeNameImpl) requireNonNullArgument( exception, "exception" ) ); 318 319 //---* Done *------------------------------------------------------ 320 return this; 321 } // addException() 322 323 /** 324 * {@inheritDoc} 325 */ 326 @Override 327 public final BuilderImpl addExceptions( final Iterable<? extends TypeName> exceptions ) 328 { 329 for( final var exception : requireNonNullArgument( exceptions, "exceptions" ) ) 330 { 331 m_Exceptions.add( (TypeNameImpl) exception ); 332 } 333 334 //---* Done *------------------------------------------------------ 335 return this; 336 } // addExceptions() 337 338 /** 339 * {@inheritDoc} 340 */ 341 @Override 342 public final BuilderImpl addJavadoc( final CodeBlock block ) 343 { 344 m_Javadoc.add( block ); 345 346 //---* Done *------------------------------------------------------ 347 return this; 348 } // addJavadoc() 349 350 /** 351 * {@inheritDoc} 352 */ 353 @Override 354 public final BuilderImpl addJavadoc( final String format, final Object... args ) 355 { 356 m_Javadoc.addWithoutDebugInfo( format, args ); 357 358 //---* Done *------------------------------------------------------ 359 return this; 360 } // addJavadoc() 361 362 /** 363 * {@inheritDoc} 364 */ 365 @SuppressWarnings( {"BoundedWildcard"} ) 366 @Override 367 public final BuilderImpl addModifiers( final Iterable<Modifier> modifiers ) 368 { 369 for( final var modifier : requireNonNullArgument( modifiers, "modifiers" ) ) 370 { 371 m_Modifiers.add( modifier ); 372 } 373 374 //---* Done *------------------------------------------------------ 375 return this; 376 } // addModifiers() 377 378 /** 379 * {@inheritDoc} 380 */ 381 @Override 382 public final BuilderImpl addModifiers( final Modifier... modifiers ) 383 { 384 addAll( m_Modifiers, requireNonNullArgument( modifiers, "modifiers" ) ); 385 386 //---* Done *------------------------------------------------------ 387 return this; 388 } // addModifiers() 389 390 /** 391 * {@inheritDoc} 392 */ 393 @Override 394 public final BuilderImpl addNamedCode( final String format, final Map<String,?> args ) 395 { 396 m_Code.addNamed( format, args ); 397 398 //---* Done *------------------------------------------------------ 399 return this; 400 } // addNamedCode() 401 402 /** 403 * {@inheritDoc} 404 */ 405 @Override 406 public final BuilderImpl addParameter( final ParameterSpec parameterSpec ) 407 { 408 m_Parameters.add( (ParameterSpecImpl) requireNonNullArgument( parameterSpec, "parameterSpec" ) ); 409 410 //---* Done *------------------------------------------------------ 411 return this; 412 } // addParameter() 413 414 /** 415 * {@inheritDoc} 416 */ 417 @Override 418 public final BuilderImpl addParameter( final Type type, final String name, final Modifier... modifiers ) 419 { 420 return addParameter( TypeName.from( requireNonNullArgument( type, "type" ) ), name, modifiers ); 421 } // addParameter() 422 423 /** 424 * {@inheritDoc} 425 */ 426 @Override 427 public final BuilderImpl addParameter( final TypeName type, final String name, final Modifier... modifiers ) 428 { 429 final var parameter = m_Composer.parameterBuilder( type, name, modifiers ) 430 .build(); 431 final var retValue = addParameter( parameter ); 432 433 //---* Done *---------------------------------------------------------- 434 return retValue; 435 } // addParameter() 436 437 /** 438 * {@inheritDoc} 439 */ 440 @Override 441 public final BuilderImpl addParameters( final Iterable<? extends ParameterSpec> parameterSpecs ) 442 { 443 for( final var parameterSpec : requireNonNullArgument( parameterSpecs, "parameterSpecs" ) ) 444 { 445 m_Parameters.add( (ParameterSpecImpl) parameterSpec ); 446 } 447 448 //---* Done *------------------------------------------------------ 449 return this; 450 } // addParameters() 451 452 /** 453 * {@inheritDoc} 454 */ 455 @Override 456 public final BuilderImpl addStatement( final String format, final Object... args ) 457 { 458 m_Code.addStatement( format, args ); 459 460 //---* Done *------------------------------------------------------ 461 return this; 462 } // addStatement() 463 464 /** 465 * {@inheritDoc} 466 */ 467 @API( status = STABLE, since = "0.2.0" ) 468 @Override 469 public final MethodSpecImpl.BuilderImpl addStaticImport( final Class<?> clazz, final String... names ) 470 { 471 return addStaticImport( ClassNameImpl.from( clazz ), names ); 472 } // addStaticImport() 473 474 /** 475 * {@inheritDoc} 476 */ 477 @API( status = STABLE, since = "0.2.0" ) 478 @Override 479 public final MethodSpecImpl.BuilderImpl addStaticImport( final ClassName className, final String... names ) 480 { 481 final var canonicalName = requireNonNullArgument( className, "className" ).canonicalName(); 482 for( final var name : requireValidNonNullArgument( names, "names", v -> v.length > 0, "%s array is empty"::formatted ) ) 483 { 484 m_StaticImports.add( 485 format( 486 "%s.%s", 487 canonicalName, 488 requireValidArgument( 489 name, 490 "name", 491 Objects::nonNull, 492 $ -> "null entry in names array: %s".formatted( Arrays.toString( names ) ) 493 ) 494 ) 495 ); 496 } 497 498 //---* Done *------------------------------------------------------ 499 return this; 500 } // addStaticImport() 501 502 /** 503 * {@inheritDoc} 504 */ 505 @API( status = STABLE, since = "0.2.0" ) 506 @Override 507 public final MethodSpecImpl.BuilderImpl addStaticImport( final Enum<?> constant ) 508 { 509 return addStaticImport( ClassNameImpl.from( requireNonNullArgument( constant, "constant" ).getDeclaringClass() ), constant.name() ); 510 } // addStaticImport() 511 512 /** 513 * {@inheritDoc} 514 */ 515 @Override 516 public final BuilderImpl addTypeVariable( final TypeVariableName typeVariable ) 517 { 518 m_TypeVariables.add( (TypeVariableNameImpl) typeVariable ); 519 520 //---* Done *------------------------------------------------------ 521 return this; 522 } // addTypeVariable() 523 524 /** 525 * {@inheritDoc} 526 */ 527 @Override 528 public final BuilderImpl addTypeVariables( final Iterable<TypeVariableName> typeVariables ) 529 { 530 for( final var typeVariable : requireNonNullArgument( typeVariables, "typeVariables" ) ) 531 { 532 m_TypeVariables.add( (TypeVariableNameImpl) typeVariable ); 533 } 534 535 //---* Done *------------------------------------------------------ 536 return this; 537 } // addTypeVariables() 538 539 /** 540 * {@inheritDoc} 541 */ 542 @Override 543 public final BuilderImpl beginControlFlow( final String controlFlow, final Object... args ) 544 { 545 m_Code.beginControlFlow( controlFlow, args ); 546 547 //---* Done *------------------------------------------------------ 548 return this; 549 } // beginControlFlow() 550 551 /** 552 * {@inheritDoc} 553 */ 554 @Override 555 public final MethodSpecImpl build() 556 { 557 /* 558 * A method with a body cannot be abstract. 559 * We remove the modifier abstract here so that 560 * MethodSpec.toBuilder() will work properly. 561 */ 562 if( !m_Code.isEmpty() ) 563 { 564 m_Modifiers.remove( ABSTRACT ); 565 } 566 final var retValue = new MethodSpecImpl( this ); 567 568 //---* Done *------------------------------------------------------ 569 return retValue; 570 } // build() 571 572 /** 573 * {@inheritDoc} 574 */ 575 @Override 576 public final BuilderImpl defaultValue( final CodeBlock defaultValue ) 577 { 578 checkState( isNull( m_DefaultValue ), () -> new IllegalStateException( "defaultValue was already set" ) ); 579 var codeBlockImpl = (CodeBlockImpl) requireNonNullArgument( defaultValue, "defaultValue" ); 580 if( m_Composer.addDebugOutput() ) 581 { 582 codeBlockImpl = (CodeBlockImpl) createDebugOutput( true ) 583 .map( DebugOutput::asComment ) 584 .map( m_Composer::codeBlockOf ) 585 .map( block -> block.join( " ", defaultValue ) ) 586 .orElse( defaultValue ); 587 } 588 m_DefaultValue = codeBlockImpl; 589 590 //---* Done *------------------------------------------------------ 591 return this; 592 } // defaultValue() 593 594 /** 595 * {@inheritDoc} 596 */ 597 @Override 598 public final BuilderImpl defaultValue( final String format, final Object... args ) 599 { 600 return defaultValue( m_Composer.codeBlockOf( format, args ) ); 601 } // defaultValue() 602 603 /** 604 * {@inheritDoc} 605 */ 606 @Override 607 public final BuilderImpl endControlFlow() 608 { 609 m_Code.endControlFlow(); 610 611 //---* Done *------------------------------------------------------ 612 return this; 613 } // endControlFlow() 614 615 /** 616 * {@inheritDoc} 617 */ 618 @Override 619 public final BuilderImpl endControlFlow( final String controlFlow, final Object... args ) 620 { 621 m_Code.endControlFlow( controlFlow, args ); 622 623 //---* Done *------------------------------------------------------ 624 return this; 625 } // endControlFlow() 626 627 /** 628 * Returns <i>a reference to</i> the declared exceptions. 629 * 630 * @return The exceptions. 631 */ 632 @SuppressWarnings( {"PublicMethodNotExposedInInterface", "AssignmentOrReturnOfFieldWithMutableType"} ) 633 public final Collection<TypeNameImpl> exceptions() 634 { 635 return m_Exceptions ; 636 } // exceptions() 637 638 /** 639 * {@inheritDoc} 640 */ 641 @Override 642 public final BuilderImpl nextControlFlow( final String controlFlow, final Object... args ) 643 { 644 m_Code.nextControlFlow( controlFlow, args ); 645 646 //---* Done *------------------------------------------------------ 647 return this; 648 } // nextControlFlow() 649 650 /** 651 * Returns <i>a reference to</i>the parameters. 652 * 653 * @return The parameters. 654 */ 655 @SuppressWarnings( {"PublicMethodNotExposedInInterface", "AssignmentOrReturnOfFieldWithMutableType"} ) 656 public final List<ParameterSpecImpl> parameters() 657 { 658 return m_Parameters; 659 } // parameters() 660 /** 661 * {@inheritDoc} 662 */ 663 @Override 664 public final BuilderImpl returns( final Type returnType ) 665 { 666 return returns( TypeNameImpl.from( requireNonNullArgument( returnType, "returnType" ) ) ); 667 } // returns() 668 669 /** 670 * {@inheritDoc} 671 */ 672 @Override 673 public final BuilderImpl returns( final Type returnType, final String format, final Object... args ) 674 { 675 return returns( TypeNameImpl.from( requireNonNullArgument( returnType, "returnType" ) ), format, args ); 676 } // returns() 677 678 /** 679 * {@inheritDoc} 680 */ 681 @Override 682 public final BuilderImpl returns( final TypeName returnType ) 683 { 684 checkState( !m_Name.equals( CONSTRUCTOR ), () -> new IllegalStateException( "constructor cannot have return type." ) ); 685 m_ReturnType = (TypeNameImpl) requireNonNullArgument( returnType, "returnType" ); 686 createDebugOutput( m_Composer.addDebugOutput() ) 687 .ifPresent( debug -> m_ReturnComment.addWithoutDebugInfo( debug.asLiteral() ) ); 688 689 //---* Done *------------------------------------------------------ 690 return this; 691 } // returns() 692 693 /** 694 * {@inheritDoc} 695 */ 696 @Override 697 public final BuilderImpl returns( final TypeName returnType, final String format, final Object... args ) 698 { 699 returns( returnType ); 700 m_ReturnComment.addWithoutDebugInfo( format, args ); 701 702 //---* Done *------------------------------------------------------ 703 return this; 704 } // returns() 705 706 /** 707 * {@inheritDoc} 708 */ 709 @Override 710 public final BuilderImpl varargs() { return varargs( true ); } 711 712 /** 713 * {@inheritDoc} 714 */ 715 @Override 716 public final BuilderImpl varargs( final boolean varargs ) 717 { 718 m_Varargs = varargs; 719 720 //---* Done *------------------------------------------------------ 721 return this; 722 } // varargs() 723 } 724 // class BuilderImpl 725 726 /*------------*\ 727 ====** Attributes **======================================================= 728 \*------------*/ 729 /** 730 * The annotations of this method. 731 */ 732 private final List<AnnotationSpecImpl> m_Annotations; 733 734 /** 735 * Lazily initialised return value of 736 * {@link #toString()} 737 * for this instance. 738 */ 739 private final Lazy<String> m_CachedString; 740 741 /** 742 * The code of this method. 743 */ 744 @SuppressWarnings( "UseOfConcreteClass" ) 745 private final CodeBlockImpl m_Code; 746 747 /** 748 * The reference to the factory. 749 */ 750 @SuppressWarnings( "UseOfConcreteClass" ) 751 private final JavaComposer m_Composer; 752 753 /** 754 * The default value of this method; only applicable for annotations. 755 */ 756 @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) 757 private final Optional<CodeBlockImpl> m_DefaultValue; 758 759 /** 760 * The declared exceptions for this method. 761 */ 762 private final List<TypeNameImpl> m_Exceptions; 763 764 /** 765 * The Javadoc comment of this method. 766 */ 767 @SuppressWarnings( "UseOfConcreteClass" ) 768 private final CodeBlockImpl m_Javadoc; 769 770 /** 771 * The modifiers of this method. 772 */ 773 private final Set<Modifier> m_Modifiers; 774 775 /** 776 * The name of this method. 777 */ 778 private final String m_Name; 779 780 /** 781 * The parameters of this method. 782 */ 783 private final List<ParameterSpecImpl> m_Parameters; 784 785 /** 786 * The comment for the return value of the method. 787 */ 788 @SuppressWarnings( "UseOfConcreteClass" ) 789 private final CodeBlockImpl m_ReturnComment; 790 791 /** 792 * The return type of the method. 793 */ 794 @SuppressWarnings( "UseOfConcreteClass" ) 795 private final TypeNameImpl m_ReturnType; 796 797 /** 798 * The static imports. 799 */ 800 private final Set<String> m_StaticImports; 801 802 /** 803 * The type variables of this method. 804 */ 805 private final List<TypeVariableNameImpl> m_TypeVariables; 806 807 /** 808 * The flag that indicates whether a parameter (the last one) is a 809 * {@code varargs} parameter. 810 */ 811 private final boolean m_Varargs; 812 813 /*--------------*\ 814 ====** Constructors **===================================================== 815 \*--------------*/ 816 /** 817 * Creates a new {@code MethodSpecImpl} instance. 818 * 819 * @param builder The builder. 820 */ 821 @SuppressWarnings( {"AccessingNonPublicFieldOfAnotherObject"} ) 822 public MethodSpecImpl( @SuppressWarnings( "UseOfConcreteClass" ) final BuilderImpl builder ) 823 { 824 checkState( !builder.m_Varargs || lastParameterIsArray( builder.m_Parameters ), () -> new ValidationException( "last parameter of varargs method %s must be an array".formatted( builder.m_Name ) ) ); 825 826 final var code = builder.m_Code.build(); 827 checkState( code.isEmpty() || !builder.m_Modifiers.contains( ABSTRACT ), () -> new ValidationException( "abstract method %s cannot have code".formatted( builder.m_Name ) ) ); 828 829 m_Composer = builder.m_Composer; 830 m_Name = builder.m_Name; 831 m_Javadoc = builder.m_Javadoc.build(); 832 m_Annotations = List.copyOf( builder.m_Annotations ); 833 m_Modifiers = Set.copyOf( builder.m_Modifiers ); 834 m_TypeVariables = List.copyOf( builder.m_TypeVariables ); 835 m_ReturnType = builder.m_ReturnType; 836 m_ReturnComment = builder.m_ReturnComment.build(); 837 m_Parameters = List.copyOf( builder.parameters() ); 838 m_Varargs = builder.m_Varargs; 839 m_Exceptions = List.copyOf( builder.exceptions() ); 840 m_DefaultValue = Optional.ofNullable( builder.m_DefaultValue ); 841 m_Code = code; 842 843 final Collection<String> staticImports = new HashSet<>( builder.m_StaticImports ); 844 staticImports.addAll( m_Javadoc.getStaticImports() ); 845 staticImports.addAll( m_ReturnComment.getStaticImports() ); 846 m_Parameters.stream() 847 .map( ParameterSpecImpl::javadoc ) 848 .filter( Optional::isPresent ) 849 .map( codeBlock -> codeBlock.map( block -> (CodeBlockImpl) block ).get().getStaticImports() ) 850 .forEach( staticImports::addAll ); 851 m_DefaultValue.ifPresent( codeBlock -> staticImports.addAll( codeBlock.getStaticImports() ) ); 852 staticImports.addAll( m_Code.getStaticImports() ); 853 m_StaticImports = Set.copyOf( staticImports ); 854 855 m_CachedString = Lazy.use( this::initializeCachedString ); 856 } // MethodSpecImpl() 857 858 /*---------*\ 859 ====** Methods **========================================================== 860 \*---------*/ 861 /** 862 * Returns the default value of this method. 863 * 864 * @return An instance of 865 * {@link Optional} 866 * that holds the default value. 867 */ 868 @SuppressWarnings( "PublicMethodNotExposedInInterface" ) 869 public final Optional<CodeBlockImpl> defaultValue() { return m_DefaultValue; } 870 871 /** 872 * Emits the Javadoc to the given code writer. 873 * 874 * @param codeWriter The code writer. 875 * @throws UncheckedIOException A problem occurred when writing to the 876 * output target. 877 */ 878 private final void emitJavadoc( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter ) throws UncheckedIOException 879 { 880 final var javaDocBuilder = m_Javadoc.toBuilder(); 881 var addNewLine = false; 882 @SuppressWarnings( {"OptionalGetWithoutIsPresent"} ) 883 final var paramComments = m_Parameters.stream() 884 .filter( p -> p.javadoc().isPresent() ) 885 .map( p -> (CodeBlockImpl) p.javadoc().get() ) 886 .toArray( CodeBlockImpl[]::new ); 887 addNewLine = paramComments.length > 0; 888 for( final var comment : paramComments ) 889 { 890 javaDocBuilder.add( comment ); 891 } 892 if( !m_ReturnComment.isEmpty() ) 893 { 894 javaDocBuilder.add( m_Composer.codeBlockOf( "\n@return $L", m_ReturnComment ) ); 895 addNewLine = true; 896 } 897 if( addNewLine ) javaDocBuilder.add( "\n" ); 898 codeWriter.emitJavadoc( javaDocBuilder.build() ); 899 } // emitJavadoc() 900 901 /** 902 * Emits this method to the given code writer. 903 * 904 * @param codeWriter The code writer. 905 * @param enclosingName The name of the type that owns this method. 906 * @param implicitModifiers The implicit modifiers for this method. 907 * @throws UncheckedIOException A problem occurred when writing to the 908 * output target. 909 */ 910 @SuppressWarnings( {"PublicMethodNotExposedInInterface", "OptionalUsedAsFieldOrParameterType"} ) 911 public final void emit( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter, final Optional<String> enclosingName, final Collection<Modifier> implicitModifiers ) throws UncheckedIOException 912 { 913 switch( codeWriter.layout() ) 914 { 915 case LAYOUT_FOUNDATION -> emit4Foundation( codeWriter, enclosingName, implicitModifiers ); 916 case LAYOUT_DEFAULT, LAYOUT_JAVAPOET, LAYOUT_JAVAPOET_WITH_TAB -> emit4JavaPoet( codeWriter, enclosingName, implicitModifiers ); 917 default -> throw new UnsupportedEnumError( codeWriter.layout() ); 918 } 919 } // emit() 920 921 /** 922 * Emits this method to the given code writer, using the Foundation 923 * layout. 924 * 925 * @param codeWriter The code writer. 926 * @param enclosingName The name of the type that owns this method. 927 * @param implicitModifiers The implicit modifiers for this method. 928 * @throws UncheckedIOException A problem occurred when writing to the 929 * output target. 930 */ 931 @SuppressWarnings( {"OptionalUsedAsFieldOrParameterType", "OverlyComplexMethod"} ) 932 private final void emit4Foundation( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter, final Optional<String> enclosingName, final Collection<Modifier> implicitModifiers ) throws UncheckedIOException 933 { 934 emitJavadoc( codeWriter ); 935 codeWriter.emitAnnotations( m_Annotations, false ); 936 codeWriter.emitModifiers( m_Modifiers, implicitModifiers ); 937 938 if( !m_TypeVariables.isEmpty() ) 939 { 940 codeWriter.emitTypeVariables( m_TypeVariables ); 941 codeWriter.emit( " " ); 942 } 943 944 if( isConstructor() ) 945 { 946 /* 947 * Anonymous types do not have a constructor, therefore there is 948 * no check required for the name. 949 */ 950 //noinspection OptionalGetWithoutIsPresent 951 codeWriter.emit( "$L", enclosingName.get() ); 952 } 953 else 954 { 955 codeWriter.emit( "$T $L", m_ReturnType, m_Name ); 956 } 957 958 if( !m_Parameters.isEmpty() ) 959 { 960 codeWriter.emit( "( " ); 961 var firstParameter = true; 962 for( final var iterator = m_Parameters.iterator(); iterator.hasNext(); ) 963 { 964 final var parameter = iterator.next(); 965 if( !firstParameter ) codeWriter.emit( "," ).emitWrappingSpace(); 966 parameter.emit( codeWriter, !iterator.hasNext() && m_Varargs ); 967 firstParameter = false; 968 } 969 codeWriter.emit( " )" ); 970 } 971 else 972 { 973 codeWriter.emit( "()" ); 974 } 975 976 if( m_DefaultValue.isPresent() && !m_DefaultValue.get().isEmpty() ) 977 { 978 codeWriter.emit( " default " ); 979 codeWriter.emit( m_DefaultValue.get() ); 980 } 981 982 if( !m_Exceptions.isEmpty() ) 983 { 984 codeWriter.emitWrappingSpace().emit( "throws" ); 985 var firstException = true; 986 for( final var exception : m_Exceptions ) 987 { 988 if( !firstException ) codeWriter.emit( "," ); 989 codeWriter.emitWrappingSpace().emit( "$T", exception ); 990 firstException = false; 991 } 992 } 993 994 if( hasModifier( ABSTRACT ) ) 995 { 996 codeWriter.emit( ";\n" ); 997 } 998 else if( hasModifier( NATIVE ) ) 999 { 1000 //---* Code is allowed to support stuff like GWT JSNI *------------ 1001 codeWriter.emit( m_Code ); 1002 codeWriter.emit( ";\n" ); 1003 } 1004 else 1005 { 1006 codeWriter.emit( "\n{" ); 1007 1008 if( !m_Code.isEmpty() ) 1009 { 1010 codeWriter.emit( "\n" ) 1011 .indent() 1012 .emit( m_Code ) 1013 .unindent(); 1014 } 1015 1016 if( isConstructor() ) 1017 { 1018 //noinspection OptionalGetWithoutIsPresent 1019 codeWriter.emit( "} // $L()\n", enclosingName.get() ); 1020 } 1021 else 1022 { 1023 codeWriter.emit( "} // $L()\n", m_Name ); 1024 } 1025 } 1026 } // emit4Foundation() 1027 1028 /** 1029 * Emits this method to the given code writer, using the JavaPoet layout. 1030 * 1031 * @param codeWriter The code writer. 1032 * @param enclosingName The name of the type that owns this method. 1033 * @param implicitModifiers The implicit modifiers for this method. 1034 * @throws UncheckedIOException A problem occurred when writing to the 1035 * output target. 1036 */ 1037 @SuppressWarnings( {"OptionalUsedAsFieldOrParameterType", "OverlyComplexMethod"} ) 1038 private final void emit4JavaPoet( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter, final Optional<String> enclosingName, final Collection<Modifier> implicitModifiers ) throws UncheckedIOException 1039 { 1040 emitJavadoc( codeWriter ); 1041 codeWriter.emitAnnotations( m_Annotations, false ); 1042 codeWriter.emitModifiers( m_Modifiers, implicitModifiers ); 1043 1044 if( !m_TypeVariables.isEmpty() ) 1045 { 1046 codeWriter.emitTypeVariables( m_TypeVariables ); 1047 codeWriter.emit( " " ); 1048 } 1049 1050 if( isConstructor() ) 1051 { 1052 /* 1053 * Anonymous types do not have a constructor, therefore there is 1054 * no check required for the name. 1055 */ 1056 //noinspection OptionalGetWithoutIsPresent 1057 codeWriter.emit( "$L($Z", enclosingName.get() ); 1058 } 1059 else 1060 { 1061 codeWriter.emit( "$T $L($Z", m_ReturnType, m_Name ); 1062 } 1063 1064 var firstParameter = true; 1065 for( final var iterator = m_Parameters.iterator(); iterator.hasNext(); ) 1066 { 1067 final var parameter = iterator.next(); 1068 if( !firstParameter ) codeWriter.emit( "," ).emitWrappingSpace(); 1069 parameter.emit( codeWriter, !iterator.hasNext() && m_Varargs ); 1070 firstParameter = false; 1071 } 1072 1073 codeWriter.emit( ")" ); 1074 1075 if( m_DefaultValue.isPresent() && !m_DefaultValue.get().isEmpty() ) 1076 { 1077 codeWriter.emit( " default " ); 1078 codeWriter.emit( m_DefaultValue.get() ); 1079 } 1080 1081 if( !m_Exceptions.isEmpty() ) 1082 { 1083 codeWriter.emitWrappingSpace().emit( "throws" ); 1084 var firstException = true; 1085 for( final var exception : m_Exceptions ) 1086 { 1087 if( !firstException ) codeWriter.emit( "," ); 1088 codeWriter.emitWrappingSpace().emit( "$T", exception ); 1089 firstException = false; 1090 } 1091 } 1092 1093 if( hasModifier( ABSTRACT ) ) 1094 { 1095 codeWriter.emit( ";\n" ); 1096 } 1097 else if( hasModifier( NATIVE ) ) 1098 { 1099 //---* Code is allowed to support stuff like GWT JSNI *------------ 1100 codeWriter.emit( m_Code ); 1101 codeWriter.emit( ";\n" ); 1102 } 1103 else 1104 { 1105 codeWriter.emit( " {\n" ); 1106 1107 codeWriter.indent(); 1108 codeWriter.emit( m_Code ); 1109 codeWriter.unindent(); 1110 1111 codeWriter.emit( "}\n" ); 1112 } 1113 } // emit4JavaPoet() 1114 1115 /** 1116 * {@inheritDoc} 1117 */ 1118 @Override 1119 public final boolean equals( final Object o ) 1120 { 1121 var retValue = this == o; 1122 if( !retValue && (o instanceof final MethodSpecImpl other) ) 1123 { 1124 retValue = m_Composer.equals( other.m_Composer ) && toString().equals( o.toString() ); 1125 } 1126 1127 //---* Done *---------------------------------------------------------- 1128 return retValue; 1129 } // equals() 1130 1131 /** 1132 * Returns the declared exceptions for this method. 1133 * 1134 * @return The declared exceptions. 1135 */ 1136 @SuppressWarnings( "PublicMethodNotExposedInInterface" ) 1137 public final List<TypeNameImpl> exceptions() { return m_Exceptions; } 1138 1139 /** 1140 * Returns the 1141 * {@link JavaComposer} 1142 * factory. 1143 * 1144 * @return The reference to the factory. 1145 */ 1146 @SuppressWarnings( {"PublicMethodNotExposedInInterface"} ) 1147 public final JavaComposer getFactory() { return m_Composer; } 1148 1149 /** 1150 * Returns the static imports for this code block. 1151 * 1152 * @return The static imports. 1153 */ 1154 @SuppressWarnings( "PublicMethodNotExposedInInterface" ) 1155 @API( status = INTERNAL, since = "0.2.0" ) 1156 public final Set<String> getStaticImports() { return m_StaticImports; } 1157 1158 /** 1159 * {@inheritDoc} 1160 */ 1161 @Override 1162 public final int hashCode() { return hash( m_Composer, toString() ); } 1163 1164 /** 1165 * {@inheritDoc} 1166 */ 1167 @Override 1168 public final boolean hasModifier( final Modifier modifier ) { return m_Modifiers.contains( requireNonNullArgument( modifier, "modifier" ) ); } 1169 1170 /** 1171 * The initializer for 1172 * {@link #m_CachedString}. 1173 * 1174 * @return The return value for 1175 * {@link #toString()}. 1176 */ 1177 private final String initializeCachedString() 1178 { 1179 final var resultBuilder = new StringBuilder(); 1180 final var codeWriter = new CodeWriter( m_Composer, resultBuilder ); 1181 try 1182 { 1183 emit( codeWriter, Optional.of( "Constructor" ), Set.of() ); 1184 } 1185 catch( final UncheckedIOException e ) 1186 { 1187 throw new UnexpectedExceptionError( e.getCause() ); 1188 } 1189 final var retValue = resultBuilder.toString(); 1190 1191 //---* Done *---------------------------------------------------------- 1192 return retValue; 1193 } // initializeCachedString() 1194 1195 /** 1196 * {@inheritDoc} 1197 */ 1198 @Override 1199 public final boolean isConstructor() { return m_Name.equals( CONSTRUCTOR ); } 1200 1201 /** 1202 * Checks whether the last entry of the given parameter list is an array. 1203 * 1204 * @param parameters The parameter list. 1205 * @return {@code true} if the last entry of the given parameter list is 1206 * an array type, {@code false} if not. 1207 */ 1208 @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" ) 1209 private static final boolean lastParameterIsArray( final SequencedCollection<ParameterSpecImpl> parameters ) 1210 { 1211 final var retValue = !parameters.isEmpty() && TypeName.asArray( (parameters.getLast().type() ) ).isPresent(); 1212 1213 //---* Done *---------------------------------------------------------- 1214 return retValue; 1215 } // lastParameterIsArray() 1216 1217 /** 1218 * Returns a builder for a regular method. 1219 * 1220 * @param name The name for the method. 1221 * @return The builder. 1222 * 1223 * @deprecated Got obsolete with the introduction of 1224 * {@link JavaComposer}. 1225 */ 1226 @Deprecated( since = "0.2.0", forRemoval = true ) 1227 @API( status = DEPRECATED, since = "0.0.5" ) 1228 public static final BuilderImpl methodBuilder( final CharSequence name ) 1229 { 1230 final var retValue = new BuilderImpl( new JavaComposer(), name ); 1231 1232 //---* Done *---------------------------------------------------------- 1233 return retValue; 1234 } // methodBuilder() 1235 1236 /** 1237 * {@inheritDoc} 1238 */ 1239 @Override 1240 public final Set<Modifier> modifiers() { return m_Modifiers; } 1241 1242 /** 1243 * {@inheritDoc} 1244 */ 1245 @Override 1246 public final String name() { return m_Name; } 1247 1248 /** 1249 * <p>{@summary Returns a new method spec builder for a method that 1250 * overrides the given method.}</p> 1251 * <p>This new builder will copy visibility modifiers, type parameters, 1252 * return type, name, parameters, and throws declarations. An 1253 * {@link Override} 1254 * annotation will be added.</p> 1255 * 1256 * @note In JavaPoet 1.2 through 1.7 this method retained 1257 * annotations from the method and parameters of the overridden 1258 * method. Since JavaPoet 1.8 and in JavaComposer annotations 1259 * must be added separately. 1260 * 1261 * @param method The method to override. 1262 * @return The builder. 1263 * 1264 * @deprecated Got obsolete with the introduction of 1265 * {@link JavaComposer}. 1266 */ 1267 @Deprecated( since = "0.2.0", forRemoval = true ) 1268 @API( status = DEPRECATED, since = "0.0.5" ) 1269 public static final BuilderImpl overriding( final ExecutableElement method ) 1270 { 1271 final var composer = new JavaComposer(); 1272 final var retValue = (BuilderImpl) composer.overridingMethodBuilder( method ); 1273 1274 //---* Done *---------------------------------------------------------- 1275 return retValue; 1276 } // overriding() 1277 1278 /** 1279 * <p>{@summary Returns a new method spec builder that overrides the given 1280 * method as a member of of the given enclosing class.} This will resolve 1281 * type parameters: for example overriding 1282 * {@link Comparable#compareTo} 1283 * in a type that implements {@code Comparable<Movie>}, the {@code T} 1284 * parameter will be resolved to {@code Movie}.</p> 1285 * <p>This will copy its visibility modifiers, type parameters, return 1286 * type, name, parameters, and throws declarations. An 1287 * {@link Override} 1288 * annotation will be added.</p> 1289 * 1290 * @note In JavaPoet 1.2 through 1.7 this method retained 1291 * annotations from the method and parameters of the overridden 1292 * method. Since JavaPoet 1.8 and in JavaComposer annotations 1293 * must be added separately. 1294 * 1295 * @param method The method to override. 1296 * @param enclosing The enclosing class for the method. 1297 * @param types The type variables. 1298 * @return The builder. 1299 * 1300 * @deprecated Got obsolete with the introduction of 1301 * {@link JavaComposer}. 1302 */ 1303 @Deprecated( since = "0.2.0", forRemoval = true ) 1304 @API( status = DEPRECATED, since = "0.0.5" ) 1305 public static final BuilderImpl overriding( final ExecutableElement method, final DeclaredType enclosing, final Types types ) 1306 { 1307 final var composer = new JavaComposer(); 1308 final var retValue = (BuilderImpl) composer.overridingMethodBuilder( method, enclosing, types ); 1309 1310 //---* Done *---------------------------------------------------------- 1311 return retValue; 1312 } // overriding() 1313 1314 /** 1315 * <p>{@summary Returns a new method spec builder for a method that 1316 * overrides the given method.}</p> 1317 * <p>This new builder will copy visibility modifiers, type parameters, 1318 * return type, name, parameters, and throws declarations. An 1319 * {@link Override} 1320 * annotation will be added, but any other annotation will be omitted; 1321 * this is consistent with the behaviour of 1322 * {@link #overriding(ExecutableElement)} 1323 * and 1324 * {@link #overriding(ExecutableElement, DeclaredType, Types)}.</p> 1325 * 1326 * @param method The method to override. 1327 * @return The builder. 1328 * 1329 * @deprecated Got obsolete with the introduction of 1330 * {@link JavaComposer}. 1331 */ 1332 @Deprecated( since = "0.2.0", forRemoval = true ) 1333 @API( status = DEPRECATED, since = "0.0.8" ) 1334 public static final BuilderImpl overriding( final Method method ) 1335 { 1336 final var composer = new JavaComposer(); 1337 final var retValue = (BuilderImpl) composer.overridingMethodBuilder( method ); 1338 1339 //---* Done *---------------------------------------------------------- 1340 return retValue; 1341 } // overriding() 1342 1343 /** 1344 * {@inheritDoc} 1345 */ 1346 @Override 1347 public final Collection<ParameterSpec> parameters() { return List.copyOf( m_Parameters ); } 1348 1349 /** 1350 * {@inheritDoc} 1351 */ 1352 @Override 1353 public final TypeName returnType() 1354 { 1355 final var retValue = nonNull( m_ReturnType ) ? m_ReturnType : VOID_PRIMITIVE; 1356 1357 //---* Done *---------------------------------------------------------- 1358 return retValue; 1359 } // returnType() 1360 1361 /** 1362 * {@inheritDoc} 1363 */ 1364 @Override 1365 public final String signature() 1366 { 1367 final var joiner = new StringJoiner( ", ", format( "%s( ", name() ), " )" ); 1368 joiner.setEmptyValue( format( "%s()", name() ) ); 1369 m_Parameters.stream() 1370 .map( parameter -> parameter.type().toString() ) 1371 .forEach( joiner::add ); 1372 final var retValue = joiner.toString(); 1373 1374 //---* Done *---------------------------------------------------------- 1375 return retValue; 1376 } // signature() 1377 1378 /** 1379 * {@inheritDoc} 1380 */ 1381 @SuppressWarnings( {"AccessingNonPublicFieldOfAnotherObject"} ) 1382 @Override 1383 public final BuilderImpl toBuilder( final boolean omitCode ) 1384 { 1385 final var retValue = new BuilderImpl( m_Composer, m_Name ); 1386 retValue.m_Javadoc.addWithoutDebugInfo( m_Javadoc ); 1387 retValue.m_Annotations.addAll( m_Annotations ); 1388 retValue.m_Modifiers.addAll( m_Modifiers ); 1389 if( omitCode ) retValue.m_Modifiers.add( ABSTRACT ); 1390 retValue.m_TypeVariables.addAll( m_TypeVariables ); 1391 retValue.m_ReturnType = m_ReturnType; 1392 retValue.m_ReturnComment.addWithoutDebugInfo( m_ReturnComment ); 1393 retValue.m_Parameters.addAll( m_Parameters ); 1394 retValue.m_Exceptions.addAll( m_Exceptions ); 1395 if( !omitCode ) retValue.m_Code.addWithoutDebugInfo( m_Code ); 1396 retValue.m_Varargs = m_Varargs; 1397 retValue.m_DefaultValue = m_DefaultValue.orElse( null ); 1398 retValue.m_StaticImports.addAll( m_StaticImports ); 1399 1400 //---* Done *---------------------------------------------------------- 1401 return retValue; 1402 } // toBuilder() 1403 1404 /** 1405 * {@inheritDoc} 1406 */ 1407 @Override 1408 public final String toString() { return m_CachedString.get(); } 1409} 1410// class MethodSpecImpl 1411 1412/* 1413 * End of File 1414 */