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: import com.sun.tools.javac.code.Flags;
031: import com.sun.tools.javac.code.Kinds;
032: import com.sun.tools.javac.code.Scope;
033: import com.sun.tools.javac.code.Symbol.VarSymbol;
034: import com.sun.tools.javac.code.Symbol.ClassSymbol;
035: import com.sun.tools.javac.code.Symbol.MethodSymbol;
036: import com.sun.tools.javac.util.Name;
037: import com.sun.tools.javac.util.ListBuffer;
038:
039: /**
040: * The serialized form is the specification of a class' serialization
041: * state. <p>
042: *
043: * It consists of the following information:<p>
044: *
045: * <pre>
046: * 1. Whether class is Serializable or Externalizable.
047: * 2. Javadoc for serialization methods.
048: * a. For Serializable, the optional readObject, writeObject,
049: * readResolve and writeReplace.
050: * serialData tag describes, in prose, the sequence and type
051: * of optional data written by writeObject.
052: * b. For Externalizable, writeExternal and readExternal.
053: * serialData tag describes, in prose, the sequence and type
054: * of optional data written by writeExternal.
055: * 3. Javadoc for serialization data layout.
056: * a. For Serializable, the name,type and description
057: * of each Serializable fields.
058: * b. For Externalizable, data layout is described by 2(b).
059: * </pre>
060: *
061: * @since 1.2
062: * @author Joe Fialli
063: * @author Neal Gafter (rewrite but not too proud)
064: */
065: class SerializedForm {
066: ListBuffer<MethodDoc> methods = new ListBuffer<MethodDoc>();
067:
068: /* List of FieldDocImpl - Serializable fields.
069: * Singleton list if class defines Serializable fields explicitly.
070: * Otherwise, list of default serializable fields.
071: * 0 length list for Externalizable.
072: */
073: private final ListBuffer<FieldDocImpl> fields = new ListBuffer<FieldDocImpl>();
074:
075: /* True if class specifies serializable fields explicitly.
076: * using special static member, serialPersistentFields.
077: */
078: private boolean definesSerializableFields = false;
079:
080: // Specially treated field/method names defined by Serialization.
081: private static final String SERIALIZABLE_FIELDS = "serialPersistentFields";
082: private static final String READOBJECT = "readObject";
083: private static final String WRITEOBJECT = "writeObject";
084: private static final String READRESOLVE = "readResolve";
085: private static final String WRITEREPLACE = "writeReplace";
086: private static final String READOBJECTNODATA = "readObjectNoData";
087:
088: /**
089: * Constructor.
090: *
091: * Catalog Serializable fields for Serializable class.
092: * Catalog serialization methods for Serializable and
093: * Externalizable classes.
094: */
095: SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd) {
096: if (cd.isExternalizable()) {
097: /* look up required public accessible methods,
098: * writeExternal and readExternal.
099: */
100: String[] readExternalParamArr = { "java.io.ObjectInput" };
101: String[] writeExternalParamArr = { "java.io.ObjectOutput" };
102: MethodDoc md = cd.findMethod("readExternal",
103: readExternalParamArr);
104: if (md != null) {
105: methods.append(md);
106: }
107: md = cd.findMethod("writeExternal", writeExternalParamArr);
108: if (md != null) {
109: methods.append(md);
110: Tag tag[] = md.tags("serialData");
111: }
112: // } else { // isSerializable() //### ???
113: } else if (cd.isSerializable()) {
114:
115: VarSymbol dsf = getDefinedSerializableFields(def);
116: if (dsf != null) {
117:
118: /* Define serializable fields with array of ObjectStreamField.
119: * Each ObjectStreamField should be documented by a
120: * serialField tag.
121: */
122: definesSerializableFields = true;
123: //### No modifier filtering applied here.
124: FieldDocImpl dsfDoc = env.getFieldDoc(dsf);
125: fields.append(dsfDoc);
126: mapSerialFieldTagImplsToFieldDocImpls(dsfDoc, env, def);
127: } else {
128:
129: /* Calculate default Serializable fields as all
130: * non-transient, non-static fields.
131: * Fields should be documented by serial tag.
132: */
133: computeDefaultSerializableFields(env, def, cd);
134: }
135:
136: /* Check for optional customized readObject, writeObject,
137: * readResolve and writeReplace, which can all contain
138: * the serialData tag. */
139: addMethodIfExist(env, def, READOBJECT);
140: addMethodIfExist(env, def, WRITEOBJECT);
141: addMethodIfExist(env, def, READRESOLVE);
142: addMethodIfExist(env, def, WRITEREPLACE);
143: addMethodIfExist(env, def, READOBJECTNODATA);
144: }
145: }
146:
147: /*
148: * Check for explicit Serializable fields.
149: * Check for a private static array of ObjectStreamField with
150: * name SERIALIZABLE_FIELDS.
151: */
152: private VarSymbol getDefinedSerializableFields(ClassSymbol def) {
153: Name.Table names = def.name.table;
154:
155: /* SERIALIZABLE_FIELDS can be private,
156: * so must lookup by ClassSymbol, not by ClassDocImpl.
157: */
158: for (Scope.Entry e = def.members().lookup(
159: names.fromString(SERIALIZABLE_FIELDS)); e.scope != null; e = e
160: .next()) {
161: if (e.sym.kind == Kinds.VAR) {
162: VarSymbol f = (VarSymbol) e.sym;
163: if ((f.flags() & Flags.STATIC) != 0
164: && (f.flags() & Flags.PRIVATE) != 0) {
165: return f;
166: }
167: }
168: }
169: return null;
170: }
171:
172: /*
173: * Compute default Serializable fields from all members of ClassSymbol.
174: *
175: * Since the fields of ClassDocImpl might not contain private or
176: * package accessible fields, must walk over all members of ClassSymbol.
177: */
178: private void computeDefaultSerializableFields(DocEnv env,
179: ClassSymbol def, ClassDocImpl cd) {
180: for (Scope.Entry e = def.members().elems; e != null; e = e.sibling) {
181: if (e.sym != null && e.sym.kind == Kinds.VAR) {
182: VarSymbol f = (VarSymbol) e.sym;
183: if ((f.flags() & Flags.STATIC) == 0
184: && (f.flags() & Flags.TRANSIENT) == 0) {
185: //### No modifier filtering applied here.
186: FieldDocImpl fd = env.getFieldDoc(f);
187: //### Add to beginning.
188: //### Preserve order used by old 'javadoc'.
189: fields.prepend(fd);
190: }
191: }
192: }
193: }
194:
195: /*
196: * Catalog Serializable method if it exists in current ClassSymbol.
197: * Do not look for method in superclasses.
198: *
199: * Serialization requires these methods to be non-static.
200: *
201: * @param method should be an unqualified Serializable method
202: * name either READOBJECT, WRITEOBJECT, READRESOLVE
203: * or WRITEREPLACE.
204: * @param visibility the visibility flag for the given method.
205: */
206: private void addMethodIfExist(DocEnv env, ClassSymbol def,
207: String methodName) {
208: Name.Table names = def.name.table;
209:
210: for (Scope.Entry e = def.members().lookup(
211: names.fromString(methodName)); e.scope != null; e = e
212: .next()) {
213: if (e.sym.kind == Kinds.MTH) {
214: MethodSymbol md = (MethodSymbol) e.sym;
215: if ((md.flags() & Flags.STATIC) == 0) {
216: /*
217: * WARNING: not robust if unqualifiedMethodName is overloaded
218: * method. Signature checking could make more robust.
219: * READOBJECT takes a single parameter, java.io.ObjectInputStream.
220: * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream.
221: */
222: methods.append(env.getMethodDoc(md));
223: }
224: }
225: }
226: }
227:
228: /*
229: * Associate serialField tag fieldName with FieldDocImpl member.
230: * Note: A serialField tag does not have to map an existing field
231: * of a class.
232: */
233: private void mapSerialFieldTagImplsToFieldDocImpls(
234: FieldDocImpl spfDoc, DocEnv env, ClassSymbol def) {
235: Name.Table names = def.name.table;
236:
237: SerialFieldTag[] sfTag = spfDoc.serialFieldTags();
238: for (int i = 0; i < sfTag.length; i++) {
239: Name fieldName = names.fromString(sfTag[i].fieldName());
240:
241: // Look for a FieldDocImpl that is documented by serialFieldTagImpl.
242: for (Scope.Entry e = def.members().lookup(fieldName); e.scope != null; e = e
243: .next()) {
244: if (e.sym.kind == Kinds.VAR) {
245: VarSymbol f = (VarSymbol) e.sym;
246: FieldDocImpl fdi = env.getFieldDoc(f);
247: ((SerialFieldTagImpl) (sfTag[i]))
248: .mapToFieldDocImpl(fdi);
249: break;
250: }
251: }
252: }
253: }
254:
255: /**
256: * Return serializable fields in class. <p>
257: *
258: * Returns either a list of default fields documented by serial tag comment or
259: * javadoc comment<p>
260: * Or Returns a single FieldDocImpl for serialPersistentField. There is a
261: * serialField tag for each serializable field.<p>
262: *
263: * @return an array of FieldDocImpl for representing the visible
264: * fields in this class.
265: */
266: FieldDoc[] fields() {
267: return (FieldDoc[]) fields.toArray(new FieldDocImpl[fields
268: .length()]);
269: }
270:
271: /**
272: * Return serialization methods in class.
273: *
274: * @return an array of MethodDocImpl for serialization methods in this class.
275: */
276: MethodDoc[] methods() {
277: return (MethodDoc[]) methods.toArray(new MethodDoc[methods
278: .length()]);
279: }
280:
281: /**
282: * Returns true if Serializable fields are defined explicitly using
283: * member, serialPersistentFields.
284: *
285: * @see #fields()
286: */
287: boolean definesSerializableFields() {
288: return definesSerializableFields;
289: }
290: }
|