001package Torello.JavaDoc;
002
003
004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
005// Standard-Java Imports
006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
007
008import java.io.IOException;
009import java.util.Optional;
010import java.util.function.Consumer;
011
012
013// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
014// Java-HTML Imports
015// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
016
017import Torello.Java.*;
018
019import static Torello.Java.C.*;
020import static Torello.JavaDoc.PF.*;
021
022import Torello.Java.ReadOnly.ReadOnlyList;
023import Torello.Java.ReadOnly.ROArrayListBuilder;
024
025
026// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
027// The new Source-Code Parser: com.sun.source.*
028// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
029
030import com.sun.source.tree.MethodTree;
031import com.sun.source.tree.Tree;
032
033
034// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
035// JDUInternal
036// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
037
038import Torello.JDUInternal.Miscellaneous.EntityAnnotationData;
039
040
041/**
042 * <B CLASS=JDDescLabel>Reflection Class:</B>
043 * 
044 * <BR />Holds all information extracted from <CODE>'&#46;java'</CODE> Annotation
045 * (<CODE>&#64;interface</CODE>) Source-Files about all Elements identified in that file.
046 * 
047 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_GET_INST>
048 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_AELEM>
049 * <!-- EMBED CLASS='external-html' DATA-FILE-ID=JPB_AELEM_NOTE -->
050 */
051@Torello.JavaDoc.Annotations.JDHeaderBackgroundImg(EmbedTagFileID={"REFLECTION_EXTENSION"})
052public class AnnotationElem
053    extends Declaration
054    implements java.io.Serializable, Comparable<AnnotationElem>, Cloneable
055{
056    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
057    public static final long serialVersionUID = 1;
058
059    @Override
060    String codeHiLiteString() { return this.signature; }
061
062
063    // ********************************************************************************************
064    // ********************************************************************************************
065    // Public Fields: The Type, and the (optional) Default-Value
066    // ********************************************************************************************
067    // ********************************************************************************************
068
069
070    /**
071     * An Annotation-Element may only assume one of several types, as per the Java Sun / Oracle
072     * Documentation.  The type must be one of the following, or a compile-time error occurs:
073     * 
074     * <BR /><BR /><UL CLASS=JDUL>
075     * <LI>a primitive type</LI>
076     * <LI>String</LI>
077     * <LI>Class or an invocation of Class</LI>
078     * <LI>An enum type</LI>
079     * <LI>An annotation type</LI>
080     * <LI>An (1 dimensional) array type whose component type is one of the preceding types</LI>
081     * </UL>
082     */
083    public final String type;
084
085    /** <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JOW_2> */
086    public final String typeJOW;
087
088    /**
089     * The default value assigned to this element.  
090     * This may be null if there is no assigned default value.
091     */
092    public final String defaultValue;
093
094
095    // ********************************************************************************************
096    // ********************************************************************************************
097    // AST Reference-Hook
098    // ********************************************************************************************
099    // ********************************************************************************************
100
101
102    /**
103     * <EMBED CLASS='external-html' DATA-FILE-ID=SSTB_HOOK_FIELD>
104     * 
105     * If a user decides to make use of the native Oracle {@code MethodTree} instance that was
106     * used to build this {@code AnnotationElem} instance, it may be retrieved from this
107     * {@code transient} field.
108     * 
109     * <BR /><BR /><B CLASS=JDDescLabel>{@code MethodTree} Note:</B>
110     * 
111     * <BR />The package {@code com.sun.source.tree} "reuses" or "overloads" the {@code MethodTree}
112     * class.  {@code com.sun.source.tree.MethodTree} can actually represent either a Method, or an
113     * Annotation-Element (or even a Constructor!  but that's besides the point).
114     */
115    public final transient MethodTree methodTree;
116
117
118    // ********************************************************************************************
119    // ********************************************************************************************
120    // Constructor - com.sun.source.tree 
121    // ********************************************************************************************
122    // ********************************************************************************************
123
124
125    /**
126     * <EMBED CLASS="defs" DATA-KIND=AnnotationElem DATA-ENTITY=MethodTree>
127     * <EMBED CLASS='external-html' DATA-FILE-ID=RC_DESCRIPTION>
128     * @param mt <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_TREE>
129     * @param util <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_UTIL>
130     */
131    public AnnotationElem(
132            final MethodTree            mt, 
133            final EntityAnnotationData  ead,
134            final TreeUtils             util
135        )
136    {
137        super(
138            ead,                        // Stuff for building EntityAnnotationMirrors
139            util,                       // TreeUtils instance (contains all the parser and stuff)
140            mt,                         // 'Tree' instance
141            mt.getModifiers(),          // ModifiersTree: Annotations on the Element & key-words
142            mt.getName().toString(),    // Name Element
143            Entity.ANNOTATION_ELEM,     // Entity
144            mt.getDefaultValue()        // Treat the "default-value" as the "body"
145        );
146
147        Tree defaultValue = mt.getDefaultValue();
148
149        this.type           = mt.getReturnType().toString();
150        this.typeJOW        = StrSource.typeToJavaIdentifier(this.type);
151        this.defaultValue   = (defaultValue != null) ? defaultValue.toString().trim() : null;
152
153        // Reference Hook: This was built using the com.sun.source.tree.MethodTree class
154        this.methodTree = mt;
155    }
156
157
158    // ********************************************************************************************
159    // ********************************************************************************************
160    // Used Internally by 'SignatureParse'
161    // ********************************************************************************************
162    // ********************************************************************************************
163
164
165    // Ensures that the Version with longer type-information strings is used. Java Doc often uses
166    //  longer type strings
167
168    public AnnotationElem(final AnnotationElem aeFromSourceParser, final String jdTypeStr)
169    {
170        super(aeFromSourceParser);
171
172        // 'AnnotationElem' specific fields.  Copied from Google:
173        //
174        // Allowed member types (for Annotation-Members / Annotation-Elements) are the following:
175        // primitive types, String, Class, enumerated types, annotation types, and arrays of any
176        // of the above types (but not an array of arrays).
177        //
178        // This does mean that the "type" of an Annotation-Elem (sort-of) cannot be abbreviated or
179        // extended.  There is no sense in explaining that 'String' is a 'java.lang.String'
180
181        this.type                           = jdTypeStr;
182        this.typeJOW                        = aeFromSourceParser.typeJOW;
183        this.defaultValue                   = aeFromSourceParser.defaultValue;
184        this.methodTree                     = aeFromSourceParser.methodTree;
185    }
186
187
188    // ********************************************************************************************
189    // ********************************************************************************************
190    // toString(...)
191    // ********************************************************************************************
192    // ********************************************************************************************
193
194
195    /**
196     * Generates a {@code String} of this {@code Annotation Element}, with all information included.
197     * @return A printable string of this {@code AnnotationElem}.
198     * @see #toString(int)
199     */
200    public String toString()
201    {
202        String def = (defaultValue != null)
203            ? ("Default:      [" + StrPrint.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
204                "]\n") 
205            : "";
206    
207        return
208            "Name:         [" + name + "]\n" +
209            "Declaration:  [" + StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
210            "Type:         [" + typeJOW + "]\n" +
211            "Modifiers:    [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" +
212            def +
213
214            // This will **NEVER** be null - unless 'this' instance was built from an HTML File,
215            // rather than a source-code file.  Instances like that are only used temporarily, and
216            // are garbage collected instantly.  Do this check anyway (just in case).
217
218            "Location:     " + ((this.location == null)
219                ? "null" 
220                : ('[' + this.location.quickSummary() + ']'));
221    }
222
223    /**
224     * <EMBED CLASS='external-html' DATA-FILE-ID=TO_STR_PF>
225     * 
226     * <BR /><BR />There is additional information printed by this {@code 'toString'} method
227     * (versus the zero-argument, standard, Java {@code 'toString'}).  This method will print any
228     * available Java-Doc Comment's that were placed on this {@code AnnotationElem}.
229     * 
230     * <BR /><BR />This {@code 'toString'} also allows for adding UNIX-Terminal color codes.
231     * 
232     * @param flags These are defined in the {@link PF Print-Flags} class
233     * @return A printable {@code String} of this {@code AnnotationElem}.
234     * @see PF
235     * @see #toString()
236     */
237    public String toString(int flags)
238    {
239        boolean color = (flags & UNIX_COLORS) > 0;
240
241        return
242            printedName("Element", 14, color) + 
243            printedDeclaration(14, color) +
244            "Type-JOW:     [" + typeJOW + "]\n" + 
245            printedModifiers(14) +
246            printedLocation(14, color, (flags & BRIEF_LOCATION) > 0) +
247
248            // The previous method does not add a '\n' end to the end of the returned string
249            // These are both optional, they add a '\n' AT THE BEGINNING if one of them is included
250
251            printedDefault(color) +
252            printedComments(14, color, (flags & JAVADOC_COMMENTS) > 0);
253    }
254
255    private String printedDefault(boolean color)
256    {
257        // They need to abbreviate, seems extremely "unlikely" - but just in case...
258        return (defaultValue == null)
259            ? ""
260            :  "\nDefault:      [" + (color ? BGREEN : "") +
261                StrPrint.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
262                (color ? RESET : "") + "]";
263    }
264
265
266    // ********************************************************************************************
267    // ********************************************************************************************
268    //  CompareTo & Equals Stuff
269    // ********************************************************************************************
270    // ********************************************************************************************
271
272
273    /**
274     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
275     * using the two elements' {@link #name} field.
276     * 
277     * @param ae Any other {@code AnnotationElem} to be compared to {@code 'this' AnnotationElem}
278     * 
279     * @return An integer that fulfills Java's {@code Comparable<AnnotationElem>} interface
280     * requirements.
281     */
282    public int compareTo(AnnotationElem ae)
283    { return (this == ae) ? 0 : this.name.compareTo(ae.name); }
284
285    /**
286     * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object
287     * other)} method.  This version of equals merely compares the name of the element defined.
288     * The presumption here is that the definition of an 'element' only has meaning - <I>at all</I>
289     * - inside the context of an {@code Annotation} where that element has been defined.  Since
290     * inside any {@code '.java'} {@code Annotation}, there may only be one element with a given
291     * name, this method shall return {@code TRUE} whenever the element being compared also has the
292     * same name.
293     * 
294     * @param other This may be any other {@code Annotation-Element}.  It is <I><B>strongly
295     * suggested</B></I> that {@code 'other'} be an {@code element} defined in the same
296     * {@code '.java'} source-code file as {@code 'this'} element.
297     * 
298     * @return This method returns {@code TRUE} when {@code 'this'} instance of
299     * {@code AnnotationElem} has the same {@code 'name'} as the name of input-parameter
300     * {@code 'other'}
301     */
302    public boolean equals(AnnotationElem other)
303    { return this.name.equals(other.name); }
304
305
306    // ********************************************************************************************
307    // ********************************************************************************************
308    // A.I. Token-Stream Generator-Method
309    // ********************************************************************************************
310    // ********************************************************************************************
311
312
313    public ReadOnlyList<ReadOnlyList<String>> getTokenStreams()
314    {
315        final ROArrayListBuilder<ReadOnlyList<String>>  tokens  = new ROArrayListBuilder<>();
316        ROArrayListBuilder<String>                      b       = new ROArrayListBuilder<>();
317
318        tokens.add(ReadOnlyList.of("SECTION", "entity", "annotation-element"));
319        tokens.add(ReadOnlyList.of("SECTION", "name", this.name));
320        tokens.add(ReadOnlyList.of("SECTION", "type", this.typeJOW));
321    
322        if ((this.defaultValue != null) && (!this.defaultValue.isEmpty()))
323            tokens.add(ReadOnlyList.of("SECTION", "default", this.defaultValue));
324    
325        if ((this.annotations != null) && (this.annotations.size() > 0))
326        {
327            b.add("SECTION");
328            b.add("annotations");
329            for (String a : this.annotations) b.add(a);
330            tokens.add(b.build());
331        }
332    
333        return tokens.build();
334    }
335    
336}