001/*
002 * ============================================================================
003 *  Copyright © 2002-2026 by Thomas Thrien.
004 *  All Rights Reserved.
005 * ============================================================================
006 *  Licensed to the public under the agreements of the GNU Lesser General Public
007 *  License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *       http://www.gnu.org/licenses/lgpl.html
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 *  License for the specific language governing permissions and limitations
015 *  under the License.
016 */
017
018package org.tquadrat.foundation.javacomposer;
019
020import org.apiguardian.api.API;
021import org.tquadrat.foundation.annotation.ClassVersion;
022import org.tquadrat.foundation.annotation.UtilityClass;
023import org.tquadrat.foundation.exception.PrivateConstructorForStaticClassCalledError;
024import org.tquadrat.foundation.exception.ValidationException;
025import org.tquadrat.foundation.javacomposer.internal.AnnotationSpecImpl;
026import org.tquadrat.foundation.javacomposer.internal.AnnotationSpecImpl.BuilderImpl;
027import org.tquadrat.foundation.javacomposer.internal.AnnotationTypeSpecImpl;
028import org.tquadrat.foundation.javacomposer.internal.AnnotationValueVisitor;
029import org.tquadrat.foundation.javacomposer.internal.ClassNameImpl;
030import org.tquadrat.foundation.javacomposer.internal.ClassSpecImpl;
031import org.tquadrat.foundation.javacomposer.internal.CodeBlockImpl;
032import org.tquadrat.foundation.javacomposer.internal.EnumSpecImpl;
033import org.tquadrat.foundation.javacomposer.internal.FieldSpecImpl;
034import org.tquadrat.foundation.javacomposer.internal.InterfaceSpecImpl;
035import org.tquadrat.foundation.javacomposer.internal.JavaFileImpl;
036import org.tquadrat.foundation.javacomposer.internal.LambdaSpecImpl;
037import org.tquadrat.foundation.javacomposer.internal.MethodSpecImpl;
038import org.tquadrat.foundation.javacomposer.internal.ParameterSpecImpl;
039import org.tquadrat.foundation.javacomposer.internal.RecordSpecImpl;
040import org.tquadrat.foundation.javacomposer.internal.TypeNameImpl;
041import org.tquadrat.foundation.javacomposer.internal.TypeSpecImpl;
042import org.tquadrat.foundation.lang.Lazy;
043import org.tquadrat.foundation.lang.Objects;
044import org.tquadrat.foundation.util.JavaUtils;
045
046import javax.lang.model.SourceVersion;
047import javax.lang.model.element.AnnotationMirror;
048import javax.lang.model.element.ExecutableElement;
049import javax.lang.model.element.Modifier;
050import javax.lang.model.element.TypeElement;
051import javax.lang.model.element.VariableElement;
052import javax.lang.model.type.DeclaredType;
053import javax.lang.model.type.ExecutableType;
054import javax.lang.model.type.TypeVariable;
055import javax.lang.model.util.Types;
056import java.lang.annotation.Annotation;
057import java.lang.reflect.Array;
058import java.lang.reflect.InvocationTargetException;
059import java.lang.reflect.Method;
060import java.lang.reflect.Parameter;
061import java.lang.reflect.Type;
062import java.util.Collection;
063import java.util.LinkedHashSet;
064import java.util.List;
065import java.util.Optional;
066import java.util.function.Supplier;
067
068import static java.lang.String.format;
069import static java.util.Arrays.sort;
070import static java.util.Arrays.stream;
071import static java.util.Comparator.comparing;
072import static java.util.stream.Collectors.joining;
073import static javax.lang.model.element.Modifier.ABSTRACT;
074import static javax.lang.model.element.Modifier.DEFAULT;
075import static javax.lang.model.element.Modifier.FINAL;
076import static javax.lang.model.element.Modifier.PRIVATE;
077import static javax.lang.model.element.Modifier.PUBLIC;
078import static javax.lang.model.element.Modifier.STATIC;
079import static org.apiguardian.api.API.Status.STABLE;
080import static org.tquadrat.foundation.javacomposer.Layout.LAYOUT_DEFAULT;
081import static org.tquadrat.foundation.javacomposer.MethodSpec.CONSTRUCTOR;
082import static org.tquadrat.foundation.javacomposer.Primitives.BOOLEAN;
083import static org.tquadrat.foundation.javacomposer.Primitives.INT;
084import static org.tquadrat.foundation.lang.CommonConstants.EMPTY_STRING;
085import static org.tquadrat.foundation.lang.Objects.deepEquals;
086import static org.tquadrat.foundation.lang.Objects.hash;
087import static org.tquadrat.foundation.lang.Objects.isNull;
088import static org.tquadrat.foundation.lang.Objects.nonNull;
089import static org.tquadrat.foundation.lang.Objects.require;
090import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
091import static org.tquadrat.foundation.lang.Objects.requireNotEmptyArgument;
092import static org.tquadrat.foundation.lang.Objects.requireValidNonNullArgument;
093import static org.tquadrat.foundation.util.JavaUtils.translateModifiers;
094
095/**
096 *  <p>{@summary The factory for the various JavaComposer artefacts.}</p>
097 *  <p>Instances of this class do not maintain a state, therefore they are
098 *  thread-safe without any synchronisation.</p>
099 *
100 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
101 *  @version $Id: JavaComposer.java 1163 2026-03-20 15:28:33Z tquadrat $
102 *  @since 0.2.0
103 *
104 *  @UMLGraph.link
105 */
106@SuppressWarnings( {"OverlyCoupledClass", "ClassWithTooManyMethods", "OverlyComplexClass"} )
107@ClassVersion( sourceVersion = "$Id: JavaComposer.java 1163 2026-03-20 15:28:33Z tquadrat $" )
108@API( status = STABLE, since = "0.2.0" )
109public final class JavaComposer
110{
111        /*-----------*\
112    ====** Constants **========================================================
113        \*-----------*/
114    /**
115     *  The Javadoc tag for inherited documentation: {@value}.
116     */
117    public static final String JAVADOC_TAG_INHERITDOC = "{@inheritDoc}";
118
119    /**
120     *  The Javadoc tag for a constant value: {@value}.
121     */
122    public static final String JAVADOC_TAG_VALUE = "{@value}";
123
124    /**
125     *  Message: {@value}.
126     */
127    public static final String MSG_CannotOverrideFinalClass = "Cannot override method on final class '%s'";
128
129    /**
130     *  Message: {@value}.
131     */
132    public static final String MSG_CannotOverrideMethod = "Cannot override method with modifier '%s'";
133
134        /*------------*\
135    ====** Attributes **=======================================================
136        \*------------*/
137    /**
138     *  If set to {@code true}, some debug information will be added to the
139     *  output.
140     */
141    private final boolean m_AddDebugOutput;
142
143    /**
144     *  The {@code @ClassVersion} annotation.
145     */
146    @SuppressWarnings( "FieldNamingConvention" )
147    private final Lazy<AnnotationSpec> m_Annotation_ClassVersion;
148
149    /**
150     *  The {@code @UtilityClass} annotation.
151     */
152    @SuppressWarnings( "FieldNamingConvention" )
153    private final Lazy<AnnotationSpec> m_Annotation_UtilityClass;
154
155    /**
156     *  The Javadoc comment for an overriding method.
157     */
158    @SuppressWarnings( "FieldNamingConvention" )
159    private final Lazy<CodeBlock> m_JavaDoc_InheritDoc;
160
161    /**
162     *  The layout that is used to format the output.
163     */
164    private final Layout m_Layout;
165
166    /**
167     *  The maximum number of fields for a class; if this number is exceeded,
168     *  an annotation
169     *  {@link SuppressWarnings &#64;SuppressWarnings}
170     *  with
171     *  {@link SuppressableWarnings#CLASS_WITH_TOO_MANY_FIELDS}
172     *  will be added to the class.
173     */
174    @SuppressWarnings( "MagicNumber" )
175    private int m_MaxFields = 16;
176
177    /**
178     *  The maximum number of methods for a class; if this number is exceeded,
179     *  an annotation
180     *  {@link SuppressWarnings &#64;SuppressWarnings}
181     *  with
182     *  {@link SuppressableWarnings#CLASS_WITH_TOO_MANY_METHODS}
183     *  will be added to the class.
184     */
185    @SuppressWarnings( "MagicNumber" )
186    private int m_MaxMethods = 20;
187
188    /**
189     *  A predefined {@code equals()} method.
190     */
191    @SuppressWarnings( "FieldNamingConvention" )
192    private final Lazy<MethodSpec> m_Method_Equals;
193
194    /**
195     *  A predefined {@code hashCode()} method.
196     */
197    @SuppressWarnings( "FieldNamingConvention" )
198    private final Lazy<MethodSpec> m_Method_HashCode;
199
200    /**
201     *  A predefined {@code toString()} method.
202     */
203    @SuppressWarnings( "FieldNamingConvention" )
204    private final Lazy<MethodSpec> m_Method_ToString;
205
206        /*--------------*\
207    ====** Constructors **=====================================================
208        \*--------------*/
209    /**
210     *  Creates a new instance of {@code JavaComposer} that uses the default
211     *  {@link Layout#LAYOUT_DEFAULT Layout}.
212     */
213    public JavaComposer()
214    {
215        this( LAYOUT_DEFAULT, false );
216    }   //  JavaComposer()
217
218    /**
219     *  Creates a new instance of {@code JavaComposer}.
220     *
221     *  @param  layout  The layout that is used to format the output.
222     */
223    public JavaComposer( final Layout layout )
224    {
225        this( layout, false );
226    }   //  JavaComposer()
227
228    /**
229     *  Creates a new instance of {@code JavaComposer} that uses the default
230     *  {@link Layout#LAYOUT_DEFAULT Layout} and adds some debug information
231     *  to the output.
232     *
233     *  @param  addDebugOutput  {@code true} if debug information should be
234     *      added,  {@code false} if not.
235     */
236    public JavaComposer( final boolean addDebugOutput )
237    {
238        this( LAYOUT_DEFAULT, addDebugOutput );
239    }   //  JavaComposer()
240
241    /**
242     *  Creates a new instance of {@code JavaComposer}.
243     *
244     *  @param  layout  The layout that is used to format the output.
245     *  @param  addDebugOutput  {@code true} if debug information should be
246     *      added,  {@code false} if not.
247     */
248    public JavaComposer( final Layout layout, final boolean addDebugOutput )
249    {
250        m_Layout = requireNonNullArgument( layout, "layout" );
251        m_AddDebugOutput = addDebugOutput;
252
253        //---* The inherited doc comment *-------------------------------------
254        final var codeBlockSupplier = (Supplier<CodeBlock>) () ->
255        {
256            final var retValue = new CodeBlockImpl.BuilderImpl( this )
257                .addWithoutDebugInfo( "$L\n", JAVADOC_TAG_INHERITDOC )
258                .build();
259
260            //---* Done *------------------------------------------------------
261            return retValue;
262        };
263        m_JavaDoc_InheritDoc = Lazy.use( codeBlockSupplier );
264        final var inheritDocComment = codeBlockSupplier.get();
265
266        //---* The @ClassVersion annotation *----------------------------------
267        final var annotationSpecSupplierClassVersion = (Supplier<AnnotationSpec>) () ->
268        {
269            final var retValue = annotationBuilder( ClassVersion.class )
270                .forceInline( true )
271                .addMember( "sourceVersion", "$S", "Generated with JavaComposer" )
272                .addMember( "isGenerated", "$L", "true" )
273                .build();
274
275            //---* Done *------------------------------------------------------
276            return retValue;
277        };
278        m_Annotation_ClassVersion = Lazy.use( annotationSpecSupplierClassVersion );
279
280        //---* The @UtilityClass annotation *----------------------------------
281        final var annotationSpecSupplierUtilityClass = (Supplier<AnnotationSpec>) () ->
282        {
283            final var retValue = annotationBuilder( UtilityClass.class )
284                .forceInline( true )
285                .build();
286
287            //---* Done *------------------------------------------------------
288            return retValue;
289        };
290        m_Annotation_UtilityClass = Lazy.use( annotationSpecSupplierUtilityClass );
291
292        //---* The equals() method *-------------------------------------------
293        var methodSpecSupplier = (Supplier<MethodSpec>) () ->
294        {
295            final var retValue = methodBuilder( "equals" )
296                .addJavadoc( inheritDocComment )
297                .addAnnotation( Override.class )
298                .addModifiers( PUBLIC )
299                .addParameter( Object.class, "o", FINAL )
300                .returns( BOOLEAN )
301                .build();
302
303            //---* Done *------------------------------------------------------
304            return retValue;
305        };
306        m_Method_Equals = Lazy.use( methodSpecSupplier );
307
308        //---* The hashCode() method *-----------------------------------------
309        methodSpecSupplier = () ->
310        {
311            final var retValue = methodBuilder( "hashCode" )
312                .addJavadoc( inheritDocComment )
313                .addAnnotation( Override.class )
314                .addModifiers( PUBLIC )
315                .returns( INT )
316                .build();
317
318            //---* Done *------------------------------------------------------
319            return retValue;
320        };
321        m_Method_HashCode = Lazy.use( methodSpecSupplier );
322
323        //---* The toString() method *-----------------------------------------
324        methodSpecSupplier = () ->
325        {
326            final var retValue = methodBuilder( "toString" )
327                .addJavadoc( inheritDocComment )
328                .addAnnotation( Override.class )
329                .addModifiers( PUBLIC )
330                .returns( String.class )
331                .build();
332
333            //---* Done *------------------------------------------------------
334            return retValue;
335        };
336        m_Method_ToString = Lazy.use( methodSpecSupplier );
337    }   //  JavaComposer()
338
339        /*---------*\
340    ====** Methods **==========================================================
341        \*---------*/
342    /**
343     *  Returns the flag that controls whether the output should be enhanced
344     *  with some debug information.
345     *
346     *  @return {@code true} if the debug information should be added to the
347     *      output, {@code false} otherwise.
348     */
349    @SuppressWarnings( "BooleanMethodNameMustStartWithQuestion" )
350    public final boolean addDebugOutput() { return m_AddDebugOutput; }
351
352    /**
353     *  <p>{@summary Creates a builder for an instance of an implementation for
354     *  {@link AnnotationSpec}
355     *  from the given
356     *  {@link ClassName}
357     *  instance.}</p>
358     *  <p>This builder generates the code for the <i>use</i> of an annotation,
359     *  while the builders returned from
360     *  {@link #annotationTypeBuilder(CharSequence)}
361     *  and
362     *  {@link #annotationTypeBuilder(ClassName)}
363     *  will generate <i>new</i> annotation types.</p>
364     *
365     *  @param  type    The class name.
366     *  @return The new builder.
367     */
368    public final AnnotationSpec.Builder annotationBuilder( final ClassName type )
369    {
370        final var retValue = new BuilderImpl( this, requireNonNullArgument( type, "type" ) );
371
372        //---* Done *----------------------------------------------------------
373        return retValue;
374    }   //  annotationBuilder()
375
376    /**
377     *  <p>{@summary Creates a builder for an instance of an implementation for
378     *  {@link AnnotationSpec}
379     *  from the given
380     *  {@link Class}
381     *  instance.}</p>
382     *  <p>This builder generates the code for the <i>use</i> of an annotation,
383     *  while the builders returned from
384     *  {@link #annotationTypeBuilder(CharSequence)}
385     *  and
386     *  {@link #annotationTypeBuilder(ClassName)}
387     *  will generate <i>new</i> annotation types.</p>
388     *
389     *  @param  type    The class.
390     *  @return The new builder.
391     */
392    public final AnnotationSpec.Builder annotationBuilder( final Class<?> type )
393    {
394        final var retValue = annotationBuilder( ClassName.from( type ) );
395
396        //---* Done *----------------------------------------------------------
397        return retValue;
398    }   //  annotationBuilder()
399
400    /**
401     *  <p>{@summary Creates a builder for an annotation.}</p>
402     *  <p>This method creates a builder for a new annotation, while
403     *  {@link #annotationBuilder(ClassName)}
404     *  and
405     *  {@link #annotationBuilder(Class)}
406     *  will create the builder for the <i>use</i> of an annotation.</p>
407     *
408     *  @param  className   The name of the annotation.
409     *  @return The builder.
410     */
411    public final TypeSpec.Builder annotationTypeBuilder( final ClassName className )
412    {
413        final var retValue = annotationTypeBuilder( requireNonNullArgument( className, "className" ).simpleName() );
414
415        //---* Done *----------------------------------------------------------
416        return retValue;
417    }   //  annotationTypeBuilder()
418
419    /**
420     *  <p>{@summary Creates a builder for an annotation.}</p>
421     *  <p>This method creates a builder for a new annotation, while
422     *  {@link #annotationBuilder(ClassName)}
423     *  and
424     *  {@link #annotationBuilder(Class)}
425     *  will create the builder for the <i>use</i> of an annotation.</p>
426     *
427     *  @param  name   The name of the annotation.
428     *  @return The builder.
429     */
430    public final TypeSpec.Builder annotationTypeBuilder( final CharSequence name )
431    {
432        final var retValue = new AnnotationTypeSpecImpl.BuilderImpl( this, requireNonNullArgument( name, "name" ) );
433
434        //---* Done *----------------------------------------------------------
435        return retValue;
436    }   //  annotationTypeBuilder()
437
438    /**
439     *  Creates a builder for an anonymous class.
440     *
441     *  @param  typeArguments   The type arguments.
442     *  @return The builder.
443     */
444    public final TypeSpec.Builder anonymousClassBuilder( final CodeBlock typeArguments )
445    {
446        final var retValue = new ClassSpecImpl.BuilderImpl( this, (CodeBlockImpl) requireNonNullArgument( typeArguments, "typeArguments" ) );
447
448        //---* Done *----------------------------------------------------------
449        return retValue;
450    }   //  anonymousClassBuilder()
451
452    /**
453     *  <p>{@summary Creates a builder for an anonymous class.} This method is
454     *  the shortcut for</p>
455     *  <pre><code>  CodeBlock codeBlock = codeBlockBuilder()
456     *      .add( format, args )
457     *      .build();
458     *  TypeSpec.Builder builder = anonymousClassBuilder( codeBlock ); </code></pre>
459     *
460     *  @param  format  The format for the code; may be empty.
461     *  @param  args    The arguments for the code.
462     *  @return The builder.
463     *
464     *  @see #codeBlockBuilder()
465     *  @see #anonymousClassBuilder(CodeBlock)
466     */
467    public final TypeSpec.Builder anonymousClassBuilder( final String format, final Object... args )
468    {
469        final var retValue = anonymousClassBuilder( codeBlockBuilder()
470            .add( format, args )
471            .build() );
472
473        //---* Done *----------------------------------------------------------
474        return retValue;
475    }   //  anonymousClassBuilder()
476
477    /**
478     *  Creates a builder for a regular class.
479     *
480     *  @param  className   The name of the class.
481     *  @return The builder.
482     */
483    public final TypeSpec.Builder classBuilder( final ClassName className )
484    {
485        final var retValue = classBuilder( requireNonNullArgument( className, "className" ).simpleName() );
486
487        //---* Done *----------------------------------------------------------
488        return retValue;
489    }   //  classBuilder()
490
491    /**
492     *  Creates a builder for a regular class.
493     *
494     *  @param  name    The name of the class.
495     *  @return The builder.
496     */
497    public final TypeSpec.Builder classBuilder( final CharSequence name )
498    {
499        final var retValue = new ClassSpecImpl.BuilderImpl( this, requireNotEmptyArgument( name, "name" ), null );
500
501        //---* Done *----------------------------------------------------------
502        return retValue;
503    }   //  classBuilder()
504
505    /**
506     *  Creates a builder for an instance of
507     *  {@link CodeBlock}.
508     *
509     *  @return The new builder.
510     */
511    public final CodeBlock.Builder codeBlockBuilder()
512    {
513        return new CodeBlockImpl.BuilderImpl( this );
514    }   //  codeBlockBuilder()
515
516    /**
517     *  Creates a new
518     *  {@link CodeBlock}
519     *  instance from the given format and arguments.
520     *
521     *  @note   No debug info will be added.
522     *
523     *  @param  format  The format.
524     *  @param  args    The arguments.
525     *  @return The new code block.
526     */
527    public final CodeBlock codeBlockOf( final String format, final Object... args )
528    {
529        final var retValue = ((CodeBlockImpl.BuilderImpl) codeBlockBuilder())
530            .add( format, args )
531            .build();
532
533        //---* Done *----------------------------------------------------------
534        return retValue;
535    }   //  codeBlockOf()
536
537    /**
538     *  Creates a builder that builds an instance of {@code MethodSpec} for a
539     *  constructor.
540     *
541     *  @return The builder.
542     */
543    public final MethodSpec.Builder constructorBuilder()
544    {
545        final var retValue = new MethodSpecImpl.BuilderImpl( this, CONSTRUCTOR );
546
547        //---* Done *----------------------------------------------------------
548        return retValue;
549    }   //  constructorBuilder()
550
551    /**
552     *  Creates an instance of
553     *  {@link AnnotationSpec}
554     *  from the given
555     *  {@link Annotation}
556     *  instance.
557     *
558     *  @param  annotation  The annotation.
559     *  @return The new instance of {@code AnnotationSpec}.
560     */
561    public final AnnotationSpec createAnnotation( final Annotation annotation )
562    {
563        final var retValue = createAnnotation( annotation, false );
564
565        //---* Done *----------------------------------------------------------
566        return retValue;
567    }   //  createAnnotation()
568
569    /**
570     *  Creates an instance of
571     *  {@link AnnotationSpec}
572     *  from the given
573     *  {@link Annotation}
574     *  instance.
575     *
576     *  @param  annotation  The annotation.
577     *  @param  includeDefaultValues    {@code true} to include the
578     *      annotation's default values, {@code false} to ignore them.
579     *  @return The new instance of {@code AnnotationSpec}.
580     */
581    public final AnnotationSpec createAnnotation( final Annotation annotation, final boolean includeDefaultValues )
582    {
583        final var builder = (AnnotationSpecImpl.BuilderImpl) annotationBuilder( ClassName.from( requireNonNullArgument( annotation, "annotation" ).annotationType() ) );
584        try
585        {
586            final var methods = annotation.annotationType().getDeclaredMethods();
587            sort( methods, comparing( Method::getName ) );
588            MethodsLoop: for( final var method : methods )
589            {
590                final var value = method.invoke( annotation );
591                if( !includeDefaultValues )
592                {
593                    if( deepEquals( value, method.getDefaultValue() ) ) continue MethodsLoop;
594                }
595                if( value.getClass().isArray() )
596                {
597                    for( var i = 0; i < Array.getLength( value ); ++i )
598                    {
599                        builder.addMemberForValue( method.getName(), Array.get( value, i ) );
600                    }
601                    continue MethodsLoop;
602                }
603                if( value instanceof final Annotation annotationValue )
604                {
605                    builder.addMember( method.getName(), "$L", createAnnotation( annotationValue, false ) );
606                    continue MethodsLoop;
607                }
608                builder.addMemberForValue( method.getName(), value );
609            }   //  MethodsLoop:
610        }
611        catch( final SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e )
612        {
613            throw new JavaComposerException( "Reflecting " + annotation + " failed!", e );
614        }
615        final var retValue = builder.build();
616
617        //---* Done *----------------------------------------------------------
618        return retValue;
619    }   //  createAnnotation()
620
621    /**
622     *  Creates an instance of
623     *  {@link AnnotationSpec}
624     *  from the given
625     *  {@link AnnotationMirror}
626     *  instance.
627     *
628     *  @param  annotation  The annotation mirror.
629     *  @return The new instance of {@code AnnotationSpec}.
630     */
631    public final AnnotationSpec createAnnotation( final AnnotationMirror annotation )
632    {
633        final var element = (TypeElement) requireNonNullArgument( annotation, "annotation" ).getAnnotationType().asElement();
634        final var builder = (AnnotationSpecImpl.BuilderImpl) annotationBuilder( ClassName.from( element ) );
635        final var visitor = new AnnotationValueVisitor( builder );
636        for( final var executableElement : annotation.getElementValues().keySet() )
637        {
638            final var name = executableElement.getSimpleName().toString();
639            @SuppressWarnings( "unlikely-arg-type" )
640            final var value = annotation.getElementValues().get( executableElement );
641            value.accept( visitor, name );
642        }
643        final var retValue = builder.build();
644
645        //---* Done *----------------------------------------------------------
646        return retValue;
647    }   //  createAnnotation()
648
649    /**
650     *  Returns a {@code @ClassVersion} annotation with a default text for
651     *  {@link ClassVersion#sourceVersion()}.
652     *
653     *  @return The annotation.
654     *
655     *  @see    ClassVersion
656     */
657    public final AnnotationSpec createClassVersionAnnotation() { return m_Annotation_ClassVersion.get(); }
658
659    /**
660     *  Returns a {@code @ClassVersion} annotation with the text for
661     *  {@link ClassVersion#sourceVersion()}.
662     *
663     *  @param  sourceVersion   The text.
664     *  @return The annotation.
665     *
666     *  @see    ClassVersion
667     */
668    public final AnnotationSpec createClassVersionAnnotation( final String sourceVersion )
669    {
670        final var retValue = annotationBuilder( ClassVersion.class )
671            .forceInline( true )
672            .addMember( "sourceVersion", "$S", requireNotEmptyArgument( sourceVersion, "sourceVersion" ) )
673            .addMember( "isGenerated", "$L", "true" )
674            .build();
675
676        //---* Done *------------------------------------------------------
677        return retValue;
678    }   //  createClassVersionAnnotation()
679
680    /**
681     *  Creates the comment for a constant.
682     *
683     *  @param  comment The already existing comment; can be {@code null}.
684     *  @return The comment for the new constant.
685     */
686    private final CodeBlock createComment4Constant( final CodeBlock comment )
687    {
688        var retValue = comment;
689        if( isNull( retValue ) )
690        {
691            retValue = codeBlockOf(
692                """
693                Constant value: $L.
694                """, JAVADOC_TAG_VALUE );
695        }
696        else
697        {
698            if( !comment.toString().contains( JAVADOC_TAG_VALUE ) )
699            {
700                retValue = retValue.join( "\n", codeBlockOf(
701                    """
702                    <p>The value is: $L.</p>
703                    """, JAVADOC_TAG_VALUE ) );
704            }
705        }
706
707        //---* Done *----------------------------------------------------------
708        return retValue;
709    }   //  createComment4Constant()
710
711    /**
712     *  <p>{@summary Creates a String constant.}</p>
713     *  <p>A constant is an initialised {@code public static final} field.</p>
714     *
715     *  @param  name    The name of the constant.
716     *  @param  value   The value of the constant.
717     *  @param  comment The description for the constant.
718     *  @return The field spec for the new constant.
719     */
720    public final FieldSpec createConstant( final CharSequence name, final String value, final CodeBlock comment )
721    {
722        final var retValue = createConstant( name, String.class, codeBlockOf( "$S", requireNonNullArgument( value, "value" ) ), createComment4Constant( comment ) );
723
724        //---* Done *----------------------------------------------------------
725        return retValue;
726    }   //  createConstant()
727
728    /**
729     *  <p>{@summary Creates a numerical constant.}</p>
730     *  <p>A constant is an initialised {@code public static final} field.</p>
731     *
732     *  @param  name    The name of the constant.
733     *  @param  type    The type of the constant.
734     *  @param  value   The value of the constant.
735     *  @param  comment The description for the constant.
736     *  @return The field spec for the new constant.
737     */
738    @SuppressWarnings( "SameParameterValue" )
739    private final FieldSpec createConstant( final CharSequence name, final TypeName type, final Number value, final CodeBlock comment )
740    {
741        final var retValue = createConstant( name, type, codeBlockOf( "$L", requireNonNullArgument( value, "value" ) ), createComment4Constant( comment ) );
742
743        //---* Done *----------------------------------------------------------
744        return retValue;
745    }   //  createConstant()
746
747    /**
748     *  <p>{@summary Creates an integer constant.}</p>
749     *  <p>A constant is an initialised {@code public static final} field.</p>
750     *
751     *  @param  name    The name of the constant.
752     *  @param  value   The value of the constant.
753     *  @param  comment The description for the constant.
754     *  @return The field spec for the new constant.
755     */
756    public final FieldSpec createConstant( final CharSequence name, final int value, final CodeBlock comment )
757    {
758        final var retValue = createConstant( name, INT, Integer.valueOf( value ), comment );
759
760        //---* Done *----------------------------------------------------------
761        return retValue;
762    }   //  createConstant()
763
764    /**
765     *  <p>{@summary Creates a constant.}</p>
766     *  <p>A constant is an initialised {@code public static final} field.</p>
767     *
768     *  @param  name    The name of the constant.
769     *  @param  type    The type of the constant.
770     *  @param  value   The value of the constant.
771     *  @param  comment The description for the constant.
772     *  @return The field spec for the new constant.
773     */
774    public final FieldSpec createConstant( final CharSequence name, final Type type, final CodeBlock value, final CodeBlock comment )
775    {
776        return createConstant( name, TypeName.from( requireNonNullArgument( type, "type" ) ), value, comment );
777    }   //  createConstant()
778
779    /**
780     *  Creates a constant.<br>
781     *  <br>A constant is an initialised {@code public final static} field.
782     *
783     *  @param  name    The name of the constant.
784     *  @param  type    The type of the constant.
785     *  @param  value   The value of the constant.
786     *  @param  comment The description for the constant.
787     *  @return The field spec for the new constant.
788     */
789    public final FieldSpec createConstant( final CharSequence name, final TypeName type, final CodeBlock value, final CodeBlock comment )
790    {
791        final var builder = fieldBuilder( type, name, PUBLIC, FINAL, STATIC )
792            .initializer( requireNonNullArgument( value, "value" ) );
793
794        if( nonNull( comment ) && !comment.isEmpty() ) builder.addJavadoc( comment );
795
796        final var retValue = builder.build();
797
798        //---* Done *----------------------------------------------------------
799        return retValue;
800    }   //  createConstant()
801
802    /**
803     *  <p>{@summary Returns a builder for an implementation of the method
804     *  {@link Object#equals(Object)}
805     *  that just needs the method body for completion.}</p>
806     *  <p>The argument has the name &quot;{@code o}&quot;.</p>
807     *
808     *  @return The method builder.
809     */
810    public final MethodSpec.Builder createEqualsBuilder()
811    {
812        final var retValue = m_Method_Equals.get().toBuilder();
813
814        //---* Done *----------------------------------------------------------
815        return retValue;
816    }   //  createEqualsBuilder()
817
818    /**
819     *  <p>{@summary Returns a
820     *  {@link MethodSpec}
821     *  instance for an implementation of the method
822     *  {@link Object#equals(Object)}.}</p>
823     *  <p>The argument has the name &quot;{@code o}&quot;.</p>
824     *
825     *  @param  body    The method body.
826     *  @return The method specification.
827     */
828    public final MethodSpec createEqualsMethod( final CodeBlock body )
829    {
830        final var retValue = createEqualsBuilder()
831            .addCode( requireNonNullArgument( body, "body" ) )
832            .build();
833
834        //---* Done *----------------------------------------------------------
835        return retValue;
836    }   //  createEqualsMethod()
837
838    /**
839     *  Returns a builder for an implementation of the method
840     *  {@link Object#hashCode()}
841     *  that just needs the method body for completion.
842     *
843     *  @return The method builder.
844     */
845    public final MethodSpec.Builder createHashCodeBuilder()
846    {
847        final var retValue = m_Method_HashCode.get().toBuilder();
848
849        //---* Done *----------------------------------------------------------
850        return retValue;
851    }   //  createHashCodeBuilder()
852
853    /**
854     *  Returns a
855     *  {@link MethodSpec}
856     *  instance for an implementation of the method
857     *  {@link Object#hashCode()}.
858     *
859     *  @param  body    The method body.
860     *  @return The method specification.
861     */
862    public final MethodSpec createHashCodeMethod( final CodeBlock body )
863    {
864        final var retValue = createHashCodeBuilder()
865            .addCode( requireNonNullArgument( body, "body" ) )
866            .build();
867
868        //---* Done *----------------------------------------------------------
869        return retValue;
870    }   //  createHashCodeMethod()
871
872    /**
873     *  <p>{@summary Returns a
874     *  {@link MethodSpec}
875     *  instance for an implementation of the method
876     *  {@link Object#hashCode()}.}</p>
877     *  <p>The created method uses
878     *  {@link org.tquadrat.foundation.lang.Objects#hash(Object...)}
879     *  for the implementation.</p>
880     *
881     *  @param  fields  The fields that are used for the calculation of the
882     *      hash code value.
883     *  @return The method specification.
884     */
885    public final MethodSpec createHashCodeMethod( final FieldSpec... fields )
886    {
887        final var retValue = createHashCodeMethod( List.of( requireNonNullArgument( fields, "fields" ) ) );
888
889        //---* Done *----------------------------------------------------------
890        return retValue;
891    }   //  createHashCodeMethod()
892
893    /**
894     *  <p>{@summary Returns a
895     *  {@link MethodSpec}
896     *  instance for an implementation of the method
897     *  {@link Object#hashCode()}.}</p>
898     *  <p>The created method uses
899     *  {@link org.tquadrat.foundation.lang.Objects#hash(Object...)}
900     *  for the implementation.</p>
901     *
902     *  @param  fields  The fields that are used for the calculation of the
903     *      hash code value.
904     *  @return The method specification.
905     */
906    public final MethodSpec createHashCodeMethod( final Collection<? extends FieldSpec> fields )
907    {
908        final var fieldList = requireNotEmptyArgument( fields, "fields" ).stream()
909            .map( FieldSpec::name )
910            .collect( joining( ", ", "return hash( ", " )" ) );
911        final var body = codeBlockBuilder()
912            .addStaticImport( Objects.class, "hash" )
913            .addStatement( fieldList )
914            .build();
915        final var retValue = createHashCodeBuilder()
916            .addCode( body )
917            .build();
918
919        //---* Done *----------------------------------------------------------
920        return retValue;
921    }   //  createHashCodeMethod()
922
923    /**
924     *  Returns a code block with a comment for overriding methods:
925     *  <div class="source-container"><pre>&#47;**
926     *   * {&#64;inheritDoc}
927     *   *&#47;</pre></div>
928     *
929     *  @return The comment.
930     */
931    public final CodeBlock createInheritDocComment() { return m_JavaDoc_InheritDoc.get(); }
932
933    /**
934     *  <p>{@summary Creates a
935     *  {@link MethodSpec}
936     *  for the given
937     *  {@link ExecutableElement}.}</p>
938     *  <p>This method copies visibility modifiers, type parameters, return
939     *  type, name, parameters, and {@code throws} declarations, but not the
940     *  body (if any).</p>
941     *
942     *  @note   The annotations will not be copied and must be added separately.
943     *
944     *  @param  method  The method to override.
945     *  @return The builder.
946     */
947    public final MethodSpec createMethod( final ExecutableElement method )
948    {
949        final var methodName = requireNonNullArgument( method, "method" ).getSimpleName();
950        final var builder = methodBuilder( methodName )
951            .addModifiers( method.getModifiers() )
952            .returns( TypeName.from( method.getReturnType() ) )
953            .addParameters( parametersOf( method ) )
954            .varargs( method.isVarArgs() );
955
956        for( final var typeParameterElement : method.getTypeParameters() )
957        {
958            final var typeVariable = (TypeVariable) typeParameterElement.asType();
959            builder.addTypeVariable( TypeVariableName.from( typeVariable ) );
960        }
961
962        for( final var thrownType : method.getThrownTypes() )
963        {
964            builder.addException( TypeName.from( thrownType ) );
965        }
966
967        //---* Create the return value *---------------------------------------
968        final var retValue = builder.build();
969
970        //---* Done *----------------------------------------------------------
971        return retValue;
972    }   //  createMethod()
973
974    /**
975     *  Creates an instance of
976     *  {@link ParameterSpec}
977     *  from the given
978     *  {@link VariableElement}
979     *  instance.
980     *
981     *  @param  element The variable element.
982     *  @return The parameter spec.
983     */
984    public final ParameterSpec createParameter( final VariableElement element )
985    {
986        final var type = TypeName.from( requireNonNullArgument( element, "element" ).asType() );
987        final var name = element.getSimpleName().toString();
988        final var modifiers = element.getModifiers();
989        final var builder = parameterBuilder( type, name )
990            .addModifiers( modifiers );
991        for( final var mirror : element.getAnnotationMirrors() )
992        {
993            builder.addAnnotation( createAnnotation( mirror ) );
994        }
995        final var retValue = builder.build();
996
997        //---* Done *----------------------------------------------------------
998        return retValue;
999    }   //  createParameter()
1000
1001    /**
1002     *  Creates an instance of
1003     *  {@link ParameterSpec}
1004     *  from the given
1005     *  {@link Parameter}
1006     *  instance.
1007     *
1008     *  @param  parameter The variable element.
1009     *  @return The parameter spec.
1010     */
1011    public final ParameterSpec createParameter( final Parameter parameter )
1012    {
1013        final var type = TypeName.from( requireNonNullArgument( parameter, "parameter" ).getType() );
1014        final var name = parameter.getName();
1015        final var modifiers = translateModifiers( parameter.getModifiers() );
1016        final var builder = parameterBuilder( type, name )
1017            .addModifiers( modifiers );
1018        for( final var annotation : parameter.getAnnotations() )
1019        {
1020            builder.addAnnotation( createAnnotation( annotation ) );
1021        }
1022        final var retValue = builder.build();
1023
1024        //---* Done *----------------------------------------------------------
1025        return retValue;
1026    }   //  createParameter()
1027
1028    /**
1029     *  Creates a return statement with a comment, using {@code retValue} as
1030     *  the name for the return variable.
1031     *
1032     *  @return The return statement.
1033     */
1034    public final CodeBlock createReturnStatement() { return createReturnStatement( "retValue" ); }
1035
1036    /**
1037     *  Creates a return statement with a comment.
1038     *
1039     *  @param  name    The name of the variable that is returned.
1040     *  @return The return statement.
1041     */
1042    public final CodeBlock createReturnStatement( final CharSequence name )
1043    {
1044        final var retValue = new CodeBlockImpl.BuilderImpl( this )
1045            .addWithoutDebugInfo(
1046                  """
1047
1048                  //---* Done *----------------------------------------------------------
1049                  """ )
1050            .addStatement( "return $L", requireNotEmptyArgument( name, "name" ) )
1051            .build();
1052
1053        //---* Done *----------------------------------------------------------
1054        return retValue;
1055    }   //  createReturnStatement()
1056
1057    /**
1058     *  <p>{@summary Returns a builder for a static class.}</p>
1059     *  <p>A <i>static class</i> is a {@code final} class with a
1060     *  {@code private} constructor that has only {@code static} members; no
1061     *  instances are allowed for such a class, so none of the {@code static}
1062     *  methods are factories for that class.</p>
1063     *  <p>This would be the skeleton for the new static class:</p>
1064     *  <pre><code>  &lt;package <i>what.ever.package.was.chosen</i>&gt;;
1065     *
1066     *  import org.tquadrat.foundation.annotation.ClassVersion;
1067     *  import org.tquadrat.foundation.annotation.UtilityClass;
1068     *  import org.tquadrat.foundation.exception.PrivateConstructorForStaticClassCalledError;
1069     *
1070     *  &#64;UtilityClass
1071     *  &#64;ClassVersion(sourceVersion = "Generated with JavaComposer", isGenerated = true)
1072     *  public final class StaticClass {
1073     *    &#47;**
1074     *     * No instance allowed for this class!
1075     *     *&#47;
1076     *    private StaticClass() {
1077     *      throw new PrivateConstructorForStaticClassCalledError( StaticClass.class );
1078     *    }
1079     *  }</code></pre>
1080     *
1081     *  @param  className   The name of the new class.
1082     *  @return The builder.
1083     *
1084     *  @see    ClassVersion
1085     *  @see    PrivateConstructorForStaticClassCalledError
1086     *  @see    UtilityClass
1087     */
1088    public final TypeSpec.Builder createStaticClassBuilder( final CharSequence className )
1089    {
1090        requireValidNonNullArgument( className, "className", v -> SourceVersion.isName( requireNotEmptyArgument( v, "className" ) ), _ -> "not a valid name: %s".formatted( className ) );
1091        final var constructor = constructorBuilder()
1092            .addModifiers( PRIVATE )
1093            .addJavadoc(
1094                """
1095                No instance allowed for this class!
1096                """ )
1097            .addStatement( "throw new $T( $L.class )", PrivateConstructorForStaticClassCalledError.class, className )
1098            .build();
1099        final var retValue = classBuilder( className )
1100            .addModifiers( PUBLIC, FINAL )
1101            .addAnnotation( createUtilityClassAnnotation() )
1102            .addAnnotation( createClassVersionAnnotation() )
1103            .addMethod( constructor );
1104
1105        //---* Done *----------------------------------------------------------
1106        return retValue;
1107    }   //  createStaticClassBuilder()
1108
1109    /**
1110     *  <p>{@summary Returns a
1111     *  {@link SuppressWarnings &#64;SuppressWarnings}
1112     *  annotation with the given values.} No annotation will be created if
1113     *  the given collection is empty.</p>
1114     *
1115     *  @param  warnings    The warnings to suppress.
1116     *  @return An instance of
1117     *      {@link Optional}
1118     *      that holds the new annotation.
1119     */
1120    public final Optional<AnnotationSpec> createSuppressWarningsAnnotation( final Collection<SuppressableWarnings> warnings )
1121    {
1122        return createSuppressWarningsAnnotation( requireNonNullArgument( warnings, "warnings" ).toArray( SuppressableWarnings []::new ) );
1123    }   //  createSuppressWarningsAnnotation()
1124
1125    /**
1126     *  <p>{@summary Returns a
1127     *  {@link SuppressWarnings &#64;SuppressWarnings}
1128     *  annotation with the given values.} No annotation will be created if
1129     *  the given collection is empty.</p>
1130     *
1131     *  @param  warnings    The warnings to suppress.
1132     *  @return An instance of
1133     *      {@link Optional}
1134     *      that holds the new annotation.
1135     */
1136    public final Optional<AnnotationSpec> createSuppressWarningsAnnotation( final SuppressableWarnings... warnings )
1137    {
1138        final Optional<AnnotationSpec> retValue = warnings.length > 0
1139            ? Optional.of( SuppressableWarnings.createSuppressWarningsAnnotation( this, warnings ) )
1140            : Optional.empty();
1141
1142        //---* Done *----------------------------------------------------------
1143        return retValue;
1144    }   //  createSuppressWarningsAnnotation()
1145
1146    /**
1147     *  Returns a builder for an implementation of the method
1148     *  {@link Object#toString()}
1149     *  that just needs the method body for completion.
1150     *
1151     *  @return The method builder.
1152     */
1153    public final MethodSpec.Builder createToStringBuilder()
1154    {
1155        final var retValue = m_Method_ToString.get().toBuilder();
1156
1157        //---* Done *----------------------------------------------------------
1158        return retValue;
1159    }   //  createToStringBuilder()
1160
1161    /**
1162     *  Returns a
1163     *  {@link MethodSpec}
1164     *  instance for an implementation of the method
1165     *  {@link Object#toString()}.
1166     *
1167     *  @param  body    The method body.
1168     *  @return The method specification.
1169     */
1170    public final MethodSpec createToStringMethod( final CodeBlock body )
1171    {
1172        final var retValue = createToStringBuilder()
1173            .addCode( requireNonNullArgument( body, "body" ) )
1174            .build();
1175
1176        //---* Done *----------------------------------------------------------
1177        return retValue;
1178    }   //  createToStringMethod()
1179
1180    /**
1181     *  Returns a {@code @UtilityClass} annotation.
1182     *
1183     *  @return The annotation.
1184     *
1185     *  @see    UtilityClass
1186     */
1187    public final AnnotationSpec createUtilityClassAnnotation() { return m_Annotation_UtilityClass.get(); }
1188
1189    /**
1190     *  Returns an empty
1191     *  {@link CodeBlock}.
1192     *
1193     *  @return An empty code block.
1194     */
1195    public final CodeBlock emptyCodeBlock() { return codeBlockBuilder().build(); }
1196
1197    /**
1198     *  Creates a builder for an {@code enum} type.
1199     *
1200     *  @param  className   The name of the class.
1201     *  @return The builder.
1202     */
1203    public final TypeSpec.Builder enumBuilder( final ClassName className )
1204    {
1205        final var retValue = enumBuilder( requireNonNullArgument( className, "className" ).simpleName() );
1206
1207        //---* Done *----------------------------------------------------------
1208        return retValue;
1209    }   //  enumBuilder()
1210
1211    /**
1212     *  Creates a builder for an {@code enum} type.
1213     *
1214     *  @param  name   The name of the class.
1215     *  @return The builder.
1216     */
1217    public final TypeSpec.Builder enumBuilder( final CharSequence name )
1218    {
1219        final var retValue = new EnumSpecImpl.BuilderImpl( this, requireNonNullArgument( name, "name" ) );
1220
1221        //---* Done *----------------------------------------------------------
1222        return retValue;
1223    }   //  enumBuilder()
1224
1225    /**
1226     *  {@inheritDoc}
1227     */
1228    @Override
1229    public final boolean equals( final Object o )
1230    {
1231        var retValue = this == o;
1232        if( !retValue && o instanceof final JavaComposer other )
1233        {
1234            retValue = (m_Layout == other.m_Layout) && (m_AddDebugOutput == other.m_AddDebugOutput);
1235        }
1236
1237        //---* Done *----------------------------------------------------------
1238        return retValue;
1239    }   //  equals()
1240
1241    /**
1242     *  Creates a builder for an instance of
1243     *  {@link FieldSpec}
1244     *  from the given type, name and modifiers.
1245     *
1246     *  @param  type    The type of the {@code FieldSpec} to build.
1247     *  @param  name    The name for the new field.
1248     *  @param  modifiers   The modifiers.
1249     *  @return The new builder.
1250     */
1251    public final FieldSpec.Builder fieldBuilder( final Type type, final CharSequence name, final Modifier... modifiers )
1252    {
1253        final var retValue = fieldBuilder( TypeNameImpl.from( requireNonNullArgument( type, "type" ) ), name, modifiers );
1254
1255        //---* Done *----------------------------------------------------------
1256        return retValue;
1257    }   //  fieldBuilder()
1258
1259    /**
1260     *  Creates a builder for an instance of
1261     *  {@link FieldSpec}
1262     *  from the given type, name and modifiers.
1263     *
1264     *  @param  type    The type of the {@code FieldSpec} to build.
1265     *  @param  name    The name for the new field.
1266     *  @param  modifiers   The modifiers.
1267     *  @return The new builder.
1268     */
1269    public final FieldSpec.Builder fieldBuilder( final TypeName type, final CharSequence name, final Modifier... modifiers )
1270    {
1271        final var retValue = new FieldSpecImpl.BuilderImpl( this, (TypeNameImpl) requireNonNullArgument( type, "type" ), require( name, _ -> "not a valid name: %s".formatted( name ), JavaUtils::isValidName ) ).addModifiers( requireNonNullArgument( modifiers, "modifiers" ) );
1272
1273        //---* Done *----------------------------------------------------------
1274        return retValue;
1275    }   //  fieldBuilder()
1276
1277    /**
1278     *  Creates a builder for an instance of
1279     *  {@link FieldSpec}
1280     *  from the given type, name and modifiers.
1281     *
1282     *  @param  type    The type of the {@code FieldSpec} to build.
1283     *  @param  name    The name for the new field.
1284     *  @param  modifiers   The modifiers.
1285     *  @return The new builder.
1286     */
1287    public final FieldSpec.Builder fieldBuilder( final TypeSpec type, final CharSequence name, final Modifier... modifiers )
1288    {
1289        final var typeName = ClassNameImpl.from( EMPTY_STRING, requireNonNullArgument( type, "type" ).name().orElseThrow( () -> new ValidationException( "Anonymous class cannot be used as type for a field" ) ) );
1290        final var retValue = fieldBuilder( typeName, name, modifiers );
1291
1292        //---* Done *----------------------------------------------------------
1293        return retValue;
1294    }   //  fieldBuilder()
1295
1296    /**
1297     *  Returns the layout that is used to format the output.
1298     *
1299     *  @return The layout.
1300     */
1301    public final Layout getLayout() { return m_Layout; }
1302
1303    /**
1304     *  <p>{@summary Returns the maximum number of fields for a class.} If this
1305     *  number is exceeded, an annotation
1306     *  {@link SuppressWarnings &#64;SuppressWarnings}
1307     *  with
1308     *  {@link SuppressableWarnings#CLASS_WITH_TOO_MANY_FIELDS}
1309     *  will be added to the class.</p>
1310     *
1311     *  @return The maximum number of fields.
1312     */
1313    public final int getMaxFields() { return m_MaxFields; }
1314
1315    /**
1316     *  <p>{@summary Returns the maximum number of methods for a class.} If
1317     *  this number is exceeded, an annotation
1318     *  {@link SuppressWarnings &#64;SuppressWarnings}
1319     *  with
1320     *  {@link SuppressableWarnings#CLASS_WITH_TOO_MANY_METHODS}
1321     *  will be added to the class.</p>
1322     *
1323     *  @return The maximum number of fields.
1324     */
1325    public final int getMaxMethods() { return m_MaxMethods; }
1326
1327    /**
1328     *  {@inheritDoc}
1329     */
1330    @Override
1331    public final int hashCode() { return hash( m_Layout, Boolean.valueOf( m_AddDebugOutput ) ) ; }
1332
1333    /**
1334     *  Creates a builder for an interface.
1335     *
1336     *  @param  className   The name of the class.
1337     *  @return The builder.
1338     */
1339    public final TypeSpec.Builder interfaceBuilder( final ClassName className )
1340    {
1341        final var retValue = interfaceBuilder( requireNonNullArgument( className, "className" ).simpleName() );
1342
1343        //---* Done *----------------------------------------------------------
1344        return retValue;
1345    }   //  interfaceBuilder()
1346
1347    /**
1348     *  Creates a builder for an interface.
1349     *
1350     *  @param  name   The name of the class.
1351     *  @return The builder.
1352     */
1353    public final TypeSpec.Builder interfaceBuilder( final CharSequence name )
1354    {
1355        final var retValue = new InterfaceSpecImpl.BuilderImpl( new JavaComposer(), requireNotEmptyArgument( name, "name" ) );
1356
1357        //---* Done *----------------------------------------------------------
1358        return retValue;
1359    }   //  interfaceBuilder()
1360
1361    /**
1362     *  Creates a builder for a new instance of
1363     *  {@link JavaFile}
1364     *  from the given package name and class definition.
1365     *
1366     *  @param  packageName The package name; may be empty for the default
1367     *      package.
1368     *  @param  typeSpec    The class definition.
1369     *  @return The builder.
1370     */
1371    public final JavaFile.Builder javaFileBuilder( final CharSequence packageName, final TypeSpec typeSpec )
1372    {
1373        final var retValue = new JavaFileImpl.BuilderImpl( this, packageName, (TypeSpecImpl) typeSpec );
1374
1375        //---* Done *----------------------------------------------------------
1376        return retValue;
1377    }   //  javaFileBuilder()
1378
1379    /**
1380     *  Creates a builder for an instance of
1381     *  {@link LambdaSpec}.
1382     *
1383     *  @return The new builder.
1384     */
1385    public final LambdaSpec.Builder lambdaBuilder()
1386    {
1387        final var retValue = new LambdaSpecImpl.BuilderImpl( this );
1388
1389        //---* Done *----------------------------------------------------------
1390        return retValue;
1391    }   //  lambdaBuilder()
1392
1393    /**
1394     *  Returns a builder for a regular method.
1395     *
1396     *  @param  name    The name for the method.
1397     *  @return The builder.
1398     */
1399    public final MethodSpec.Builder methodBuilder( final CharSequence name )
1400    {
1401        final var retValue = new MethodSpecImpl.BuilderImpl( new JavaComposer(), name );
1402
1403        //---* Done *----------------------------------------------------------
1404        return retValue;
1405    }   //  methodBuilder()
1406
1407    /**
1408     *  <p>{@summary Returns a new method builder for a method that overrides
1409     *  the given method.}</p>
1410     *  <p>This new builder will copy visibility modifiers, type parameters,
1411     *  return type, name, parameters, and {@code throws} declarations. An
1412     *  {@link Override}
1413     *  annotation will be added.</p>
1414     *
1415     *  @note In JavaPoet&nbsp;1.2 through 1.7 this method retained annotations
1416     *      from the method and parameters of the overridden method. Since
1417     *      JavaPoet&nbsp;1.8 and in JavaComposer annotations must be added
1418     *      separately.
1419     *
1420     *  @param  method  The method to override.
1421     *  @return The builder.
1422     */
1423    public final MethodSpec.Builder overridingMethodBuilder( final ExecutableElement method )
1424    {
1425        final var enclosingClass = requireNonNullArgument( method, "method" ).getEnclosingElement();
1426        if( enclosingClass.getModifiers().contains( FINAL ) )
1427        {
1428            //noinspection UnnecessaryToStringCall
1429            throw new IllegalArgumentException( format( MSG_CannotOverrideFinalClass, enclosingClass.toString() ) );
1430        }
1431
1432        var modifiers = method.getModifiers();
1433        if( modifiers.contains( PRIVATE ) || modifiers.contains( FINAL ) || modifiers.contains( STATIC ) )
1434        {
1435            throw new IllegalArgumentException( format( MSG_CannotOverrideMethod, modifiers.stream().map( Enum::name ).collect( joining( "', '" ) ) ) );
1436        }
1437
1438        final var methodName = method.getSimpleName().toString();
1439        final var retValue = methodBuilder( methodName );
1440
1441        retValue.addAnnotation( Override.class );
1442
1443        modifiers = new LinkedHashSet<>( modifiers );
1444        modifiers.remove( ABSTRACT );
1445        modifiers.remove( DEFAULT );
1446        retValue.addModifiers( modifiers );
1447
1448        for( final var typeParameterElement : method.getTypeParameters() )
1449        {
1450            final var typeVariable = (TypeVariable) typeParameterElement.asType();
1451            retValue.addTypeVariable( TypeVariableName.from( typeVariable ) );
1452        }
1453
1454        retValue.returns( TypeName.from( method.getReturnType() ) );
1455
1456        retValue.addParameters( parametersOf( method ) );
1457        retValue.varargs( method.isVarArgs() );
1458
1459        for( final var thrownType : method.getThrownTypes() )
1460        {
1461            retValue.addException( TypeName.from( thrownType ) );
1462        }
1463
1464        //---* Done *----------------------------------------------------------
1465        return retValue;
1466    }   //  overridingMethodBuilder()
1467
1468    /**
1469     *  <p>{@summary Returns a new method builder that overrides the given
1470     *  method as a member of of the given enclosing class.} This will resolve
1471     *  type parameters: for example overriding
1472     *  {@link Comparable#compareTo}
1473     *  in a type that implements {@code Comparable<Movie>}, the {@code T}
1474     *  parameter will be resolved to {@code Movie}.</p>
1475     *  <p>This will copy its visibility modifiers, type parameters, return
1476     *  type, name, parameters, and {@code throws} declarations. An
1477     *  {@link Override}
1478     *  annotation will be added.</p>
1479     *
1480     *  @note In JavaPoet&nbsp;1.2 through 1.7 this method retained annotations
1481     *      from the method and parameters of the overridden method. Since
1482     *      JavaPoet&nbsp;1.8 and in JavaComposer annotations must be added
1483     *      separately.
1484     *
1485     *  @param  method  The method to override.
1486     *  @param  enclosing   The enclosing class for the method.
1487     *  @param  typeUtils   An implementation of some utility methods for
1488     *      operating on types, as provided by the processing environment of an
1489     *      annotation processor.
1490     *  @return The builder.
1491     */
1492    public final MethodSpec.Builder overridingMethodBuilder( final ExecutableElement method, final DeclaredType enclosing, final Types typeUtils )
1493    {
1494        final var executableType = (ExecutableType) requireNonNullArgument( typeUtils, "types" ).asMemberOf( requireNonNullArgument( enclosing, "enclosing" ), requireNonNullArgument( method, "method" ) );
1495        final var resolvedParameterTypes = executableType.getParameterTypes();
1496        final var resolvedThrownTypes = executableType.getThrownTypes();
1497        final var resolvedReturnType = executableType.getReturnType();
1498
1499        final var retValue = (MethodSpecImpl.BuilderImpl) overridingMethodBuilder( method );
1500        retValue.returns( TypeName.from( resolvedReturnType ) );
1501        final var parameters = retValue.parameters();
1502        for( int i = 0, size = parameters.size(); i < size; ++i )
1503        {
1504            final var parameter = parameters.get( i );
1505            final var type = TypeName.from( resolvedParameterTypes.get( i ) );
1506            parameters.set( i, parameter.toBuilder( type, parameter.name(), true ).build() );
1507        }
1508        retValue.exceptions().clear();
1509        for( final var resolvedThrownType : resolvedThrownTypes )
1510        {
1511            retValue.addException( TypeName.from( resolvedThrownType ) );
1512        }
1513
1514        //---* Done *----------------------------------------------------------
1515        return retValue;
1516    }   //  overridingMethodBuilder()
1517
1518    /**
1519     *  <p>{@summary Returns a new method builder for a method that overrides
1520     *  the given method.}</p>
1521     *  <p>This new builder will copy visibility modifiers, type parameters,
1522     *  return type, name, parameters, and {@code throws} declarations. An
1523     *  {@link Override}
1524     *  annotation will be added, but any other annotation will be omitted;
1525     *  this is consistent with the behaviour of
1526     *  {@link #overridingMethodBuilder(ExecutableElement)}
1527     *  and
1528     *  {@link #overridingMethodBuilder(ExecutableElement, DeclaredType, Types)}.</p>
1529     *
1530     *  @param  method  The method to override.
1531     *  @return The builder.
1532     */
1533    public final MethodSpec.Builder overridingMethodBuilder( final Method method )
1534    {
1535        final var enclosingClass = requireNonNullArgument( method, "method" ).getDeclaringClass();
1536        if( translateModifiers( enclosingClass.getModifiers() ).contains( FINAL ) )
1537        {
1538            throw new IllegalArgumentException( format( MSG_CannotOverrideFinalClass, enclosingClass.getName() ) );
1539        }
1540
1541        var modifiers = translateModifiers( method.getModifiers() );
1542        if( modifiers.contains( PRIVATE ) || modifiers.contains( FINAL ) || modifiers.contains( STATIC ) )
1543        {
1544            throw new IllegalArgumentException( format( MSG_CannotOverrideMethod, modifiers.stream().map( Enum::name ).collect( joining( "', '" ) ) ) );
1545        }
1546        final var methodName = method.getName();
1547        final var retValue = methodBuilder( methodName );
1548
1549        retValue.addAnnotation( Override.class );
1550
1551        modifiers = new LinkedHashSet<>( modifiers );
1552        modifiers.remove( ABSTRACT );
1553        modifiers.remove( DEFAULT );
1554        retValue.addModifiers( modifiers );
1555
1556        for( final var typeParameterVariable : method.getTypeParameters() )
1557        {
1558            retValue.addTypeVariable( TypeVariableName.from( typeParameterVariable ) );
1559        }
1560
1561        retValue.returns( TypeName.from( method.getReturnType() ) );
1562
1563        retValue.addParameters( parametersOf( method ) );
1564        retValue.varargs( method.isVarArgs() );
1565
1566        for( final var thrownType : method.getExceptionTypes() )
1567        {
1568            retValue.addException( TypeName.from( thrownType ) );
1569        }
1570
1571        //---* Done *----------------------------------------------------------
1572        return retValue;
1573    }   //  overridingMethodBuilder()
1574
1575    /**
1576     *  Creates a builder for a new
1577     *  {@link ParameterSpec}
1578     *  instance.
1579     *
1580     *  @param  type    The type of the new parameter.
1581     *  @param  name    The name of the new parameter.
1582     *  @param  modifiers   The modifiers for the new parameter.
1583     *  @return The builder.
1584     */
1585    public final ParameterSpec.Builder parameterBuilder( final Type type, final CharSequence name, final Modifier... modifiers )
1586    {
1587        final var retValue = parameterBuilder( TypeNameImpl.from( requireNonNullArgument( type, "type" ) ), name, modifiers );
1588
1589        //---* Done *----------------------------------------------------------
1590        return retValue;
1591    }   //  parameterBuilder()
1592
1593    /**
1594     *  Creates a builder for a new
1595     *  {@link ParameterSpec}
1596     *  instance.
1597     *
1598     *  @param  type    The type of the new parameter.
1599     *  @param  name    The name of the new parameter.
1600     *  @param  modifiers   The modifiers for the new parameter.
1601     *  @return The builder.
1602     */
1603    public final ParameterSpec.Builder parameterBuilder( final TypeName type, final CharSequence name, final Modifier... modifiers )
1604    {
1605        final var retValue = new ParameterSpecImpl.BuilderImpl( this, type, name ).addModifiers( modifiers );
1606
1607        //---* Done *----------------------------------------------------------
1608        return retValue;
1609    }   //  parameterBuilder()
1610
1611    /**
1612     *  Creates a new
1613     *  {@link ParameterSpec}
1614     *  instance for the given arguments.
1615     *
1616     *  @param  type    The type of the new parameter.
1617     *  @param  name    The name of the new parameter.
1618     *  @param  modifiers   The modifiers for the new parameter.
1619     *  @return The parameter specification.
1620     */
1621    public final ParameterSpec parameterOf( final Type type, final CharSequence name, final Modifier... modifiers )
1622    {
1623        final var retValue = parameterOf( TypeNameImpl.from( requireNonNullArgument( type, "type" ) ), name, modifiers );
1624
1625        //---* Done *----------------------------------------------------------
1626        return retValue;
1627    }   //  parameterOf()
1628
1629    /**
1630     *  Creates a new
1631     *  {@link ParameterSpec}
1632     *  instance for the given arguments.
1633     *
1634     *  @param  type    The type of the new parameter.
1635     *  @param  name    The name of the new parameter.
1636     *  @param  modifiers   The modifiers for the new parameter.
1637     *  @return The parameter specification.
1638     */
1639    public final ParameterSpec parameterOf( final TypeName type, final CharSequence name, final Modifier... modifiers )
1640    {
1641        final var retValue = parameterBuilder( type, name, modifiers )
1642            .build();
1643
1644        //---* Done *----------------------------------------------------------
1645        return retValue;
1646    }   //  parameterOf()
1647
1648    /**
1649     *  Retrieves the parameters from the given method.
1650     *
1651     *  @param  method  The method.
1652     *  @return The parameters of the given method; the returned list can be
1653     *      empty, but it will not be {@code null}.
1654     */
1655    public final List<ParameterSpec> parametersOf( final ExecutableElement method )
1656    {
1657        final var retValue = requireNonNullArgument( method, "method" ).getParameters()
1658            .stream()
1659            .map( this::createParameter )
1660            .toList();
1661
1662        //---* Done *----------------------------------------------------------
1663        return retValue;
1664    }   //  parametersOf()
1665
1666    /**
1667     *  Retrieves the parameters from the given method.
1668     *
1669     *  @param  method  The method.
1670     *  @return The parameters of the given method; the returned list can be
1671     *      empty, but it will not be {@code null}.
1672     */
1673    public final List<ParameterSpec> parametersOf( final Method method )
1674    {
1675        final var retValue = stream( requireNonNullArgument( method, "method" ).getParameters() )
1676            .map( this::createParameter )
1677            .toList();
1678
1679        //---* Done *----------------------------------------------------------
1680        return retValue;
1681    }   //  parametersOf()
1682
1683    /**
1684     *  Creates a builder for a record.
1685     *
1686     *  @param  className   The name of the record type.
1687     *  @return The builder.
1688     */
1689    public final TypeSpec.Builder recordBuilder( final ClassName className )
1690    {
1691        final var retValue = recordBuilder( requireNonNullArgument( className, "className" ).simpleName() );
1692
1693        //---* Done *----------------------------------------------------------
1694        return retValue;
1695    }   //  recordBuilder()
1696
1697    /**
1698     *  Creates a builder for a record.
1699     *
1700     *  @param  name    The name of the record type.
1701     *  @return The builder.
1702     */
1703    public final TypeSpec.Builder recordBuilder( final CharSequence name )
1704    {
1705        final var retValue = new RecordSpecImpl.BuilderImpl( this, requireNotEmptyArgument( name, "name" ) );
1706
1707        //---* Done *----------------------------------------------------------
1708        return retValue;
1709    }   //  recordBuilder()
1710
1711    /**
1712     *  <p>{@summary Sets the maximum number of fields for a class.} If this
1713     *  number is exceeded, an annotation
1714     *  {@link SuppressWarnings &#64;SuppressWarnings}
1715     *  with
1716     *  {@link SuppressableWarnings#CLASS_WITH_TOO_MANY_FIELDS}
1717     *  will be added to the class.</p>
1718     *  <p>Setting the value to 0 or a negative value will disable this
1719     *  feature.</p>
1720     *
1721     *  @param  value   The value.
1722     */
1723    public final void setMaxFields( final int value ) { m_MaxFields = value; }
1724
1725    /**
1726     *  <p>{@summary Sets the maximum number of methods for a class.} If this
1727     *  number is exceeded, an annotation
1728     *  {@link SuppressWarnings &#64;SuppressWarnings}
1729     *  with
1730     *  {@link SuppressableWarnings#CLASS_WITH_TOO_MANY_METHODS}
1731     *  will be added to the class.</p>
1732     *  <p>Setting the value to 0 or a negative value will disable this
1733     *  feature.</p>
1734     *
1735     *  @param  value   The value.
1736     */
1737    public final void setMaxMethods( final int value ) { m_MaxMethods = value; }
1738
1739    /**
1740     *  Creates a new
1741     *  {@link CodeBlock}
1742     *  instance from the given format and arguments, using
1743     *  {@link CodeBlock.Builder#addStatement(String, Object...)}.
1744     *
1745     *  @note   No debug info will be added.
1746     *
1747     *  @param  format  The format.
1748     *  @param  args    The arguments.
1749     *  @return The new code block.
1750     */
1751    public final CodeBlock statementOf( final String format, final Object... args )
1752    {
1753        final var retValue = ((CodeBlockImpl.BuilderImpl) codeBlockBuilder())
1754            .addStatement( format, args )
1755            .build();
1756
1757        //---* Done *----------------------------------------------------------
1758        return retValue;
1759    }   //  codeBlockOf()
1760}
1761//  class JavaComposer
1762
1763/*
1764 *  End of File
1765 */