1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
package Torello.JavaDoc;


// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// Standard-Java Imports
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

import java.io.IOException;
import java.util.Optional;
import java.util.function.Consumer;


// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// Java-HTML Imports
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

import Torello.Java.*;

import static Torello.Java.C.*;
import static Torello.JavaDoc.PF.*;


// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
// The new Source-Code Parser: com.sun.source.*
// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

import com.sun.source.tree.MethodTree;
import com.sun.source.tree.Tree;

/**
 * <B STYLE='color:darkred;'>Reflection Class:</B>
 * 
 * Holds all information extracted from <CODE>'&#46;java'</CODE> Annotation
 * (<CODE>&#64;interface</CODE>) Source-Files about all Elements identified in that file.
 * 
 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_GET_INST>
 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_AELEM>
 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_DIAGRAM>
 * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_AELEM_NOTE>
 */
@JDHeaderBackgroundImg(EmbedTagFileID={"REFLECTION_EXTENSION"})
public class AnnotationElem
    extends Declaration
    implements java.io.Serializable, Comparable<AnnotationElem>, Cloneable
{
    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
    public static final long serialVersionUID = 1;

    @Override
    String codeHiLiteString() { return this.signature; }


    // ********************************************************************************************
    // ********************************************************************************************
    // Public Fields: The Type, and the (optional) Default-Value
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * An Annotation-Element may only assume one of several types, as per the Java Sun / Oracle
     * Documentation.  The type must be one of the following, or a compile-time error occurs:
     * 
     * <BR /><BR /><UL CLASS=JDUL>
     * <LI>a primitive type</LI>
     * <LI>String</LI>
     * <LI>Class or an invocation of Class</LI>
     * <LI>An enum type</LI>
     * <LI>An annotation type</LI>
     * <LI>An (1 dimensional) array type whose component type is one of the preceding types</LI>
     * </UL>
     */
    public final String type;

    /**
     * <BR /><BR /><B STYLE='color:red;'>JOW: Just One Word</B>
     * 
     * <BR /><BR />The <B STYLE='color:red'>Just One Word</B> convention in the upgrader tool 
     * elminates package-name information from type-{@code String's}.
     */
    public final String typeJOW;

    /**
     * The default value assigned to this element.  
     * This may be null if there is no assigned default value.
     */
    public final String defaultValue;


    // ********************************************************************************************
    // ********************************************************************************************
    // AST Reference-Hook
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * <EMBED CLASS='external-html' DATA-FILE-ID=SSTB_HOOK_FIELD>
     * 
     * If a user decides to make use of the native Sun/Oracle {@code MethodTree} instance that was
     * used to build this {@code Constructor} instance, it may be retrieved from this
     * {@code transient} field.
     * 
     * <BR /><BR /><B>NOTE:</B> The package {@code com.sun.source.tree} "reuses" or "overloads" the
     * {@code MethodTree} object such that it may represent either a Method, or an Annotation
     * Element (or even a Constructor).
     * 
     * <BR /><BR />Since Java Annotations do not actually have methods or constructors, when a
     * {@code MethodTree} instance is one of the Members of a Class-Tree, it should always be 
     * treated as an Annotation-Element (rather than a method or constructor), 
     */
    public final transient MethodTree methodTree;


    // ********************************************************************************************
    // ********************************************************************************************
    // Constructor - com.sun.source.tree 
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * <EMBED CLASS="defs" DATA-KIND=AnnotationElem DATA-ENTITY=MethodTree>
     * <EMBED CLASS='external-html' DATA-FILE-ID=RC_DESCRIPTION>
     * @param mt <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_TREE>
     * @param util <EMBED CLASS='external-html' DATA-FILE-ID=RC_PARAM_UTIL>
     */
    public AnnotationElem(MethodTree mt, TreeUtils util)
    {
        super(
            util,                       // TreeUtils instance (contains all the parser and stuff)
            mt,                         // 'Tree' instance
            mt.getModifiers(),          // ModifiersTree: Annotations on the Element & key-words
            mt.getName().toString(),    // Name Element
            Entity.ANNOTATION_ELEM,     // Entity
            mt.getDefaultValue()        // Treat the "default-value" as the "body"
        );

        Tree defaultValue = mt.getDefaultValue();

        this.type           = mt.getReturnType().toString();
        this.typeJOW        = StrSource.typeToJavaIdentifier(this.type);
        this.defaultValue   = (defaultValue != null) ? defaultValue.toString().trim() : null;

        // Reference Hook: This was built using the com.sun.source.tree.MethodTree class
        this.methodTree = mt;
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // Used Internally by 'SignatureParse'
    // ********************************************************************************************
    // ********************************************************************************************


    // Ensures that the Version with longer type-information strings is used. Java Doc often uses
    //  longer type strings

    public AnnotationElem(AnnotationElem aeFromSourceParser, String jdTypeStr)
    {
        super(aeFromSourceParser);

        // 'AnnotationElem' specific fields.  Copied from Google:
        //
        // Allowed member types (for Annotation-Members / Annotation-Elements) are the following:
        // primitive types, String, Class, enumerated types, annotation types, and arrays of any
        // of the above types (but not an array of arrays).
        //
        // This does mean that the "type" of an Annotation-Elem (sort-of) cannot be abbreviated or
        // extended.  There is no sense in explaining that 'String' is a 'java.lang.String'

        this.type                           = jdTypeStr;
        this.typeJOW                        = aeFromSourceParser.typeJOW;
        this.defaultValue                   = aeFromSourceParser.defaultValue;
        this.methodTree                     = aeFromSourceParser.methodTree;
    }


    // ********************************************************************************************
    // ********************************************************************************************
    // toString(...)
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Generates a {@code String} of this {@code Annotation Element}, with all information included.
     * 
     * @return A printable string of this {@code AnnotationElem}.
     * 
     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
     * @see #toString(int)
     */
    public String toString()
    {
        String def = (defaultValue != null)
            ? ("Default:      [" + StrPrint.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
                "]\n") 
            : "";
    
        return
            "Name:         [" + name + "]\n" +
            "Declaration:  [" + StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
            "Type:         [" + typeJOW + "]\n" +
            "Modifiers:    [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" +
            def +

            // This will **NEVER** be null - unless 'this' instance was built from an HTML File,
            // rather than a source-code file.  Instances like that are only used temporarily, and
            // are garbage collected instantly.  Do this check anyway (just in case).

            "Location:     " + ((this.location == null)
                ? "null" 
                : ('[' + this.location.quickSummary() + ']'));
    }

    /**
     * Generates a {@code String} of this {@code Annotation Element}, with all information
     * included. This will also included any content requested by the {@code 'flags'} parameter.
     * For this class ({@code class AnnotationElem}), the only additional information printed by
     * this {@code 'toString'} method is the Java-Doc Comment {@code String}.
     * 
     * <BR /><BR />This {@code String} may also have UNIX color codes added.
     * 
     * @param flags These are the {@code toString(...)} flags from class {@code PF}
     * ("Print Flags"). View available flags listed in class {@link PF}.
     * 
     * @return A printable {@code String} of this {@code AnnotationElem}.
     * 
     * @see PF
     * @see StrCSV#toCSV(String[], boolean, boolean, Integer)
     * @see #toString()
     */
    public String toString(int flags)
    {
        boolean color = (flags & UNIX_COLORS) > 0;

        return
            printedName("Element", 14, color) + 
            printedDeclaration(14, color) +
            "Type-JOW:     [" + typeJOW + "]\n" + 
            printedModifiers(14) +
            printedLocation(14, color, (flags & BRIEF_LOCATION) > 0) +

            // The previous method does not add a '\n' end to the end of the returned string
            // These are both optional, they add a '\n' AT THE BEGINNING if one of them is included

            printedDefault(color) +
            printedComments(14, color, (flags & JAVADOC_COMMENTS) > 0);
    }

    private String printedDefault(boolean color)
    {
        // They need to abbreviate, seems extremely "unlikely" - but just in case...
        return (defaultValue == null)
            ? ""
            :  "\nDefault:      [" + (color ? BGREEN : "") +
                StrPrint.abbrevEndRDSF(defaultValue, MAX_STR_LEN, true) +
                (color ? RESET : "") + "]";
    }


    // ********************************************************************************************
    // ********************************************************************************************
    //  CompareTo & Equals Stuff
    // ********************************************************************************************
    // ********************************************************************************************


    /**
     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
     * using the two elements' {@code 'name'} field.
     * 
     * @param ae Any other {@code AnnotationElem} to be compared to {@code 'this' AnnotationElem}
     * 
     * @return An integer that fulfills Java's
     * {@code interface Comparable<AnnotationElem> public boolean compareTo(AnnotationElem ae)}
     * method requirements.
     */
    public int compareTo(AnnotationElem ae)
    { return (this == ae) ? 0 : this.name.compareTo(ae.name); }

    /**
     * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object
     * other)} method.  This version of equals merely compares the name of the element defined.
     * The presumption here is that the definition of an 'element' only has meaning - <I>at all</I>
     * - inside the context of an {@code Annotation} where that element has been defined.  Since
     * inside any {@code '.java'} {@code Annotation}, there may only be one element with a given
     * name, this method shall return {@code TRUE} whenever the element being compared also has the
     * same name.
     * 
     * @param other This may be any other {@code Annotation-Element}.  It is <I><B>strongly
     * suggested</B></I> that {@code 'other'} be an {@code element} defined in the same
     * {@code '.java'} source-code file as {@code 'this'} element.
     * 
     * @return This method returns {@code TRUE} when {@code 'this'} instance of
     * {@code AnnotationElem} has the same {@code 'name'} as the name of input-parameter
     * {@code 'other'}
     */
    public boolean equals(AnnotationElem other)
    { return this.name.equals(other.name); }
}