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