001package Torello.JavaDoc;
002
003
004// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
005// Standard-Java Imports
006// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
007
008import java.io.IOException;
009import java.util.Optional;
010
011
012// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
013// Java-HTML Imports
014// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
015
016import Torello.Java.*;
017
018import static Torello.Java.C.*;
019import static Torello.JavaDoc.PF.*;
020
021import Torello.Java.ReadOnly.ReadOnlyList;
022import Torello.Java.ReadOnly.ROArrayListBuilder;
023
024
025// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
026// JDUInternal
027// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
028
029import Torello.JDUInternal.Annotations.EntityAnnotations.EntityAnnotationData;
030
031
032// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
033// The new Source-Code Parser: com.sun.source.*
034// *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
035
036import com.sun.source.tree.Tree;
037import com.sun.source.tree.VariableTree;
038import com.sun.source.tree.ExpressionTree;
039
040
041/**
042 * <B CLASS=JDDescLabel>Reflection Class:</B>
043 * 
044 * <BR />Holds all information extracted from <CODE>'&#46;java'</CODE> Source-Files about Field's
045 * 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_FIELD>
049 */
050@JDHeaderBackgroundImg(EmbedTagFileID={"REFLECTION_EXTENSION"})
051public class Field extends Declaration
052    implements java.io.Serializable, Comparable<Field>, Cloneable
053{
054    /** <EMBED CLASS='external-html' DATA-FILE-ID=SVUID> */
055    protected static final long serialVersionUID = 1;
056
057    @Override
058    String codeHiLiteString() { return this.signature; }
059
060
061    // ********************************************************************************************
062    // ********************************************************************************************
063    // Public Fields: The Type, and the Initializer
064    // ********************************************************************************************
065    // ********************************************************************************************
066
067
068    /** The definition of this field, as a {@code String}. */
069    public final String definition;
070
071    /** The type / class of this field, as a {@code String}. */
072    public final String type;
073
074    /**
075     * The type / class of this field, as a {@code String}.
076     * <BR /><BR />
077     * <EMBED CLASS='external-html' DATA-FILE-ID=JPB_JOW_TITLE>
078     */
079    public final String typeJOW;
080
081
082    // ********************************************************************************************
083    // ********************************************************************************************
084    // Reference-Hook: com.sun.source.tree
085    // ********************************************************************************************
086    // ********************************************************************************************
087
088
089    /**
090     * <EMBED CLASS='external-html' DATA-FILE-ID=SSTB_HOOK_FIELD>
091     * 
092     * If a user decides to make use of the native Oracle {@code VariableTree}-Instance that
093     * was used to build this {@code Field}-Instance, the {@code VariableTree} may be retrieved
094     * from this {@code transient} field.
095     */
096    public final transient VariableTree variableTree;
097
098
099    // ********************************************************************************************
100    // ********************************************************************************************
101    // Constructor - com.sun.source.tree 
102    // ********************************************************************************************
103    // ********************************************************************************************
104
105
106    // Public, but internally-used-only Constructor for "Field"
107    public Field(
108            final VariableTree          vt,
109            final EntityAnnotationData  ead,
110            final TreeUtils             util
111        )
112    {
113        super(
114            ead,                        // Stuff for building EntityAnnotationMirrors
115            util,                       // TreeUtils instance (contains all the parser and stuff)
116            vt,                         // 'Tree' instance
117            vt.getModifiers(),          // ModifiersTree: Annotations on the Field & key-words
118            vt.getName().toString(),    // Name of the Field
119            Entity.FIELD,               // Entity
120            vt.getInitializer()         // NEW: Pass the initializer to the 'body' tree-node
121        );
122
123        this.type       = vt.getType().toString();
124        this.typeJOW    = StrSource.typeToJavaIdentifier(this.type);
125
126        ExpressionTree initializer = vt.getInitializer();
127
128        this.definition = (initializer == null) ? null : util.substring(initializer).trim();
129
130        // Reference Hook: This was built using the com.sun.source.tree.VariableTree class
131        this.variableTree = vt;
132    }
133
134
135    // ********************************************************************************************
136    // ********************************************************************************************
137    // Constructor: Used Internally by SignatureParse
138    // ********************************************************************************************
139    // ********************************************************************************************
140
141
142    // Ensures that the Version with longer type-information strings is used.
143    // Java Doc often uses longer type strings than is available from the source-code parse
144    // Remember, JavaParser Symbol-Solver doesn't work well, and the Sun/Oracle Parser doesn't have
145    // a linker at all.
146    // 
147    // Intended for JDU Internal-Use-Only
148
149    public Field(final Field fFromSourceParser, final Field fFromHTMLParser)
150    {
151        // Calls the super 'clone' constructor for Declaration
152        // Java Parser has much more information for everything, except the "Type"
153        // JP elects to leave off the "Package Information" for types - while Java Doc includes
154        // it (**unless** it can provide an <A HREF=...> for the type, then it leaves it off too!)
155
156        super(fFromSourceParser);
157
158        // Continuing with: "JP has this info", while Java Doc just leaves this blank.
159        this.definition = fFromSourceParser.definition;
160
161        // Java Doc always produces "java.lang.String", while JP just gives "String"
162        ///
163        // REMEMBER: JP is lazy when it comes to "Package Information" for types.
164        //           Java-Doc includes it often - BUT NOT ALWAYS.  (See above comment)
165        //
166        // Remember, though, the rest of the JavaParser fields are filled out, Java Doc
167        // leaves out all the other information that JP retrieves.
168
169        this.type =
170            (fFromHTMLParser.type.length() > fFromSourceParser.type.length())
171                ? fFromHTMLParser.type
172                : fFromSourceParser.type;
173
174        // This should never matter.  They must be identical.
175        this.typeJOW        = fFromSourceParser.typeJOW;
176        this.variableTree   = fFromSourceParser.variableTree;
177    }
178
179
180    // *************************************************************************************
181    // *************************************************************************************
182    // toString()
183    // *************************************************************************************
184    // *************************************************************************************
185
186
187    /**
188     * Generates a {@code String} of this field, with all information included.
189     * @return A printable {@code String} of this field.
190     * @see #toString(int)
191     */
192    public String toString()
193    {
194        String defStr = (definition == null)
195            ? "null" 
196            : StrPrint.abbrevEndRDSF(definition, MAX_STR_LEN, true);
197
198        return
199            "Name:         [" + name + "]\n" +
200            "Declaration:  [" + StrPrint.abbrevEndRDSF(signature, MAX_STR_LEN, true) + "]\n" +
201            "Type:         [" + type + "]\n" + 
202            "Definition:   [" + defStr + "]\n" +
203            "Modifiers:    [" + StrCSV.toCSV(modifiers, true, true, null) + "]\n" +
204
205            // This will **NEVER** be null - unless 'this' instance was built from an HTML File,
206            // rather than a source-code file.  Instances like that are only used temporarily, and
207            // are garbage collected instantly.  Do this check anyway (just in case).
208
209            "Location:     " + ((this.location == null)
210                ? "null" 
211                : ('[' + this.location.quickSummary() + ']'));
212    }
213
214    /**
215     * <EMBED CLASS='external-html' DATA-FILE-ID=TO_STR_PF>
216     * 
217     * <BR /><BR />There is additional information printed by this {@code 'toString'} method
218     * (versus the zero-argument, standard, Java {@code 'toString'}).  This method will print any
219     * available Java-Doc Comment's that were placed on this {@code Field}.
220     * 
221     * <BR /><BR />This {@code 'toString'} also allows for adding UNIX-Terminal color codes.
222     * 
223     * @param flags These are defined in the {@link PF Print-Flags} class
224     * @return A printable {@code String} of this {@code Field}.
225     * @see PF
226     * @see #toString()
227     */
228    public String toString(int flags)
229    {
230        boolean color = (flags & UNIX_COLORS) > 0;
231
232        return
233            printedName("Field", 15, color) + 
234            printedDeclaration(15, color) +
235            printedType(jowFlags(flags)) +
236            printedDefinition(color) +
237            printedModifiers(15) +
238            printedLocation(15, color, (flags & BRIEF_LOCATION) > 0) +
239
240            // The previous method does not add a '\n' end to the end of the returned string
241            // This is optional, it adds a '\n' AT THE BEGINNING if it is included
242
243            printedComments(15, color, (flags & JAVADOC_COMMENTS) > 0);
244    }
245
246    private String printedType(Torello.Java.Additional.Ret2<Boolean, Boolean> jow)
247    {
248        if (jow.a /*add-JOW*/)
249            return
250                "Type:          [" + type + "]\n" +
251                "Type-JOW:      [" + typeJOW + "]\n";
252        else if (jow.b /*only-JOW*/)
253            return  "Type-JOW:      [" + typeJOW + "]\n";
254        else
255            return  "Type:          [" + type + "]\n";
256    }
257
258    private String printedDefinition(boolean color)
259    {
260        return (definition == null)
261            ? "Definition:    [null]\n"
262            : "Definition:    [" +
263                (color ? BGREEN : "") +
264                StrPrint.abbrevEndRDSF(definition, MAX_STR_LEN, true) +
265                (color ? RESET : "") + "]\n";
266    }
267
268
269    // *************************************************************************************
270    // *************************************************************************************
271    // CompareTo & Equals Stuff
272    // *************************************************************************************
273    // *************************************************************************************
274
275
276    /**
277     * Java's {@code interface Comparable<T>} requirements.  This does a very simple comparison
278     * using the two field's {@link #name} field.
279     * 
280     * @param f Any other {@code Field} to be compared to {@code 'this' Field}
281     * 
282     * @return An integer that fulfills Java's {@code Comparable<Field>} interface
283     * requirements.
284     */
285    public int compareTo(Field f)
286    { return (this == f) ? 0 : this.name.compareTo(f.name); }
287
288    /**
289     * This <I>should be called an "atypical version" of </I> the usual {@code equals(Object
290     * other)} method.  This version of equals merely compares the name of the field defined.  The
291     * presumption here is that the definition of a 'field' only has meaning - <I>at all</I> -
292     * inside the context of a {@code class, interface, } or {@code enumerated-type} where that
293     * field is defined.  Since inside any {@code '.java'} source-code file, there may only be one
294     * field with a given name, this method shall return {@code TRUE} whenever the field being
295     * compared also has the same name.
296     * 
297     * @param other This may be any other field.  It is <I><B>strongly suggested</B></I> that
298     * {@code 'other'} be a field defined in the same {@code '.java'} source-code file as
299     * {@code 'this'} field.
300     * 
301     * @return This method returns {@code TRUE} when {@code 'this'} instance of {@code Field} has
302     * the same {@code 'name'} as the name-field of input-parameter {@code 'other'}
303     */
304    public boolean equals(Field other)
305    { return this.name.equals(other.name); }
306
307
308    // ********************************************************************************************
309    // ********************************************************************************************
310    // A.I. Token-Stream Generator-Method
311    // ********************************************************************************************
312    // ********************************************************************************************
313
314
315    public ReadOnlyList<ReadOnlyList<String>> getTokenStreams()
316    {
317        final ROArrayListBuilder<ReadOnlyList<String>>  tokens  = new ROArrayListBuilder<>();
318        final ROArrayListBuilder<String>                b       = new ROArrayListBuilder<>();
319
320        tokens.add(ReadOnlyList.of("SECTION", "entity", "field"));
321        tokens.add(ReadOnlyList.of("SECTION", "name", this.name));
322        tokens.add(ReadOnlyList.of("SECTION", "signature", this.signature));
323        tokens.add(ReadOnlyList.of("SECTION", "type", this.typeJOW));
324    
325        if ((this.modifiers != null) && (modifiers.size() > 0))
326        {
327            b.clear();
328            b.add("SECTION");
329            b.add("modifiers");
330            for (String m : this.modifiers) b.add(m);
331            tokens.add(b.build());
332        }
333    
334        if ((this.annotations != null) && (annotations.size() > 0))
335        {
336            b.clear();
337            b.add("SECTION");
338            b.add("annotations");
339            for (String a : this.annotations) b.add(a);
340            tokens.add(b.build());
341        }
342    
343        if ((this.definition != null) && (!this.definition.isEmpty()))
344            tokens.add(ReadOnlyList.of("SECTION", "definition", this.definition));
345    
346        return tokens.build();
347    }
348}