001: /*
002: * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.javadoc;
027:
028: import com.sun.javadoc.*;
029:
030: /**
031: * Documents a Serializable field defined by an ObjectStreamField.
032: * <pre>
033: * The class parses and stores the three serialField tag parameters:
034: *
035: * - field name
036: * - field type name
037: * (fully-qualified or visible from the current import context)
038: * - description of the valid values for the field
039:
040: * </pre>
041: * This tag is only allowed in the javadoc for the special member
042: * serialPersistentFields.
043: *
044: * @author Joe Fialli
045: * @author Neal Gafter
046: *
047: * @see java.io.ObjectStreamField
048: */
049: class SerialFieldTagImpl extends TagImpl implements SerialFieldTag,
050: Comparable<Object> {
051: //### These could be final, except that the constructor
052: //### does not set them directly.
053:
054: private String fieldName; // Required Argument 1 of serialField
055: private String fieldType; // Required Argument 2 of serialField
056: private String description; // Optional Remaining Arguments of serialField
057:
058: private ClassDoc containingClass; // Class containing serialPersistentField member
059: private ClassDoc fieldTypeDoc; // ClassDocImpl of fieldType
060: private FieldDocImpl matchingField; // FieldDocImpl with same name as fieldName
061:
062: /* Constructor. */
063: SerialFieldTagImpl(DocImpl holder, String name, String text) {
064: super (holder, name, text);
065: parseSerialFieldString();
066: if (holder instanceof MemberDoc) {
067: containingClass = ((MemberDocImpl) holder)
068: .containingClass();
069: }
070: }
071:
072: /*
073: * The serialField tag is composed of three entities.
074: *
075: * serialField serializableFieldName serisliableFieldType
076: * description of field.
077: *
078: * The fieldName and fieldType must be legal Java Identifiers.
079: */
080: private void parseSerialFieldString() {
081: int len = text.length();
082:
083: // if no white space found
084: /* Skip white space. */
085: int inx = 0;
086: int cp;
087: for (; inx < len; inx += Character.charCount(cp)) {
088: cp = text.codePointAt(inx);
089: if (!Character.isWhitespace(cp)) {
090: break;
091: }
092: }
093:
094: /* find first word. */
095: int first = inx;
096: int last = inx;
097: cp = text.codePointAt(inx);
098: if (!Character.isJavaIdentifierStart(cp)) {
099: docenv().warning(holder,
100: "tag.serialField.illegal_character",
101: new String(Character.toChars(cp)), text);
102: return;
103: }
104:
105: for (inx += Character.charCount(cp); inx < len; inx += Character
106: .charCount(cp)) {
107: cp = text.codePointAt(inx);
108: if (!Character.isJavaIdentifierPart(cp)) {
109: break;
110: }
111: }
112:
113: if (inx < len
114: && !Character.isWhitespace(cp = text.codePointAt(inx))) {
115: docenv().warning(holder,
116: "tag.serialField.illegal_character",
117: new String(Character.toChars(cp)), text);
118: return;
119: }
120:
121: last = inx;
122: fieldName = text.substring(first, last);
123:
124: /* Skip white space. */
125: for (; inx < len; inx += Character.charCount(cp)) {
126: cp = text.codePointAt(inx);
127: if (!Character.isWhitespace(cp)) {
128: break;
129: }
130: }
131:
132: /* find second word. */
133: first = inx;
134: last = inx;
135:
136: for (; inx < len; inx += Character.charCount(cp)) {
137: cp = text.codePointAt(inx);
138: if (Character.isWhitespace(cp)) {
139: break;
140: }
141: }
142: if (inx < len
143: && !Character.isWhitespace(cp = text.codePointAt(inx))) {
144: docenv().warning(holder,
145: "tag.serialField.illegal_character",
146: new String(Character.toChars(cp)), text);
147: return;
148: }
149: last = inx;
150: fieldType = text.substring(first, last);
151:
152: /* Skip leading white space. Rest of string is description for serialField.*/
153: for (; inx < len; inx += Character.charCount(cp)) {
154: cp = text.codePointAt(inx);
155: if (!Character.isWhitespace(cp)) {
156: break;
157: }
158: }
159: description = text.substring(inx);
160: }
161:
162: /**
163: * return a key for sorting.
164: */
165: String key() {
166: return fieldName;
167: }
168:
169: /*
170: * Optional. Link this serialField tag to its corrsponding
171: * field in the class. Note: there is no requirement that
172: * there be a field in the class that matches serialField tag.
173: */
174: void mapToFieldDocImpl(FieldDocImpl fd) {
175: matchingField = fd;
176: }
177:
178: /**
179: * Return the serialziable field name.
180: */
181: public String fieldName() {
182: return fieldName;
183: }
184:
185: /**
186: * Return the field type string.
187: */
188: public String fieldType() {
189: return fieldType;
190: }
191:
192: /**
193: * Return the ClassDocImpl for field type.
194: *
195: * @returns null if no ClassDocImpl for field type is visible from
196: * containingClass context.
197: */
198: public ClassDoc fieldTypeDoc() {
199: if (fieldTypeDoc == null && containingClass != null) {
200: fieldTypeDoc = containingClass.findClass(fieldType);
201: }
202: return fieldTypeDoc;
203: }
204:
205: /**
206: * Return the corresponding FieldDocImpl for this SerialFieldTagImpl.
207: *
208: * @returns null if no matching FieldDocImpl.
209: */
210: FieldDocImpl getMatchingField() {
211: return matchingField;
212: }
213:
214: /**
215: * Return the field comment. If there is no serialField comment, return
216: * javadoc comment of corresponding FieldDocImpl.
217: */
218: public String description() {
219: if (description.length() == 0 && matchingField != null) {
220:
221: //check for javadoc comment of corresponding field.
222: Comment comment = matchingField.comment();
223: if (comment != null) {
224: return comment.commentText();
225: }
226: }
227: return description;
228: }
229:
230: /**
231: * Return the kind of this tag.
232: */
233: public String kind() {
234: return "@serialField";
235: }
236:
237: /**
238: * Convert this object to a string.
239: */
240: public String toString() {
241: return name + ":" + text;
242: }
243:
244: /**
245: * Compares this Object with the specified Object for order. Returns a
246: * negative integer, zero, or a positive integer as this Object is less
247: * than, equal to, or greater than the given Object.
248: * <p>
249: * Included to make SerialFieldTagImpl items java.lang.Comparable.
250: *
251: * @param obj the <code>Object</code> to be compared.
252: * @return a negative integer, zero, or a positive integer as this Object
253: * is less than, equal to, or greater than the given Object.
254: * @exception ClassCastException the specified Object's type prevents it
255: * from being compared to this Object.
256: * @since 1.2
257: */
258: public int compareTo(Object obj) {
259: return key().compareTo(((SerialFieldTagImpl) obj).key());
260: }
261: }
|