001/* 002 * ============================================================================ 003 * Copyright © 2015 Square, Inc. 004 * Copyright for the modifications © 2018-2025 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 1258 2026-06-04 18:33:06Z tquadrat $ 085 * @since 0.0.5 086 * 087 * @UMLGraph.link 088 */ 089@SuppressWarnings( {"ClassWithTooManyFields"} ) 090@ClassVersion( sourceVersion = "$Id: MethodSpecImpl.java 1258 2026-06-04 18:33:06Z 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 1258 2026-06-04 18:33:06Z tquadrat $ 104 * @since 0.0.5 105 * 106 * @UMLGraph.link 107 */ 108 @ClassVersion( sourceVersion = "$Id: MethodSpecImpl.java 1258 2026-06-04 18:33:06Z 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 ), (_,v) -> "not a valid name: %s".formatted( v ) ).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 //noinspection StandardVariableNames 483 for( final var name : requireValidNonNullArgument( names, "names", v -> v.length > 0, (n,_) -> "%s array is empty".formatted( n ) ) ) 484 { 485 m_StaticImports.add( 486 format( 487 "%s.%s", 488 canonicalName, 489 requireValidArgument( 490 name, 491 "name", 492 Objects::nonNull, 493 (_,_) -> "null entry in names array: %s".formatted( Arrays.toString( names ) ) 494 ) 495 ) 496 ); 497 } 498 499 //---* Done *------------------------------------------------------ 500 return this; 501 } // addStaticImport() 502 503 /** 504 * {@inheritDoc} 505 */ 506 @API( status = STABLE, since = "0.2.0" ) 507 @Override 508 public final MethodSpecImpl.BuilderImpl addStaticImport( final Enum<?> constant ) 509 { 510 return addStaticImport( ClassNameImpl.from( requireNonNullArgument( constant, "constant" ).getDeclaringClass() ), constant.name() ); 511 } // addStaticImport() 512 513 /** 514 * {@inheritDoc} 515 */ 516 @Override 517 public final BuilderImpl addTypeVariable( final TypeVariableName typeVariable ) 518 { 519 m_TypeVariables.add( (TypeVariableNameImpl) typeVariable ); 520 521 //---* Done *------------------------------------------------------ 522 return this; 523 } // addTypeVariable() 524 525 /** 526 * {@inheritDoc} 527 */ 528 @Override 529 public final BuilderImpl addTypeVariables( final Iterable<TypeVariableName> typeVariables ) 530 { 531 for( final var typeVariable : requireNonNullArgument( typeVariables, "typeVariables" ) ) 532 { 533 m_TypeVariables.add( (TypeVariableNameImpl) typeVariable ); 534 } 535 536 //---* Done *------------------------------------------------------ 537 return this; 538 } // addTypeVariables() 539 540 /** 541 * {@inheritDoc} 542 */ 543 @Override 544 public final BuilderImpl beginControlFlow( final String controlFlow, final Object... args ) 545 { 546 m_Code.beginControlFlow( controlFlow, args ); 547 548 //---* Done *------------------------------------------------------ 549 return this; 550 } // beginControlFlow() 551 552 /** 553 * {@inheritDoc} 554 */ 555 @Override 556 public final MethodSpecImpl build() 557 { 558 /* 559 * A method with a body cannot be abstract. 560 * We remove the modifier abstract here so that 561 * MethodSpec.toBuilder() will work properly. 562 */ 563 if( !m_Code.isEmpty() ) 564 { 565 m_Modifiers.remove( ABSTRACT ); 566 } 567 final var retValue = new MethodSpecImpl( this ); 568 569 //---* Done *------------------------------------------------------ 570 return retValue; 571 } // build() 572 573 /** 574 * {@inheritDoc} 575 */ 576 @Override 577 public final BuilderImpl defaultValue( final CodeBlock defaultValue ) 578 { 579 checkState( isNull( m_DefaultValue ), () -> new IllegalStateException( "defaultValue was already set" ) ); 580 var codeBlockImpl = (CodeBlockImpl) requireNonNullArgument( defaultValue, "defaultValue" ); 581 if( m_Composer.addDebugOutput() ) 582 { 583 codeBlockImpl = (CodeBlockImpl) createDebugOutput( true ) 584 .map( DebugOutput::asComment ) 585 .map( m_Composer::codeBlockOf ) 586 .map( block -> block.join( " ", defaultValue ) ) 587 .orElse( defaultValue ); 588 } 589 m_DefaultValue = codeBlockImpl; 590 591 //---* Done *------------------------------------------------------ 592 return this; 593 } // defaultValue() 594 595 /** 596 * {@inheritDoc} 597 */ 598 @Override 599 public final BuilderImpl defaultValue( final String format, final Object... args ) 600 { 601 return defaultValue( m_Composer.codeBlockOf( format, args ) ); 602 } // defaultValue() 603 604 /** 605 * {@inheritDoc} 606 */ 607 @Override 608 public final BuilderImpl endControlFlow() 609 { 610 m_Code.endControlFlow(); 611 612 //---* Done *------------------------------------------------------ 613 return this; 614 } // endControlFlow() 615 616 /** 617 * {@inheritDoc} 618 */ 619 @Override 620 public final BuilderImpl endControlFlow( final String controlFlow, final Object... args ) 621 { 622 m_Code.endControlFlow( controlFlow, args ); 623 624 //---* Done *------------------------------------------------------ 625 return this; 626 } // endControlFlow() 627 628 /** 629 * Returns <i>a reference to</i> the declared exceptions. 630 * 631 * @return The exceptions. 632 */ 633 @SuppressWarnings( {"PublicMethodNotExposedInInterface", "AssignmentOrReturnOfFieldWithMutableType"} ) 634 public final Collection<TypeNameImpl> exceptions() 635 { 636 return m_Exceptions ; 637 } // exceptions() 638 639 /** 640 * {@inheritDoc} 641 */ 642 @Override 643 public final BuilderImpl nextControlFlow( final String controlFlow, final Object... args ) 644 { 645 m_Code.nextControlFlow( controlFlow, args ); 646 647 //---* Done *------------------------------------------------------ 648 return this; 649 } // nextControlFlow() 650 651 /** 652 * Returns <i>a reference to</i> the parameters. 653 * 654 * @return The parameters. 655 */ 656 @SuppressWarnings( {"PublicMethodNotExposedInInterface", "AssignmentOrReturnOfFieldWithMutableType"} ) 657 public final List<ParameterSpecImpl> parameters() 658 { 659 return m_Parameters; 660 } // parameters() 661 /** 662 * {@inheritDoc} 663 */ 664 @Override 665 public final BuilderImpl returns( final Type returnType ) 666 { 667 return returns( TypeNameImpl.from( requireNonNullArgument( returnType, "returnType" ) ) ); 668 } // returns() 669 670 /** 671 * {@inheritDoc} 672 */ 673 @Override 674 public final BuilderImpl returns( final Type returnType, final String format, final Object... args ) 675 { 676 return returns( TypeNameImpl.from( requireNonNullArgument( returnType, "returnType" ) ), format, args ); 677 } // returns() 678 679 /** 680 * {@inheritDoc} 681 */ 682 @Override 683 public final BuilderImpl returns( final TypeName returnType ) 684 { 685 checkState( !m_Name.equals( CONSTRUCTOR ), () -> new IllegalStateException( "constructor cannot have return type." ) ); 686 m_ReturnType = (TypeNameImpl) requireNonNullArgument( returnType, "returnType" ); 687 createDebugOutput( m_Composer.addDebugOutput() ) 688 .ifPresent( debug -> m_ReturnComment.addWithoutDebugInfo( debug.asLiteral() ) ); 689 690 //---* Done *------------------------------------------------------ 691 return this; 692 } // returns() 693 694 /** 695 * {@inheritDoc} 696 */ 697 @Override 698 public final BuilderImpl returns( final TypeName returnType, final String format, final Object... args ) 699 { 700 returns( returnType ); 701 m_ReturnComment.addWithoutDebugInfo( format, args ); 702 703 //---* Done *------------------------------------------------------ 704 return this; 705 } // returns() 706 707 /** 708 * {@inheritDoc} 709 */ 710 @Override 711 public final BuilderImpl varargs() { return varargs( true ); } 712 713 /** 714 * {@inheritDoc} 715 */ 716 @Override 717 public final BuilderImpl varargs( final boolean varargs ) 718 { 719 m_Varargs = varargs; 720 721 //---* Done *------------------------------------------------------ 722 return this; 723 } // varargs() 724 } 725 // class BuilderImpl 726 727 /*------------*\ 728 ====** Attributes **======================================================= 729 \*------------*/ 730 /** 731 * The annotations of this method. 732 */ 733 private final List<AnnotationSpecImpl> m_Annotations; 734 735 /** 736 * Lazily initialised return value of 737 * {@link #toString()} 738 * for this instance. 739 */ 740 private final Lazy<String> m_CachedString; 741 742 /** 743 * The code of this method. 744 */ 745 @SuppressWarnings( "UseOfConcreteClass" ) 746 private final CodeBlockImpl m_Code; 747 748 /** 749 * The reference to the factory. 750 */ 751 @SuppressWarnings( "UseOfConcreteClass" ) 752 private final JavaComposer m_Composer; 753 754 /** 755 * The default value of this method; only applicable for annotations. 756 */ 757 @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" ) 758 private final Optional<CodeBlockImpl> m_DefaultValue; 759 760 /** 761 * The declared exceptions for this method. 762 */ 763 private final List<TypeNameImpl> m_Exceptions; 764 765 /** 766 * The Javadoc comment of this method. 767 */ 768 @SuppressWarnings( "UseOfConcreteClass" ) 769 private final CodeBlockImpl m_Javadoc; 770 771 /** 772 * The modifiers of this method. 773 */ 774 private final Set<Modifier> m_Modifiers; 775 776 /** 777 * The name of this method. 778 */ 779 private final String m_Name; 780 781 /** 782 * The parameters of this method. 783 */ 784 private final List<ParameterSpecImpl> m_Parameters; 785 786 /** 787 * The comment for the return value of the method. 788 */ 789 @SuppressWarnings( "UseOfConcreteClass" ) 790 private final CodeBlockImpl m_ReturnComment; 791 792 /** 793 * The return type of the method. 794 */ 795 @SuppressWarnings( "UseOfConcreteClass" ) 796 private final TypeNameImpl m_ReturnType; 797 798 /** 799 * The static imports. 800 */ 801 private final Set<String> m_StaticImports; 802 803 /** 804 * The type variables of this method. 805 */ 806 private final List<TypeVariableNameImpl> m_TypeVariables; 807 808 /** 809 * The flag that indicates whether a parameter (the last one) is a 810 * {@code varargs} parameter. 811 */ 812 private final boolean m_Varargs; 813 814 /*--------------*\ 815 ====** Constructors **===================================================== 816 \*--------------*/ 817 /** 818 * Creates a new {@code MethodSpecImpl} instance. 819 * 820 * @param builder The builder. 821 */ 822 @SuppressWarnings( {"AccessingNonPublicFieldOfAnotherObject"} ) 823 public MethodSpecImpl( @SuppressWarnings( "UseOfConcreteClass" ) final BuilderImpl builder ) 824 { 825 checkState( !builder.m_Varargs || lastParameterIsArray( builder.m_Parameters ), () -> new ValidationException( "last parameter of varargs method %s must be an array".formatted( builder.m_Name ) ) ); 826 827 final var code = builder.m_Code.build(); 828 checkState( code.isEmpty() || !builder.m_Modifiers.contains( ABSTRACT ), () -> new ValidationException( "abstract method %s cannot have code".formatted( builder.m_Name ) ) ); 829 830 m_Composer = builder.m_Composer; 831 m_Name = builder.m_Name; 832 m_Javadoc = builder.m_Javadoc.build(); 833 m_Annotations = List.copyOf( builder.m_Annotations ); 834 m_Modifiers = Set.copyOf( builder.m_Modifiers ); 835 m_TypeVariables = List.copyOf( builder.m_TypeVariables ); 836 m_ReturnType = builder.m_ReturnType; 837 m_ReturnComment = builder.m_ReturnComment.build(); 838 m_Parameters = List.copyOf( builder.parameters() ); 839 m_Varargs = builder.m_Varargs; 840 m_Exceptions = List.copyOf( builder.exceptions() ); 841 m_DefaultValue = Optional.ofNullable( builder.m_DefaultValue ); 842 m_Code = code; 843 844 final Collection<String> staticImports = new HashSet<>( builder.m_StaticImports ); 845 staticImports.addAll( m_Javadoc.getStaticImports() ); 846 staticImports.addAll( m_ReturnComment.getStaticImports() ); 847 m_Parameters.stream() 848 .map( ParameterSpecImpl::javadoc ) 849 .filter( Optional::isPresent ) 850 .map( codeBlock -> codeBlock.map( block -> (CodeBlockImpl) block ).get().getStaticImports() ) 851 .forEach( staticImports::addAll ); 852 m_DefaultValue.ifPresent( codeBlock -> staticImports.addAll( codeBlock.getStaticImports() ) ); 853 staticImports.addAll( m_Code.getStaticImports() ); 854 m_StaticImports = Set.copyOf( staticImports ); 855 856 m_CachedString = Lazy.use( this::initializeCachedString ); 857 } // MethodSpecImpl() 858 859 /*---------*\ 860 ====** Methods **========================================================== 861 \*---------*/ 862 /** 863 * Returns the default value of this method. 864 * 865 * @return An instance of 866 * {@link Optional} 867 * that holds the default value. 868 */ 869 @SuppressWarnings( "PublicMethodNotExposedInInterface" ) 870 public final Optional<CodeBlockImpl> defaultValue() { return m_DefaultValue; } 871 872 /** 873 * Emits the Javadoc to the given code writer. 874 * 875 * @param codeWriter The code writer. 876 * @throws UncheckedIOException A problem occurred when writing to the 877 * output target. 878 */ 879 private final void emitJavadoc( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter ) throws UncheckedIOException 880 { 881 final var javaDocBuilder = m_Javadoc.toBuilder(); 882 var addNewLine = false; 883 @SuppressWarnings( {"OptionalGetWithoutIsPresent"} ) 884 final var paramComments = m_Parameters.stream() 885 .filter( p -> p.javadoc().isPresent() ) 886 .map( p -> (CodeBlockImpl) p.javadoc().get() ) 887 .toArray( CodeBlockImpl[]::new ); 888 addNewLine = paramComments.length > 0; 889 for( final var comment : paramComments ) 890 { 891 javaDocBuilder.add( comment ); 892 } 893 if( !m_ReturnComment.isEmpty() ) 894 { 895 javaDocBuilder.add( m_Composer.codeBlockOf( "\n@return $L", m_ReturnComment ) ); 896 addNewLine = true; 897 } 898 if( addNewLine ) javaDocBuilder.add( "\n" ); 899 codeWriter.emitJavadoc( javaDocBuilder.build() ); 900 } // emitJavadoc() 901 902 /** 903 * Emits this method to the given code writer. 904 * 905 * @param codeWriter The code writer. 906 * @param enclosingName The name of the type that owns this method. 907 * @param implicitModifiers The implicit modifiers for this method. 908 * @throws UncheckedIOException A problem occurred when writing to the 909 * output target. 910 */ 911 @SuppressWarnings( {"PublicMethodNotExposedInInterface", "OptionalUsedAsFieldOrParameterType"} ) 912 public final void emit( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter, final Optional<String> enclosingName, final Collection<Modifier> implicitModifiers ) throws UncheckedIOException 913 { 914 switch( codeWriter.layout() ) 915 { 916 case LAYOUT_FOUNDATION -> emit4Foundation( codeWriter, enclosingName, implicitModifiers ); 917 case LAYOUT_DEFAULT, LAYOUT_JAVAPOET, LAYOUT_JAVAPOET_WITH_TAB -> emit4JavaPoet( codeWriter, enclosingName, implicitModifiers ); 918 default -> throw new UnsupportedEnumError( codeWriter.layout() ); 919 } 920 } // emit() 921 922 /** 923 * Emits this method to the given code writer, using the Foundation 924 * layout. 925 * 926 * @param codeWriter The code writer. 927 * @param enclosingName The name of the type that owns this method. 928 * @param implicitModifiers The implicit modifiers for this method. 929 * @throws UncheckedIOException A problem occurred when writing to the 930 * output target. 931 */ 932 @SuppressWarnings( {"OptionalUsedAsFieldOrParameterType", "OverlyComplexMethod"} ) 933 private final void emit4Foundation( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter, final Optional<String> enclosingName, final Collection<Modifier> implicitModifiers ) throws UncheckedIOException 934 { 935 emitJavadoc( codeWriter ); 936 codeWriter.emitAnnotations( m_Annotations, false ); 937 codeWriter.emitModifiers( m_Modifiers, implicitModifiers ); 938 939 if( !m_TypeVariables.isEmpty() ) 940 { 941 codeWriter.emitTypeVariables( m_TypeVariables ); 942 codeWriter.emit( " " ); 943 } 944 945 if( isConstructor() ) 946 { 947 /* 948 * Anonymous types do not have a constructor, therefore there is 949 * no check required for the name. 950 */ 951 //noinspection OptionalGetWithoutIsPresent 952 codeWriter.emit( "$L", enclosingName.get() ); 953 } 954 else 955 { 956 codeWriter.emit( "$T $L", m_ReturnType, m_Name ); 957 } 958 959 if( !m_Parameters.isEmpty() ) 960 { 961 codeWriter.emit( "( " ); 962 var firstParameter = true; 963 for( final var iterator = m_Parameters.iterator(); iterator.hasNext(); ) 964 { 965 final var parameter = iterator.next(); 966 if( !firstParameter ) codeWriter.emit( "," ).emitWrappingSpace(); 967 parameter.emit( codeWriter, !iterator.hasNext() && m_Varargs ); 968 firstParameter = false; 969 } 970 codeWriter.emit( " )" ); 971 } 972 else 973 { 974 codeWriter.emit( "()" ); 975 } 976 977 if( m_DefaultValue.isPresent() && !m_DefaultValue.get().isEmpty() ) 978 { 979 codeWriter.emit( " default " ); 980 codeWriter.emit( m_DefaultValue.get() ); 981 } 982 983 if( !m_Exceptions.isEmpty() ) 984 { 985 codeWriter.emitWrappingSpace().emit( "throws" ); 986 var firstException = true; 987 for( final var exception : m_Exceptions ) 988 { 989 if( !firstException ) codeWriter.emit( "," ); 990 codeWriter.emitWrappingSpace().emit( "$T", exception ); 991 firstException = false; 992 } 993 } 994 995 if( hasModifier( ABSTRACT ) ) 996 { 997 codeWriter.emit( ";\n" ); 998 } 999 else if( hasModifier( NATIVE ) ) 1000 { 1001 //---* Code is allowed to support stuff like GWT JSNI *------------ 1002 codeWriter.emit( m_Code ); 1003 codeWriter.emit( ";\n" ); 1004 } 1005 else 1006 { 1007 codeWriter.emit( "\n{" ); 1008 1009 if( !m_Code.isEmpty() ) 1010 { 1011 codeWriter.emit( "\n" ) 1012 .indent() 1013 .emit( m_Code ) 1014 .unindent(); 1015 } 1016 1017 if( isConstructor() ) 1018 { 1019 //noinspection OptionalGetWithoutIsPresent 1020 codeWriter.emit( "} // $L()\n", enclosingName.get() ); 1021 } 1022 else 1023 { 1024 codeWriter.emit( "} // $L()\n", m_Name ); 1025 } 1026 } 1027 } // emit4Foundation() 1028 1029 /** 1030 * Emits this method to the given code writer, using the JavaPoet layout. 1031 * 1032 * @param codeWriter The code writer. 1033 * @param enclosingName The name of the type that owns this method. 1034 * @param implicitModifiers The implicit modifiers for this method. 1035 * @throws UncheckedIOException A problem occurred when writing to the 1036 * output target. 1037 */ 1038 @SuppressWarnings( {"OptionalUsedAsFieldOrParameterType", "OverlyComplexMethod"} ) 1039 private final void emit4JavaPoet( @SuppressWarnings( "UseOfConcreteClass" ) final CodeWriter codeWriter, final Optional<String> enclosingName, final Collection<Modifier> implicitModifiers ) throws UncheckedIOException 1040 { 1041 emitJavadoc( codeWriter ); 1042 codeWriter.emitAnnotations( m_Annotations, false ); 1043 codeWriter.emitModifiers( m_Modifiers, implicitModifiers ); 1044 1045 if( !m_TypeVariables.isEmpty() ) 1046 { 1047 codeWriter.emitTypeVariables( m_TypeVariables ); 1048 codeWriter.emit( " " ); 1049 } 1050 1051 if( isConstructor() ) 1052 { 1053 /* 1054 * Anonymous types do not have a constructor, therefore there is 1055 * no check required for the name. 1056 */ 1057 //noinspection OptionalGetWithoutIsPresent 1058 codeWriter.emit( "$L($Z", enclosingName.get() ); 1059 } 1060 else 1061 { 1062 codeWriter.emit( "$T $L($Z", m_ReturnType, m_Name ); 1063 } 1064 1065 var firstParameter = true; 1066 for( final var iterator = m_Parameters.iterator(); iterator.hasNext(); ) 1067 { 1068 final var parameter = iterator.next(); 1069 if( !firstParameter ) codeWriter.emit( "," ).emitWrappingSpace(); 1070 parameter.emit( codeWriter, !iterator.hasNext() && m_Varargs ); 1071 firstParameter = false; 1072 } 1073 1074 codeWriter.emit( ")" ); 1075 1076 if( m_DefaultValue.isPresent() && !m_DefaultValue.get().isEmpty() ) 1077 { 1078 codeWriter.emit( " default " ); 1079 codeWriter.emit( m_DefaultValue.get() ); 1080 } 1081 1082 if( !m_Exceptions.isEmpty() ) 1083 { 1084 codeWriter.emitWrappingSpace().emit( "throws" ); 1085 var firstException = true; 1086 for( final var exception : m_Exceptions ) 1087 { 1088 if( !firstException ) codeWriter.emit( "," ); 1089 codeWriter.emitWrappingSpace().emit( "$T", exception ); 1090 firstException = false; 1091 } 1092 } 1093 1094 if( hasModifier( ABSTRACT ) ) 1095 { 1096 codeWriter.emit( ";\n" ); 1097 } 1098 else if( hasModifier( NATIVE ) ) 1099 { 1100 //---* Code is allowed to support stuff like GWT JSNI *------------ 1101 codeWriter.emit( m_Code ); 1102 codeWriter.emit( ";\n" ); 1103 } 1104 else 1105 { 1106 codeWriter.emit( " {\n" ); 1107 1108 codeWriter.indent(); 1109 codeWriter.emit( m_Code ); 1110 codeWriter.unindent(); 1111 1112 codeWriter.emit( "}\n" ); 1113 } 1114 } // emit4JavaPoet() 1115 1116 /** 1117 * {@inheritDoc} 1118 */ 1119 @Override 1120 public final boolean equals( final Object o ) 1121 { 1122 var retValue = this == o; 1123 if( !retValue && (o instanceof final MethodSpecImpl other) ) 1124 { 1125 retValue = m_Composer.equals( other.m_Composer ) && toString().equals( o.toString() ); 1126 } 1127 1128 //---* Done *---------------------------------------------------------- 1129 return retValue; 1130 } // equals() 1131 1132 /** 1133 * Returns the declared exceptions for this method. 1134 * 1135 * @return The declared exceptions. 1136 */ 1137 @SuppressWarnings( "PublicMethodNotExposedInInterface" ) 1138 public final List<TypeNameImpl> exceptions() { return m_Exceptions; } 1139 1140 /** 1141 * Returns the 1142 * {@link JavaComposer} 1143 * factory. 1144 * 1145 * @return The reference to the factory. 1146 */ 1147 @SuppressWarnings( {"PublicMethodNotExposedInInterface"} ) 1148 public final JavaComposer getFactory() { return m_Composer; } 1149 1150 /** 1151 * Returns the static imports for this code block. 1152 * 1153 * @return The static imports. 1154 */ 1155 @SuppressWarnings( "PublicMethodNotExposedInInterface" ) 1156 @API( status = INTERNAL, since = "0.2.0" ) 1157 public final Set<String> getStaticImports() { return m_StaticImports; } 1158 1159 /** 1160 * {@inheritDoc} 1161 */ 1162 @Override 1163 public final int hashCode() { return hash( m_Composer, toString() ); } 1164 1165 /** 1166 * {@inheritDoc} 1167 */ 1168 @Override 1169 public final boolean hasModifier( final Modifier modifier ) { return m_Modifiers.contains( requireNonNullArgument( modifier, "modifier" ) ); } 1170 1171 /** 1172 * The initialiser for 1173 * {@link #m_CachedString}. 1174 * 1175 * @return The return value for 1176 * {@link #toString()}. 1177 */ 1178 private final String initializeCachedString() 1179 { 1180 final var resultBuilder = new StringBuilder(); 1181 final var codeWriter = new CodeWriter( m_Composer, resultBuilder ); 1182 try 1183 { 1184 emit( codeWriter, Optional.of( "Constructor" ), Set.of() ); 1185 } 1186 catch( final UncheckedIOException e ) 1187 { 1188 throw new UnexpectedExceptionError( e.getCause() ); 1189 } 1190 final var retValue = resultBuilder.toString(); 1191 1192 //---* Done *---------------------------------------------------------- 1193 return retValue; 1194 } // initializeCachedString() 1195 1196 /** 1197 * {@inheritDoc} 1198 */ 1199 @Override 1200 public final boolean isConstructor() { return m_Name.equals( CONSTRUCTOR ); } 1201 1202 /** 1203 * Checks whether the last entry of the given parameter list is an array. 1204 * 1205 * @param parameters The parameter list. 1206 * @return {@true} if the last entry of the given parameter list is 1207 * an array type, {@false} if not. 1208 */ 1209 @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" ) 1210 private static final boolean lastParameterIsArray( final SequencedCollection<ParameterSpecImpl> parameters ) 1211 { 1212 final var retValue = !parameters.isEmpty() && TypeName.asArray( (parameters.getLast().type() ) ).isPresent(); 1213 1214 //---* Done *---------------------------------------------------------- 1215 return retValue; 1216 } // lastParameterIsArray() 1217 1218 /** 1219 * Returns a builder for a regular method. 1220 * 1221 * @param name The name for the method. 1222 * @return The builder. 1223 * 1224 * @deprecated Got obsolete with the introduction of 1225 * {@link JavaComposer}. 1226 */ 1227 @Deprecated( since = "0.2.0", forRemoval = true ) 1228 @API( status = DEPRECATED, since = "0.0.5" ) 1229 public static final BuilderImpl methodBuilder( final CharSequence name ) 1230 { 1231 final var retValue = new BuilderImpl( new JavaComposer(), name ); 1232 1233 //---* Done *---------------------------------------------------------- 1234 return retValue; 1235 } // methodBuilder() 1236 1237 /** 1238 * {@inheritDoc} 1239 */ 1240 @Override 1241 public final Set<Modifier> modifiers() { return m_Modifiers; } 1242 1243 /** 1244 * {@inheritDoc} 1245 */ 1246 @Override 1247 public final String name() { return m_Name; } 1248 1249 /** 1250 * <p>{@summary Returns a new method spec builder for a method that 1251 * overrides the given method.}</p> 1252 * <p>This new builder will copy visibility modifiers, type parameters, 1253 * return type, name, parameters, and throws declarations. An 1254 * {@link Override} 1255 * annotation will be added.</p> 1256 * 1257 * @note In JavaPoet 1.2 through 1.7 this method retained 1258 * annotations from the method and parameters of the overridden 1259 * method. Since JavaPoet 1.8 and in JavaComposer annotations 1260 * must be added separately. 1261 * 1262 * @param method The method to override. 1263 * @return The builder. 1264 * 1265 * @deprecated Got obsolete with the introduction of 1266 * {@link JavaComposer}. 1267 */ 1268 @Deprecated( since = "0.2.0", forRemoval = true ) 1269 @API( status = DEPRECATED, since = "0.0.5" ) 1270 public static final BuilderImpl overriding( final ExecutableElement method ) 1271 { 1272 final var composer = new JavaComposer(); 1273 final var retValue = (BuilderImpl) composer.overridingMethodBuilder( method ); 1274 1275 //---* Done *---------------------------------------------------------- 1276 return retValue; 1277 } // overriding() 1278 1279 /** 1280 * <p>{@summary Returns a new method spec builder that overrides the given 1281 * method as a member of of the given enclosing class.} This will resolve 1282 * type parameters: for example overriding 1283 * {@link Comparable#compareTo} 1284 * in a type that implements {@code Comparable<Movie>}, the {@code T} 1285 * parameter will be resolved to {@code Movie}.</p> 1286 * <p>This will copy its visibility modifiers, type parameters, return 1287 * type, name, parameters, and throws declarations. An 1288 * {@link Override} 1289 * annotation will be added.</p> 1290 * 1291 * @note In JavaPoet 1.2 through 1.7 this method retained 1292 * annotations from the method and parameters of the overridden 1293 * method. Since JavaPoet 1.8 and in JavaComposer annotations 1294 * must be added separately. 1295 * 1296 * @param method The method to override. 1297 * @param enclosing The enclosing class for the method. 1298 * @param types The type variables. 1299 * @return The builder. 1300 * 1301 * @deprecated Got obsolete with the introduction of 1302 * {@link JavaComposer}. 1303 */ 1304 @Deprecated( since = "0.2.0", forRemoval = true ) 1305 @API( status = DEPRECATED, since = "0.0.5" ) 1306 public static final BuilderImpl overriding( final ExecutableElement method, final DeclaredType enclosing, final Types types ) 1307 { 1308 final var composer = new JavaComposer(); 1309 final var retValue = (BuilderImpl) composer.overridingMethodBuilder( method, enclosing, types ); 1310 1311 //---* Done *---------------------------------------------------------- 1312 return retValue; 1313 } // overriding() 1314 1315 /** 1316 * <p>{@summary Returns a new method spec builder for a method that 1317 * overrides the given method.}</p> 1318 * <p>This new builder will copy visibility modifiers, type parameters, 1319 * return type, name, parameters, and throws declarations. An 1320 * {@link Override} 1321 * annotation will be added, but any other annotation will be omitted; 1322 * this is consistent with the behaviour of 1323 * {@link #overriding(ExecutableElement)} 1324 * and 1325 * {@link #overriding(ExecutableElement, DeclaredType, Types)}.</p> 1326 * 1327 * @param method The method to override. 1328 * @return The builder. 1329 * 1330 * @deprecated Got obsolete with the introduction of 1331 * {@link JavaComposer}. 1332 */ 1333 @Deprecated( since = "0.2.0", forRemoval = true ) 1334 @API( status = DEPRECATED, since = "0.0.8" ) 1335 public static final BuilderImpl overriding( final Method method ) 1336 { 1337 final var composer = new JavaComposer(); 1338 final var retValue = (BuilderImpl) composer.overridingMethodBuilder( method ); 1339 1340 //---* Done *---------------------------------------------------------- 1341 return retValue; 1342 } // overriding() 1343 1344 /** 1345 * {@inheritDoc} 1346 */ 1347 @Override 1348 public final Collection<ParameterSpec> parameters() { return List.copyOf( m_Parameters ); } 1349 1350 /** 1351 * {@inheritDoc} 1352 */ 1353 @Override 1354 public final TypeName returnType() 1355 { 1356 final var retValue = nonNull( m_ReturnType ) ? m_ReturnType : VOID_PRIMITIVE; 1357 1358 //---* Done *---------------------------------------------------------- 1359 return retValue; 1360 } // returnType() 1361 1362 /** 1363 * {@inheritDoc} 1364 */ 1365 @Override 1366 public final String signature() 1367 { 1368 final var joiner = new StringJoiner( ", ", format( "%s( ", name() ), " )" ); 1369 joiner.setEmptyValue( format( "%s()", name() ) ); 1370 m_Parameters.stream() 1371 .map( parameter -> parameter.type().toString() ) 1372 .forEach( joiner::add ); 1373 final var retValue = joiner.toString(); 1374 1375 //---* Done *---------------------------------------------------------- 1376 return retValue; 1377 } // signature() 1378 1379 /** 1380 * {@inheritDoc} 1381 */ 1382 @SuppressWarnings( {"AccessingNonPublicFieldOfAnotherObject"} ) 1383 @Override 1384 public final BuilderImpl toBuilder( final boolean omitCode ) 1385 { 1386 final var retValue = new BuilderImpl( m_Composer, m_Name ); 1387 retValue.m_Javadoc.addWithoutDebugInfo( m_Javadoc ); 1388 retValue.m_Annotations.addAll( m_Annotations ); 1389 retValue.m_Modifiers.addAll( m_Modifiers ); 1390 if( omitCode ) retValue.m_Modifiers.add( ABSTRACT ); 1391 retValue.m_TypeVariables.addAll( m_TypeVariables ); 1392 retValue.m_ReturnType = m_ReturnType; 1393 retValue.m_ReturnComment.addWithoutDebugInfo( m_ReturnComment ); 1394 retValue.m_Parameters.addAll( m_Parameters ); 1395 retValue.m_Exceptions.addAll( m_Exceptions ); 1396 if( !omitCode ) retValue.m_Code.addWithoutDebugInfo( m_Code ); 1397 retValue.m_Varargs = m_Varargs; 1398 retValue.m_DefaultValue = m_DefaultValue.orElse( null ); 1399 retValue.m_StaticImports.addAll( m_StaticImports ); 1400 1401 //---* Done *---------------------------------------------------------- 1402 return retValue; 1403 } // toBuilder() 1404 1405 /** 1406 * {@inheritDoc} 1407 */ 1408 @Override 1409 public final String toString() { return m_CachedString.get(); } 1410} 1411// class MethodSpecImpl 1412 1413/* 1414 * End of File 1415 */