1 /*
2  * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package com.sun.tools.javadoc.main;
27 
28 import com.sun.javadoc.*;
29 
30 /**
31  * Documents a Serializable field defined by an ObjectStreamField.
32  * <pre>
33  * The class parses and stores the three serialField tag parameters:
34  *
35  * - field name
36  * - field type name
37  *      (fully-qualified or visible from the current import context)
38  * - description of the valid values for the field
39 
40  * </pre>
41  * This tag is only allowed in the javadoc for the special member
42  * serialPersistentFields.
43  *
44  *  <p><b>This is NOT part of any supported API.
45  *  If you write code that depends on this, you do so at your own risk.
46  *  This code and its internal interfaces are subject to change or
47  *  deletion without notice.</b>
48  *
49  * @author Joe Fialli
50  * @author Neal Gafter
51  *
52  * @see java.io.ObjectStreamField
53  */
54 @Deprecated(since="9", forRemoval=true)
55 @SuppressWarnings("removal")
56 class SerialFieldTagImpl
57     extends TagImpl
58     implements SerialFieldTag, Comparable<Object>
59 {
60     //### These could be final, except that the constructor
61     //### does not set them directly.
62 
63     private String fieldName;    // Required Argument 1 of serialField
64     private String fieldType;    // Required Argument 2 of serialField
65     private String description;  // Optional Remaining Arguments of serialField
66 
67     private ClassDoc containingClass;   // Class containing serialPersistentField member
68     private ClassDoc fieldTypeDoc;      // ClassDocImpl of fieldType
69     private FieldDocImpl matchingField; // FieldDocImpl with same name as fieldName
70 
71    /* Constructor. */
SerialFieldTagImpl(DocImpl holder, String name, String text)72    SerialFieldTagImpl(DocImpl holder, String name, String text) {
73         super(holder, name, text);
74         parseSerialFieldString();
75         if (holder instanceof MemberDoc) {
76             containingClass = ((MemberDocImpl)holder).containingClass();
77         }
78     }
79 
80     /*
81      * The serialField tag is composed of three entities.
82      *
83      *   serialField  serializableFieldName serisliableFieldType
84      *                 description of field.
85      *
86      * The fieldName and fieldType must be legal Java Identifiers.
87      */
parseSerialFieldString()88     private void parseSerialFieldString() {
89         int len = text.length();
90         if (len == 0) {
91             return;
92         }
93 
94         // if no white space found
95         /* Skip white space. */
96         int inx = 0;
97         int cp;
98         for (; inx < len; inx += Character.charCount(cp)) {
99              cp = text.codePointAt(inx);
100              if (!Character.isWhitespace(cp)) {
101                  break;
102              }
103         }
104 
105         /* find first word. */
106         int first = inx;
107         int last = inx;
108         cp = text.codePointAt(inx);
109         if (! Character.isJavaIdentifierStart(cp)) {
110             docenv().warning(holder,
111                              "tag.serialField.illegal_character",
112                              new String(Character.toChars(cp)), text);
113             return;
114         }
115 
116         for (inx += Character.charCount(cp); inx < len; inx += Character.charCount(cp)) {
117              cp = text.codePointAt(inx);
118              if (!Character.isJavaIdentifierPart(cp)) {
119                  break;
120              }
121         }
122 
123         if (inx < len && ! Character.isWhitespace(cp = text.codePointAt(inx))) {
124             docenv().warning(holder,
125                              "tag.serialField.illegal_character",
126                              new String(Character.toChars(cp)), text);
127             return;
128         }
129 
130         last = inx;
131         fieldName = text.substring(first, last);
132 
133         /* Skip white space. */
134         for (; inx < len; inx += Character.charCount(cp)) {
135              cp = text.codePointAt(inx);
136              if (!Character.isWhitespace(cp)) {
137                  break;
138              }
139         }
140 
141         /* find second word. */
142         first = inx;
143         last = inx;
144 
145         for (; inx < len; inx += Character.charCount(cp)) {
146              cp = text.codePointAt(inx);
147              if (Character.isWhitespace(cp)) {
148                  break;
149              }
150         }
151         if (inx < len && ! Character.isWhitespace(cp = text.codePointAt(inx))) {
152             docenv().warning(holder,
153                              "tag.serialField.illegal_character",
154                              new String(Character.toChars(cp)), text);
155             return;
156         }
157         last = inx;
158         fieldType = text.substring(first, last);
159 
160         /* Skip leading white space. Rest of string is description for serialField.*/
161         for (; inx < len; inx += Character.charCount(cp)) {
162              cp = text.codePointAt(inx);
163              if (!Character.isWhitespace(cp)) {
164                  break;
165              }
166         }
167         description = text.substring(inx);
168     }
169 
170     /**
171      * return a key for sorting.
172      */
key()173     String key() {
174         return fieldName;
175     }
176 
177     /*
178      * Optional. Link this serialField tag to its corrsponding
179      * field in the class. Note: there is no requirement that
180      * there be a field in the class that matches serialField tag.
181      */
mapToFieldDocImpl(FieldDocImpl fd)182     void mapToFieldDocImpl(FieldDocImpl fd) {
183         matchingField = fd;
184     }
185 
186     /**
187      * Return the serialziable field name.
188      */
fieldName()189     public String fieldName() {
190         return fieldName;
191     }
192 
193     /**
194      * Return the field type string.
195      */
fieldType()196     public String fieldType() {
197         return fieldType;
198     }
199 
200     /**
201      * Return the ClassDocImpl for field type.
202      *
203      * @returns null if no ClassDocImpl for field type is visible from
204      *          containingClass context.
205      */
fieldTypeDoc()206     public ClassDoc fieldTypeDoc() {
207         if (fieldTypeDoc == null && containingClass != null) {
208             fieldTypeDoc = containingClass.findClass(fieldType);
209         }
210         return fieldTypeDoc;
211     }
212 
213     /**
214      * Return the corresponding FieldDocImpl for this SerialFieldTagImpl.
215      *
216      * @returns null if no matching FieldDocImpl.
217      */
getMatchingField()218     FieldDocImpl getMatchingField() {
219         return matchingField;
220     }
221 
222     /**
223      * Return the field comment. If there is no serialField comment, return
224      * javadoc comment of corresponding FieldDocImpl.
225      */
description()226     public String description() {
227         if (description.length() == 0 && matchingField != null) {
228 
229             //check for javadoc comment of corresponding field.
230             Comment comment = matchingField.comment();
231             if (comment != null) {
232                 return comment.commentText();
233             }
234         }
235         return description;
236     }
237 
238     /**
239      * Return the kind of this tag.
240      */
kind()241     public String kind() {
242         return "@serialField";
243     }
244 
245     /**
246      * Convert this object to a string.
247      */
toString()248     public String toString() {
249         return name + ":" + text;
250     }
251 
252     /**
253      * Compares this Object with the specified Object for order.  Returns a
254      * negative integer, zero, or a positive integer as this Object is less
255      * than, equal to, or greater than the given Object.
256      * <p>
257      * Included to make SerialFieldTagImpl items java.lang.Comparable.
258      *
259      * @param   obj the <code>Object</code> to be compared.
260      * @return  a negative integer, zero, or a positive integer as this Object
261      *          is less than, equal to, or greater than the given Object.
262      * @exception ClassCastException the specified Object's type prevents it
263      *            from being compared to this Object.
264      * @since 1.2
265      */
compareTo(Object obj)266     public int compareTo(Object obj) {
267         return key().compareTo(((SerialFieldTagImpl)obj).key());
268     }
269 }
270