1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/javadoc/SerializedForm.java Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,282 @@ 1.4 +/* 1.5 + * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Sun designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Sun in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.26 + * have any questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.javadoc; 1.30 + 1.31 +import com.sun.javadoc.*; 1.32 + 1.33 +import com.sun.tools.javac.code.Flags; 1.34 +import com.sun.tools.javac.code.Kinds; 1.35 +import com.sun.tools.javac.code.Scope; 1.36 +import com.sun.tools.javac.code.Symbol.VarSymbol; 1.37 +import com.sun.tools.javac.code.Symbol.ClassSymbol; 1.38 +import com.sun.tools.javac.code.Symbol.MethodSymbol; 1.39 +import com.sun.tools.javac.util.Name; 1.40 +import com.sun.tools.javac.util.ListBuffer; 1.41 + 1.42 +/** 1.43 + * The serialized form is the specification of a class' serialization 1.44 + * state. <p> 1.45 + * 1.46 + * It consists of the following information:<p> 1.47 + * 1.48 + * <pre> 1.49 + * 1. Whether class is Serializable or Externalizable. 1.50 + * 2. Javadoc for serialization methods. 1.51 + * a. For Serializable, the optional readObject, writeObject, 1.52 + * readResolve and writeReplace. 1.53 + * serialData tag describes, in prose, the sequence and type 1.54 + * of optional data written by writeObject. 1.55 + * b. For Externalizable, writeExternal and readExternal. 1.56 + * serialData tag describes, in prose, the sequence and type 1.57 + * of optional data written by writeExternal. 1.58 + * 3. Javadoc for serialization data layout. 1.59 + * a. For Serializable, the name,type and description 1.60 + * of each Serializable fields. 1.61 + * b. For Externalizable, data layout is described by 2(b). 1.62 + * </pre> 1.63 + * 1.64 + * @since 1.2 1.65 + * @author Joe Fialli 1.66 + * @author Neal Gafter (rewrite but not too proud) 1.67 + */ 1.68 +class SerializedForm { 1.69 + ListBuffer<MethodDoc> methods = new ListBuffer<MethodDoc>(); 1.70 + 1.71 + /* List of FieldDocImpl - Serializable fields. 1.72 + * Singleton list if class defines Serializable fields explicitly. 1.73 + * Otherwise, list of default serializable fields. 1.74 + * 0 length list for Externalizable. 1.75 + */ 1.76 + private final ListBuffer<FieldDocImpl> fields = new ListBuffer<FieldDocImpl>(); 1.77 + 1.78 + /* True if class specifies serializable fields explicitly. 1.79 + * using special static member, serialPersistentFields. 1.80 + */ 1.81 + private boolean definesSerializableFields = false; 1.82 + 1.83 + // Specially treated field/method names defined by Serialization. 1.84 + private static final String SERIALIZABLE_FIELDS = "serialPersistentFields"; 1.85 + private static final String READOBJECT = "readObject"; 1.86 + private static final String WRITEOBJECT = "writeObject"; 1.87 + private static final String READRESOLVE = "readResolve"; 1.88 + private static final String WRITEREPLACE = "writeReplace"; 1.89 + private static final String READOBJECTNODATA = "readObjectNoData"; 1.90 + 1.91 + /** 1.92 + * Constructor. 1.93 + * 1.94 + * Catalog Serializable fields for Serializable class. 1.95 + * Catalog serialization methods for Serializable and 1.96 + * Externalizable classes. 1.97 + */ 1.98 + SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd) { 1.99 + if (cd.isExternalizable()) { 1.100 + /* look up required public accessible methods, 1.101 + * writeExternal and readExternal. 1.102 + */ 1.103 + String[] readExternalParamArr = { "java.io.ObjectInput" }; 1.104 + String[] writeExternalParamArr = { "java.io.ObjectOutput" }; 1.105 + MethodDoc md = cd.findMethod("readExternal", readExternalParamArr); 1.106 + if (md != null) { 1.107 + methods.append(md); 1.108 + } 1.109 + md = cd.findMethod("writeExternal", writeExternalParamArr); 1.110 + if (md != null) { 1.111 + methods.append(md); 1.112 + Tag tag[] = md.tags("serialData"); 1.113 + } 1.114 + // } else { // isSerializable() //### ??? 1.115 + } else if (cd.isSerializable()) { 1.116 + 1.117 + VarSymbol dsf = getDefinedSerializableFields(def); 1.118 + if (dsf != null) { 1.119 + 1.120 + /* Define serializable fields with array of ObjectStreamField. 1.121 + * Each ObjectStreamField should be documented by a 1.122 + * serialField tag. 1.123 + */ 1.124 + definesSerializableFields = true; 1.125 + //### No modifier filtering applied here. 1.126 + FieldDocImpl dsfDoc = env.getFieldDoc(dsf); 1.127 + fields.append(dsfDoc); 1.128 + mapSerialFieldTagImplsToFieldDocImpls(dsfDoc, env, def); 1.129 + } else { 1.130 + 1.131 + /* Calculate default Serializable fields as all 1.132 + * non-transient, non-static fields. 1.133 + * Fields should be documented by serial tag. 1.134 + */ 1.135 + computeDefaultSerializableFields(env, def, cd); 1.136 + } 1.137 + 1.138 + /* Check for optional customized readObject, writeObject, 1.139 + * readResolve and writeReplace, which can all contain 1.140 + * the serialData tag. */ 1.141 + addMethodIfExist(env, def, READOBJECT); 1.142 + addMethodIfExist(env, def, WRITEOBJECT); 1.143 + addMethodIfExist(env, def, READRESOLVE); 1.144 + addMethodIfExist(env, def, WRITEREPLACE); 1.145 + addMethodIfExist(env, def, READOBJECTNODATA); 1.146 + } 1.147 + } 1.148 + 1.149 + /* 1.150 + * Check for explicit Serializable fields. 1.151 + * Check for a private static array of ObjectStreamField with 1.152 + * name SERIALIZABLE_FIELDS. 1.153 + */ 1.154 + private VarSymbol getDefinedSerializableFields(ClassSymbol def) { 1.155 + Name.Table names = def.name.table; 1.156 + 1.157 + /* SERIALIZABLE_FIELDS can be private, 1.158 + * so must lookup by ClassSymbol, not by ClassDocImpl. 1.159 + */ 1.160 + for (Scope.Entry e = def.members().lookup(names.fromString(SERIALIZABLE_FIELDS)); e.scope != null; e = e.next()) { 1.161 + if (e.sym.kind == Kinds.VAR) { 1.162 + VarSymbol f = (VarSymbol)e.sym; 1.163 + if ((f.flags() & Flags.STATIC) != 0 && 1.164 + (f.flags() & Flags.PRIVATE) != 0) { 1.165 + return f; 1.166 + } 1.167 + } 1.168 + } 1.169 + return null; 1.170 + } 1.171 + 1.172 + /* 1.173 + * Compute default Serializable fields from all members of ClassSymbol. 1.174 + * 1.175 + * Since the fields of ClassDocImpl might not contain private or 1.176 + * package accessible fields, must walk over all members of ClassSymbol. 1.177 + */ 1.178 + private void computeDefaultSerializableFields(DocEnv env, 1.179 + ClassSymbol def, 1.180 + ClassDocImpl cd) { 1.181 + for (Scope.Entry e = def.members().elems; e != null; e = e.sibling) { 1.182 + if (e.sym != null && e.sym.kind == Kinds.VAR) { 1.183 + VarSymbol f = (VarSymbol)e.sym; 1.184 + if ((f.flags() & Flags.STATIC) == 0 && 1.185 + (f.flags() & Flags.TRANSIENT) == 0) { 1.186 + //### No modifier filtering applied here. 1.187 + FieldDocImpl fd = env.getFieldDoc(f); 1.188 + //### Add to beginning. 1.189 + //### Preserve order used by old 'javadoc'. 1.190 + fields.prepend(fd); 1.191 + } 1.192 + } 1.193 + } 1.194 + } 1.195 + 1.196 + /* 1.197 + * Catalog Serializable method if it exists in current ClassSymbol. 1.198 + * Do not look for method in superclasses. 1.199 + * 1.200 + * Serialization requires these methods to be non-static. 1.201 + * 1.202 + * @param method should be an unqualified Serializable method 1.203 + * name either READOBJECT, WRITEOBJECT, READRESOLVE 1.204 + * or WRITEREPLACE. 1.205 + * @param visibility the visibility flag for the given method. 1.206 + */ 1.207 + private void addMethodIfExist(DocEnv env, ClassSymbol def, String methodName) { 1.208 + Name.Table names = def.name.table; 1.209 + 1.210 + for (Scope.Entry e = def.members().lookup(names.fromString(methodName)); e.scope != null; e = e.next()) { 1.211 + if (e.sym.kind == Kinds.MTH) { 1.212 + MethodSymbol md = (MethodSymbol)e.sym; 1.213 + if ((md.flags() & Flags.STATIC) == 0) { 1.214 + /* 1.215 + * WARNING: not robust if unqualifiedMethodName is overloaded 1.216 + * method. Signature checking could make more robust. 1.217 + * READOBJECT takes a single parameter, java.io.ObjectInputStream. 1.218 + * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream. 1.219 + */ 1.220 + methods.append(env.getMethodDoc(md)); 1.221 + } 1.222 + } 1.223 + } 1.224 + } 1.225 + 1.226 + /* 1.227 + * Associate serialField tag fieldName with FieldDocImpl member. 1.228 + * Note: A serialField tag does not have to map an existing field 1.229 + * of a class. 1.230 + */ 1.231 + private void mapSerialFieldTagImplsToFieldDocImpls(FieldDocImpl spfDoc, 1.232 + DocEnv env, 1.233 + ClassSymbol def) { 1.234 + Name.Table names = def.name.table; 1.235 + 1.236 + SerialFieldTag[] sfTag = spfDoc.serialFieldTags(); 1.237 + for (int i = 0; i < sfTag.length; i++) { 1.238 + Name fieldName = names.fromString(sfTag[i].fieldName()); 1.239 + 1.240 + // Look for a FieldDocImpl that is documented by serialFieldTagImpl. 1.241 + for (Scope.Entry e = def.members().lookup(fieldName); e.scope != null; e = e.next()) { 1.242 + if (e.sym.kind == Kinds.VAR) { 1.243 + VarSymbol f = (VarSymbol)e.sym; 1.244 + FieldDocImpl fdi = env.getFieldDoc(f); 1.245 + ((SerialFieldTagImpl)(sfTag[i])).mapToFieldDocImpl(fdi); 1.246 + break; 1.247 + } 1.248 + } 1.249 + } 1.250 + } 1.251 + 1.252 + /** 1.253 + * Return serializable fields in class. <p> 1.254 + * 1.255 + * Returns either a list of default fields documented by serial tag comment or 1.256 + * javadoc comment<p> 1.257 + * Or Returns a single FieldDocImpl for serialPersistentField. There is a 1.258 + * serialField tag for each serializable field.<p> 1.259 + * 1.260 + * @return an array of FieldDocImpl for representing the visible 1.261 + * fields in this class. 1.262 + */ 1.263 + FieldDoc[] fields() { 1.264 + return (FieldDoc[])fields.toArray(new FieldDocImpl[fields.length()]); 1.265 + } 1.266 + 1.267 + /** 1.268 + * Return serialization methods in class. 1.269 + * 1.270 + * @return an array of MethodDocImpl for serialization methods in this class. 1.271 + */ 1.272 + MethodDoc[] methods() { 1.273 + return (MethodDoc[])methods.toArray(new MethodDoc[methods.length()]); 1.274 + } 1.275 + 1.276 + /** 1.277 + * Returns true if Serializable fields are defined explicitly using 1.278 + * member, serialPersistentFields. 1.279 + * 1.280 + * @see #fields() 1.281 + */ 1.282 + boolean definesSerializableFields() { 1.283 + return definesSerializableFields; 1.284 + } 1.285 +}