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