001package Torello.JavaDoc;
002
003
004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
005// Standard-Java Imports
006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
007
008import java.io.IOException;
009import java.util.List;
010import java.util.function.Consumer;
011import java.util.Optional;
012
013
014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
015// Java-HTML Imports
016// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
017
018import Torello.Java.*;
019
020import static Torello.JavaDoc.PF.*;
021import static Torello.Java.C.*;
022
023import Torello.Java.Additional.Ret4;
024import Torello.Java.Function.IntTFunction;
025import Torello.Java.ReadOnly.ROArrayListBuilder;
026import Torello.Java.ReadOnly.ReadOnlyArrayList;
027import Torello.Java.ReadOnly.ReadOnlyList;
028
029import Torello.JDUInternal.DataClasses.MainLoopData.AnnotationsMirror;
030import Torello.JDUInternal.DataClasses.MainLoopData.CallableSignature;
031
032
033// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
034// The new Source-Code Parser: com.sun.source.*
035// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
036
037import com.sun.source.tree.*;
038
039
040/**
041 * <B STYLE='color:darkred;'>Reflection Class:</B>
042 * 
043 * Common-Root Ancestor Class of both {@link Method} and {@link Constructor}.
044 * 
045 * <BR /><BR />
046 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_CALLBL>
047 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM>
048 */
049@JDHeaderBackgroundImg
050public abstract class Callable extends Declaration implements java.io.Serializable
051{
052    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
053    public static final long serialVersionUID = 1;
054
055    // COMPLETELY UN-USED RIGHT NOW, EXPERIMENTAL-ONLY
056    public final String autoFindID;
057
058    @Override
059    String codeHiLiteString()
060    { return (this.body == null) ? null : StrIndent.chompCallableBraces(this.body); }
061
062
063    // ********************************************************************************************
064    // ********************************************************************************************
065    // protected final String[] parameterNames;
066    // ********************************************************************************************
067    // ********************************************************************************************
068
069
070    /**
071     * The names of all parameters to this {@code Method} or {@code Constructor}.
072     *  
073     * <BR /><BR /><B CLASS=JDDescLabel>Parallel List:</B>
074     * 
075     * <BR />This list must be considered a parallel list to the other parameter-related list:
076     * {@link #parameterTypes}, {@link #parameterTypesJOW} and {@link #parameterAnnotations}
077     */
078    public final ReadOnlyList<String> parameterNames;
079
080    /**
081     * This contains the types of the parameters, stored as {@code String's}.  The contents of
082     * these {@code String's} do include: <I>package-name, containing classes (if
083     * inner-classes), and generic-parameter expressions (if generic-types).</I>  These names are
084     * as fully-qualified as the AST Parser allows.
085     * 
086     * <BR /><BR /><B CLASS=JDDescLabel>JOW Alternative:</B>
087     * 
088     * <BR />The {@code ReadOnlyList} {@link #parameterTypesJOW} reduces these types (as
089     * {@code String's}) to a single-word.  If a {@link Method} or a {@link Constructor} that
090     * accepts a paremeter such as {@code java.util.Iterable<Integer>}, and it seems
091     * <I>'difficult to work with'</I> - the entry in {@link #parameterTypesJOW} at the
092     * same array-location would contain, simply, the Java {@code String 'Iterable'}.
093     * 
094     * <BR /><BR /><B CLASS=JDDescLabel>Parallel List:</B>
095     * 
096     * <BR />This list must be considered a parallel list to the other parameter-related list:
097     * {@link #parameterNames}, {@link #parameterTypesJOW} and {@link #parameterAnnotations}
098     */
099    public final ReadOnlyList<String> parameterTypes;
100
101    /**
102     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JOW_TITLE>
103     * 
104     * <BR /><BR /><B CLASS=JDDescLabel>Parallel List:</B>
105     * 
106     * <BR />This list must be considered a parallel list to the other parameter-related list:
107     * {@link #parameterNames}, {@link #parameterTypes} and {@link #parameterAnnotations}
108     */
109    public final ReadOnlyList<String> parameterTypesJOW;
110
111    /**
112     * Any parameters that are annotated will have the <I>exact text-{@code String} of the
113     * annotations that were used in the source-code for that parameter</I> stored in this
114     * two-dimensional {@code String[][]} array.
115     * 
116     * <BR /><BR />This list will retrieve and contain the actual character data that may be found
117     * in the source-code file for an element in a {@code com.sun.source} 'AST' (Abstract Syntax
118     * Tree).  The list of annotations on a parameter (if any) will each be saved as a
119     * {@code java.lang.String}.
120     * 
121     * <BR /><BR /><B CLASS=JDDescLabel>Null Warning:</B>
122     * 
123     * <BR />Unlike the other lists in class {@code Callable}, when there are no parameters for 
124     * a {@code Callabe}, or when there are parameters, but none of them have been annotated,
125     * <I>for the purposes of efficiency and better memory management, this field will simply be
126     * assigned null</I>.
127     * 
128     * <BR /><BR />In almost all cases (particularly in the Java HTML Library), this
129     * two-dimensional list, itself, really will be null - <I>since parameter annotations are
130     * quite uncommon</I>.  Perhaps, some users make use of them from time to time.
131     *  
132     * <BR /><BR /><B CLASS=JDDescLabel>Parallel List:</B>
133     * 
134     * <BR />This list must be considered a parallel list to the other parameter-related list:
135     * {@link #parameterNames}, {@link #parameterTypes} and {@link #parameterTypesJOW}
136     */
137    public final ReadOnlyList<ReadOnlyList<String>> parameterAnnotations;
138
139    /**
140     * The names of all {@code Exception, Error} and {@code Throwable} that may be thrown by this
141     * {@code Constructor} or {@code Method}.
142     * 
143     * <BR /><BR /><B STYLE='color: red;'>NOTE:</B> Only exceptions which are included in the
144     * actual {@link Declaration#signature}, inside the original {@code '.java'} source-file for
145     * this {@code Callable} will be listed in this array.
146     */
147    public final ReadOnlyList<String> exceptions;
148
149
150    // ********************************************************************************************
151    // ********************************************************************************************
152    // Quick Parameter Helper Methods
153    // ********************************************************************************************
154    // ********************************************************************************************
155
156
157    /**
158     * Retrieves the number of parameters utilized by the {@link Method} or {@link Constructor}
159     * ({@code Callable})
160     * 
161     * @return The size of all three of the parameter {@link ReadOnlyList}'s'
162     */
163    public int numParameters()
164    { return parameterNames.size(); }
165
166    /**
167     * This will retrieve the type of the parameter (as a {@code String}) that has the name
168     * {@code 'parameterName'}.  This method will simply return null, gracefully, if this
169     * {@link Method} or {@link Constructor} does not have a parameter with that name.  This method
170     * will not throw an exception in such cases.
171     * 
172     * @param parameterName The name of the parameter whose type you are requesting.
173     * 
174     * @return The fully-qualified type of the parameter, as a {@code String} having the name
175     * {@code 'parameterName'}, or null if no such type exists.
176     * 
177     * @see #parameterTypes
178     * @see #parameterNames
179     */
180    public String getParameterType(String parameterName)
181    {
182        for (int i=0; i < parameterNames.size(); i++)
183            if (parameterNames.get(i).equals(parameterName))
184                return parameterTypes.get(i);
185
186        return null;
187    }
188
189    /** 
190     * This will retrieve the type of the parameter (as a {@code String}) that has the name
191     * {@code 'parameterName'}.  This method will simply return null, gracefully, if this
192     * {@link Method} or {@link Constructor} does not have a parameter with that name.  This
193     * method will not throw an exception in such cases.
194     * 
195     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_C_JOW_NOTE>
196     * 
197     * @param parameterName The name of the parameter whose type you are requesting.
198     * 
199     * @return The type of the parameter, as a <B>one-word {@code String}</B> having the name
200     * {@code 'parameterName'}.
201     * 
202     * @see #parameterTypesJOW
203     * @see #parameterTypes
204     * @see #parameterNames
205     */
206    public String getParameterTypeJOW(String parameterName)
207    {
208        if (parameterNames != null)
209            for (int i=0; i < parameterNames.size(); i++)
210                if (parameterNames.get(i).equals(parameterName))
211                    return parameterTypesJOW.get(i);
212
213        return null;
214    }
215
216    /**
217     * This will retrieve the annotations-list that may (or may not) adorn the parameter which uses
218     * the name {@code 'parameterName'}.
219     * 
220     * <BR /><BR />This method will simply return null, gracefully, if this {@link Method} or
221     * {@link Constructor} does not have a parameter with that name.  This method will not throw
222     * an exception in such cases.
223     * 
224     * <BR /><BR /><B>NOTE:</B>This method will also return null even if a parameter having the
225     * provided name is found, but that parameter wasn't annotated with anything.  If a null is
226     * returned, distinguishing between the case where {@code 'parameterName'} just wasn't found,
227     * and the case where that parameter wasn't annotated - isn't possible here.
228     * 
229     * @param parameterName The name of the parameter whose annotation-list you are requesting.
230     * 
231     * @return The type of the parameter having the name {@code 'parameterName'}.
232     * 
233     * @see #parameterAnnotations
234     * @see #parameterNames
235     */
236    public ReadOnlyList<String> getParameterAnnotations(String parameterName)
237    {
238        if (parameterAnnotations == null) return null;
239
240        for (int i=0; i < parameterNames.size(); i++)
241
242            if (parameterNames.get(i).equals(parameterName))
243                return parameterAnnotations.get(i);
244                    // In the line above, if a parameter isnt annotated, that location in the 
245                    // array will have a 'null'
246
247        return null;
248    }
249
250    /**
251     * This will look at each parmeter's annotation array to see if there are any parameters in
252     * this {@code Callable's} invocation parameter-list that were annotated with anything.
253     * 
254     * @return {@code TRUE} if there are any parameters that were annotated with something, and
255     * false if <B><I>every parameter</I></B> in the parameter-list had a 'null' {@code String}
256     * array of parameter-annotations.
257     * 
258     * <BR /><BR />If this instance of {@code Callable} is one which does not accept any
259     * parameters, this methhod will return {@code FALSE} immediately.
260     * 
261     * <BR /><BR /><B STYLE='color:red;'>NOTE:</B> The internal {@code 'parameterAnnotations'}
262     * field for class {@code Callable} is implemented as a two-dimensional {@code String}-array.
263     * There may be any number of parameters that are passed to a {@link Method} or
264     * {@code Constructor}, and each of those parameters may have any number of annotations that
265     * were attached to them.
266     * 
267     * <BR /><BR /><B>SANITY-CHECK</B> Likely {@code 99.99%} of the parameters in the Java HTML
268     * library do not have any parameter's that are annotated.
269     * 
270     * @see #parameterAnnotations
271     */
272    public boolean hasAnnotatedParameters()
273    { return parameterAnnotations != null; }
274
275    /**
276     * Reports how many of the parameters in the internal list of parameters that had annotations
277     * attached to them.
278     * 
279     * <BR /><BR /><B>SANITY-CHECK</B> Likely {@code 99.99%} of the parameters in the Java HTML
280     * library do not have any parameter's that are annotated.
281     * 
282     * @return This will count how many parameters which are used by this {@code Callable}
283     * (either {@link Method} or {@link Field}) that have annotations that were attached to
284     * the parameter.
285     * 
286     * @see #parameterAnnotations
287     */
288    public int numAnnotatedParameters()
289    {
290        int count = 0;
291
292        if (parameterAnnotations == null) return 0;
293
294        // NOTE: each parameter has an "Annotation List" stored in a 2-D array.  This is why
295        //       this for-loop is using 'String[]', rather than 'String' ...
296        //       A parameter may be annotated with zero annotations, one, or many annotations.
297
298        for (ReadOnlyList<String> paList : parameterAnnotations)
299            if (paList.size() > 0) count++;
300
301        return count;
302    }
303
304
305    // ********************************************************************************************
306    // ********************************************************************************************
307    // Constructor - com.sun.source.tree 
308    // ********************************************************************************************
309    // ********************************************************************************************
310
311
312    // package-private: Only used by subclasses.
313    Callable(
314            MethodTree  methodOrConstructor,
315            String      methodOrConstructorName,
316            Entity      entity,
317            TreeUtils   util
318        )
319    {
320        super(
321            util,                               // Big Ret4 thing
322            methodOrConstructor,                // com.sun.source.Tree.MethodTree instance
323            methodOrConstructor.getModifiers(), // Annotation **AND** public, static, final
324            methodOrConstructorName,            // Method-Name or "<init>"
325            entity,                             // Entity.METHOD or Entity.CONSTRUCTOR
326            methodOrConstructor.getBody()
327        );
328
329
330        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
331        // Callable Parameters
332        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
333
334        List<? extends VariableTree> pList = methodOrConstructor.getParameters();
335
336        if ((pList == null) || (pList.size() == 0))
337        {
338            this.parameterNames         =  EMPTY_READONLY_LIST;
339            this.parameterTypes         =  EMPTY_READONLY_LIST;
340            this.parameterTypesJOW      =  EMPTY_READONLY_LIST;
341            this.parameterAnnotations   =  null;
342        }
343
344        else 
345        {
346            int SIZE = pList.size();
347            boolean atLeastOneAnnotatedParameter = false;
348
349            // For efficiency, use the ROAL-Builder, because otherwise (using ReadOnlyArrayList
350            // constructor), the Iterator would have to be run 4 separate times.
351
352            ROArrayListBuilder<String> bParameterNames      = new ROArrayListBuilder<>(SIZE);
353            ROArrayListBuilder<String> bParameterTypes      = new ROArrayListBuilder<>(SIZE);
354            ROArrayListBuilder<String> bParameterTypesJOW   = new ROArrayListBuilder<>(SIZE);
355    
356            ROArrayListBuilder<ReadOnlyList<String>> bParameterAnnotations =
357                new ROArrayListBuilder<>();
358
359            for (VariableTree vt : pList)
360            {
361                bParameterNames.add(vt.getName().toString());
362
363                String type = vt.getType().toString();
364    
365                bParameterTypes.add(type);
366                bParameterTypesJOW.add(StrSource.typeToJavaIdentifier(type));
367
368                // NOTE: You **WILL TRY** again...  It cannot be done - a Var-Args Parameter is auto
369                // converted into an Array by com.sun.souce.tree.  There isn't a way to know that it
370                // was a Var-Args.  (Other than by parsing the JavaDocHTMLFile)
371                //
372                // System.out.println("    " + this.parameterTypes[i] + "  ==>  " +
373                //      this.parameterTypesJOW[i]);
374
375                // List<? extends AnnotationTree> annotList = ...
376                @SuppressWarnings("unchecked")
377                List<AnnotationTree> annotList = 
378                    (List<AnnotationTree>) vt.getModifiers().getAnnotations();
379
380                if ((annotList == null) || (annotList.size() == 0))
381                    bParameterAnnotations.add(null);
382                else
383                {
384                    atLeastOneAnnotatedParameter = true;
385
386                    bParameterAnnotations.add(
387                        new ReadOnlyArrayList<String>(
388                            annotList,
389                            (AnnotationTree at) -> at.toString().trim(),
390                            annotList.size()
391                        ));
392                }
393            }
394
395            this.parameterNames     =  bParameterNames.build();
396            this.parameterTypes     =  bParameterTypes.build();
397            this.parameterTypesJOW  =  bParameterTypesJOW.build();
398
399            this.parameterAnnotations = atLeastOneAnnotatedParameter
400                ? bParameterAnnotations.build()
401                : null;
402        }
403
404
405        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
406        // Throws Clauses Declared by this Callable
407        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
408
409        @SuppressWarnings("unchecked")
410        // List<? extends ExpressionTree> tl = ...
411        List<ExpressionTree> tl = (List<ExpressionTree>) methodOrConstructor.getThrows();
412
413        if ((tl == null) || (tl.size() == 0))
414            this.exceptions = EMPTY_READONLY_LIST;
415
416        else this.exceptions = new ReadOnlyArrayList<String>
417            (tl, (ExpressionTree et) -> et.toString().trim(), tl.size());
418
419
420        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
421        // FINISHED
422        // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
423        //
424        // Currently Unused / Experimental
425        // this.autoFindID = AnnotationsMirror.processAutoFindID(annotations, signature);
426
427        this.autoFindID = "";
428    }
429
430
431    // ********************************************************************************************
432    // ********************************************************************************************
433    // Package-Private Constructor: Used Internally by 'JDUInternal.ParseHTML.SignatureParse'
434    // ********************************************************************************************
435    // ********************************************************************************************
436
437
438    // Ensures that the Version with longer type-information strings is used.
439    // Java Doc often uses longer type strings
440    //
441    // This cannot be public because this "Merge" expects that both of these constructors are
442    // identical - with the only noted difference being one was from JavaDoc and one was from the
443    // source-code.  The array-lengths need to be equal or else IndexOutOfBoundsException will
444    // start throwing.  Plus, this is not useful outside of the upgrade application.
445    //
446    // This "merging" of two instances of Callable is **ONLY NEEDED** for Methods and Constructors,
447    // **AND NOT** for Fields, Enum-Constants or Annotation-Elements.
448
449    Callable(CallableSignature cSig, Callable cFromSourceParser)
450    {
451        // Calls the super 'clone' constructor for Declaration
452        // Java Parser has much more information for everything, except the "Parameter Types"
453        // JP elects to leave off the "Package Information" for types - while Java Doc includes
454        // it (**unless** it can provide an <A HREF=...> for the type, then it leaves it off too!)
455
456        super(cFromSourceParser);
457
458        this.parameterNames         = cFromSourceParser.parameterNames;
459        this.parameterTypesJOW      = cFromSourceParser.parameterTypesJOW;
460        this.exceptions             = cFromSourceParser.exceptions;
461        this.parameterAnnotations   = cFromSourceParser.parameterAnnotations;
462
463        // Currently Unused / Experimental
464        this.autoFindID = cFromSourceParser.autoFindID;
465
466        if (cFromSourceParser.parameterTypes.size() == 0)
467            this.parameterTypes = EMPTY_READONLY_LIST;
468
469        else
470        {
471            ROArrayListBuilder<String> roalb =
472                new ROArrayListBuilder<>(cFromSourceParser.parameterTypes.size());
473
474            // Java Doc always produces "java.lang.String", while JP just gives "String"
475            // REMEMBER: JP is lazy when it comes to "Package Information" for types.
476            //           Java-Doc includes it often - BUT NOT ALWAYS.  (See above comment)
477            // Remember, though, the rest of the JavaParser fields are filled out, Java Doc
478            // leaves out all the other information that JP retrieves.
479
480            for (int i=0; i < cFromSourceParser.parameterTypes.size(); i++)
481
482                roalb.add(
483                    (cSig.parameterTypes.get(i).length() >
484                        cFromSourceParser.parameterTypes.get(i).length())
485
486                        ? cSig.parameterTypes.get(i)
487                        : cFromSourceParser.parameterTypes.get(i)
488                );
489
490            this.parameterTypes = roalb.build();
491        }
492    }
493
494    Callable(CallableSignature cSig, Entity entity)
495    {
496        super(cSig.name, entity, cSig.signature);
497
498        this.parameterNames         = cSig.parameterNames;
499        this.parameterTypes         = cSig.parameterTypes;
500        this.parameterTypesJOW      = cSig.parameterTypesJOW;
501        this.exceptions             = null;
502        this.autoFindID             = null;
503        this.parameterAnnotations   = null;
504    }
505
506
507    // ********************************************************************************************
508    // ********************************************************************************************
509    // NEW HELPER
510    // ********************************************************************************************
511    // ********************************************************************************************
512
513
514    boolean nearlyEqualsCallableSig(CallableSignature cSig)
515    {
516        // This works for Methods and Constructors.  This method used to be in the actual 'Method'
517        // and 'Constructor' sub-class due to this one-line optimization.  (This is an un-necessary
518        // check for Constructors, but not for methods).
519
520        if (this.numParameters() != cSig.parameterNames.size()) return false;
521
522        // If there are no parameters (for either of them), then return true immediately
523        if (this.numParameters() == 0) return true;
524
525        // If any of the parameter-names are different, break immediately and return false;
526        for (int i=0; i < this.parameterNames.size(); i++)
527            if (! this.parameterNames.get(i).equals(cSig.parameterNames.get(i)))
528                return false;
529
530        // If the parameter-types listed by the javadoc '.html' file differ from parameter-types
531        // listed in the original '.java' source-code file, then break immediately.
532        //
533        // NOTE: The "package-information" for the FULL CLASS OR INTERFACE NAME is not always
534        // available.
535
536        for (int i=0; i < this.parameterTypes.size(); i++)
537            if (! this.parameterTypesJOW.get(i).equals(cSig.parameterTypesJOW.get(i)))
538                return false;
539
540        // ALL TESTS PASSED
541        return true;
542    }
543
544
545    // ********************************************************************************************
546    // ********************************************************************************************
547    // HELPERS - toString(int flags)
548    // ********************************************************************************************
549    // ********************************************************************************************
550
551
552    String printedParamNames()
553    {
554        return
555            "Parameter Names:    " +
556            "[" + 
557                ((parameterNames != null)
558                    ? StrCSV.toCSV(parameterNames, true, true, null) : "") +
559            "]\n";
560    }
561
562    String printedParamTypes(Torello.Java.Additional.Ret2<Boolean, Boolean> jow)
563    {
564        boolean b = parameterTypesJOW == null;
565
566        if (jow.b /*onlyJOW*/) return
567            "Simple Param-Types: " +
568            "[" + 
569                (b ? "" : StrCSV.toCSV(parameterTypesJOW, true, true, null)) +
570            "]\n";
571
572        else if (jow.a /*addJOW*/) return
573            "Parameter Types:    " +
574            "[" + 
575                (b ? "" : StrCSV.toCSV(parameterTypes, true, true, null)) +
576            "]\n" +
577            "Simple Param-Types: " +
578            "[" +
579                (b ? "" : StrCSV.toCSV(parameterTypesJOW, true, true, null)) +
580            "]\n";
581
582        else return
583            "Parameter Types:    " +
584            "[" +
585                (b ? "" : StrCSV.toCSV(parameterTypes, true, true, null)) +
586            "]\n";
587    }
588
589    String printedExceptions()
590    {
591        return
592            "Exceptions:         " +
593            "[" +
594                ((exceptions == null) ? "" : StrCSV.toCSV(exceptions, true, true, null)) +
595            "]\n";
596    }
597
598    String printedCallableBody(int flags)
599    {
600        boolean methodBody      = (flags & BODY) > 0;
601        boolean shortMethodBody = (flags & BODY_SHORT) > 0;
602
603        // "shortMethodBody" has a higher FLAG-PRECEDENCE
604        if (methodBody && shortMethodBody) methodBody = false;
605
606        if ((! methodBody) && (! shortMethodBody)) return "";
607
608        String bodyStr = (this.body != null) ? codeHiLiteString() : "Not Defined";
609
610        // "Synthetic Methods" do not have a body.  Interface Methods also do not have one, either
611        // If this was built from the JavaDoc Signature, it will *ALSO* have no body...
612
613        if (shortMethodBody) bodyStr = StrPrint.abbrevEndRDSF(bodyStr, MAX_STR_LEN, true);
614
615        if (    shortMethodBody
616            ||  ((bodyStr.indexOf('\n') == -1) && (bodyStr.length() <= MAX_STR_LEN))
617        )
618            return "\nCallable Body:      [" + bodyStr + " ]";
619        else if (methodBody)
620            return "\nCallable Body:      [\n" + bodyStr + "\n]";
621        else
622            return "";   
623    }
624
625    /**
626     * Dummy Method.  Overriden by Concrete Sub-Classes.
627     * @see Method#toString()
628     * @see Constructor#toString()
629     */
630    public String toString()
631    { return "Callable is Abstract, all Concrete Sub-Classes Override this method."; }
632
633    /**
634     * Dummy Method.  Overriden by Concrete Sub-Classes.
635     * @see Method#toString(int)
636     * @see Constructor#toString(int)
637     */
638    public String toString(int flags)
639    { return "Callable is Abstract, all Concrete Sub-Classes Override this method."; }
640
641
642    // ********************************************************************************************
643    // ********************************************************************************************
644    // HELPERS - toString() - NO FLAGS
645    // ********************************************************************************************
646    // ********************************************************************************************
647
648
649    String printedParameterNamesTS()
650    {
651        return
652            "Parameter Names: [" + 
653                    ((parameterNames == null)
654                        ? ""
655                        : StrCSV.toCSV(parameterNames, true, true, null)
656                    ) + "]\n";
657    }
658
659    String printedParameterTypesTS()
660    {
661        return
662            "Parameter Types: [" +
663                    ((parameterTypesJOW == null)
664                        ? ""
665                        : StrCSV.toCSV(parameterTypesJOW, true, true, null)
666                    ) + "]\n";
667    }
668
669    String printedExceptionsTS()
670    {
671        return
672            "Exceptions:      [" +
673                ((exceptions == null)
674                    ? ""
675                    : StrCSV.toCSV(exceptions, true, true, null)
676                 ) + "]\n";
677    }
678}