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 import com.sun.tools.javac.code.*;
30 import com.sun.tools.javac.code.Symbol.ClassSymbol;
31 import com.sun.tools.javac.code.Symbol.MethodSymbol;
32 import com.sun.tools.javac.code.Symbol.VarSymbol;
33 import com.sun.tools.javac.util.*;
34 
35 import static com.sun.tools.javac.code.Kinds.Kind.*;
36 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
37 
38 /**
39  * The serialized form is the specification of a class' serialization
40  * state. <p>
41  *
42  * It consists of the following information:<p>
43  *
44  * <pre>
45  * 1. Whether class is Serializable or Externalizable.
46  * 2. Javadoc for serialization methods.
47  *    a. For Serializable, the optional readObject, writeObject,
48  *       readResolve and writeReplace.
49  *       serialData tag describes, in prose, the sequence and type
50  *       of optional data written by writeObject.
51  *    b. For Externalizable, writeExternal and readExternal.
52  *       serialData tag describes, in prose, the sequence and type
53  *       of optional data written by writeExternal.
54  * 3. Javadoc for serialization data layout.
55  *    a. For Serializable, the name,type and description
56  *       of each Serializable fields.
57  *    b. For Externalizable, data layout is described by 2(b).
58  * </pre>
59  *
60  *  <p><b>This is NOT part of any supported API.
61  *  If you write code that depends on this, you do so at your own risk.
62  *  This code and its internal interfaces are subject to change or
63  *  deletion without notice.</b>
64  *
65  * @since 1.2
66  * @author Joe Fialli
67  * @author Neal Gafter (rewrite but not too proud)
68  */
69 @Deprecated(since="9", forRemoval=true)
70 @SuppressWarnings("removal")
71 class SerializedForm {
72     ListBuffer<MethodDoc> methods = new ListBuffer<>();
73 
74     /* List of FieldDocImpl - Serializable fields.
75      * Singleton list if class defines Serializable fields explicitly.
76      * Otherwise, list of default serializable fields.
77      * 0 length list for Externalizable.
78      */
79     private final ListBuffer<FieldDocImpl> fields = new ListBuffer<>();
80 
81     /* True if class specifies serializable fields explicitly.
82      * using special static member, serialPersistentFields.
83      */
84     private boolean definesSerializableFields = false;
85 
86     // Specially treated field/method names defined by Serialization.
87     private static final String SERIALIZABLE_FIELDS = "serialPersistentFields";
88     private static final String READOBJECT  = "readObject";
89     private static final String WRITEOBJECT = "writeObject";
90     private static final String READRESOLVE  = "readResolve";
91     private static final String WRITEREPLACE = "writeReplace";
92     private static final String READOBJECTNODATA = "readObjectNoData";
93 
94     /**
95      * Constructor.
96      *
97      * Catalog Serializable fields for Serializable class.
98      * Catalog serialization methods for Serializable and
99      * Externalizable classes.
100      */
SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd)101     SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd) {
102         if (cd.isExternalizable()) {
103             /* look up required public accessible methods,
104              *   writeExternal and readExternal.
105              */
106             String[] readExternalParamArr = { "java.io.ObjectInput" };
107             String[] writeExternalParamArr = { "java.io.ObjectOutput" };
108             MethodDoc md = cd.findMethod("readExternal", readExternalParamArr);
109             if (md != null) {
110                 methods.append(md);
111             }
112             md = cd.findMethod("writeExternal", writeExternalParamArr);
113             if (md != null) {
114                 methods.append(md);
115                 Tag tag[] = md.tags("serialData");
116             }
117         // } else { // isSerializable() //### ???
118         } else if (cd.isSerializable()) {
119 
120             VarSymbol dsf = getDefinedSerializableFields(def);
121             if (dsf != null) {
122 
123                 /* Define serializable fields with array of ObjectStreamField.
124                  * Each ObjectStreamField should be documented by a
125                  * serialField tag.
126                  */
127                 definesSerializableFields = true;
128                 //### No modifier filtering applied here.
129                 FieldDocImpl dsfDoc = env.getFieldDoc(dsf);
130                 fields.append(dsfDoc);
131                 mapSerialFieldTagImplsToFieldDocImpls(dsfDoc, env, def);
132             } else {
133 
134                 /* Calculate default Serializable fields as all
135                  * non-transient, non-static fields.
136                  * Fields should be documented by serial tag.
137                  */
138                 computeDefaultSerializableFields(env, def, cd);
139             }
140 
141            /* Check for optional customized readObject, writeObject,
142             * readResolve and writeReplace, which can all contain
143             * the serialData tag.        */
144             addMethodIfExist(env, def, READOBJECT);
145             addMethodIfExist(env, def, WRITEOBJECT);
146             addMethodIfExist(env, def, READRESOLVE);
147             addMethodIfExist(env, def, WRITEREPLACE);
148             addMethodIfExist(env, def, READOBJECTNODATA);
149         }
150     }
151 
152     /*
153      * Check for explicit Serializable fields.
154      * Check for a private static array of ObjectStreamField with
155      * name SERIALIZABLE_FIELDS.
156      */
getDefinedSerializableFields(ClassSymbol def)157     private VarSymbol getDefinedSerializableFields(ClassSymbol def) {
158         Names names = def.name.table.names;
159 
160         /* SERIALIZABLE_FIELDS can be private,
161          * so must lookup by ClassSymbol, not by ClassDocImpl.
162          */
163         for (Symbol sym : def.members().getSymbolsByName(names.fromString(SERIALIZABLE_FIELDS))) {
164             if (sym.kind == VAR) {
165                 VarSymbol f = (VarSymbol)sym;
166                 if ((f.flags() & Flags.STATIC) != 0 &&
167                     (f.flags() & Flags.PRIVATE) != 0) {
168                     return f;
169                 }
170             }
171         }
172         return null;
173     }
174 
175     /*
176      * Compute default Serializable fields from all members of ClassSymbol.
177      *
178      * Since the fields of ClassDocImpl might not contain private or
179      * package accessible fields, must walk over all members of ClassSymbol.
180      */
computeDefaultSerializableFields(DocEnv env, ClassSymbol def, ClassDocImpl cd)181     private void computeDefaultSerializableFields(DocEnv env,
182                                                   ClassSymbol def,
183                                                   ClassDocImpl cd) {
184         for (Symbol sym : def.members().getSymbols(NON_RECURSIVE)) {
185             if (sym != null && sym.kind == VAR) {
186                 VarSymbol f = (VarSymbol)sym;
187                 if ((f.flags() & Flags.STATIC) == 0 &&
188                     (f.flags() & Flags.TRANSIENT) == 0) {
189                     //### No modifier filtering applied here.
190                     FieldDocImpl fd = env.getFieldDoc(f);
191                     //### Add to beginning.
192                     //### Preserve order used by old 'javadoc'.
193                     fields.prepend(fd);
194                 }
195             }
196         }
197     }
198 
199     /*
200      * Catalog Serializable method if it exists in current ClassSymbol.
201      * Do not look for method in superclasses.
202      *
203      * Serialization requires these methods to be non-static.
204      *
205      * @param method should be an unqualified Serializable method
206      *               name either READOBJECT, WRITEOBJECT, READRESOLVE
207      *               or WRITEREPLACE.
208      * @param visibility the visibility flag for the given method.
209      */
addMethodIfExist(DocEnv env, ClassSymbol def, String methodName)210     private void addMethodIfExist(DocEnv env, ClassSymbol def, String methodName) {
211         Names names = def.name.table.names;
212 
213         for (Symbol sym : def.members().getSymbolsByName(names.fromString(methodName))) {
214             if (sym.kind == MTH) {
215                 MethodSymbol md = (MethodSymbol)sym;
216                 if ((md.flags() & Flags.STATIC) == 0) {
217                     /*
218                      * WARNING: not robust if unqualifiedMethodName is overloaded
219                      *          method. Signature checking could make more robust.
220                      * READOBJECT takes a single parameter, java.io.ObjectInputStream.
221                      * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream.
222                      */
223                     methods.append(env.getMethodDoc(md));
224                 }
225             }
226         }
227     }
228 
229     /*
230      * Associate serialField tag fieldName with FieldDocImpl member.
231      * Note: A serialField tag does not have to map an existing field
232      *       of a class.
233      */
mapSerialFieldTagImplsToFieldDocImpls(FieldDocImpl spfDoc, DocEnv env, ClassSymbol def)234     private void mapSerialFieldTagImplsToFieldDocImpls(FieldDocImpl spfDoc,
235                                                        DocEnv env,
236                                                        ClassSymbol def) {
237         Names names = def.name.table.names;
238         for (SerialFieldTag tag : spfDoc.serialFieldTags()) {
239             if (tag.fieldName() == null || tag.fieldType() == null) // ignore malformed @serialField tags
240                 continue;
241 
242             Name fieldName = names.fromString(tag.fieldName());
243 
244             // Look for a FieldDocImpl that is documented by serialFieldTagImpl.
245             for (Symbol sym : def.members().getSymbolsByName(fieldName)) {
246                 if (sym.kind == VAR) {
247                     VarSymbol f = (VarSymbol) sym;
248                     FieldDocImpl fdi = env.getFieldDoc(f);
249                     ((SerialFieldTagImpl) (tag)).mapToFieldDocImpl(fdi);
250                     break;
251                 }
252             }
253         }
254     }
255 
256     /**
257      * Return serializable fields in class. <p>
258      *
259      * Returns either a list of default fields documented by serial tag comment or
260      *         javadoc comment<p>
261      * Or Returns a single FieldDocImpl for serialPersistentField. There is a
262      *         serialField tag for each serializable field.<p>
263      *
264      * @return an array of FieldDocImpl for representing the visible
265      *         fields in this class.
266      */
fields()267     FieldDoc[] fields() {
268         return (FieldDoc[])fields.toArray(new FieldDocImpl[fields.length()]);
269     }
270 
271     /**
272      * Return serialization methods in class.
273      *
274      * @return an array of MethodDocImpl for serialization methods in this class.
275      */
methods()276     MethodDoc[] methods() {
277         return methods.toArray(new MethodDoc[methods.length()]);
278     }
279 
280     /**
281      * Returns true if Serializable fields are defined explicitly using
282      * member, serialPersistentFields.
283      *
284      * @see #fields()
285      */
definesSerializableFields()286     boolean definesSerializableFields() {
287         return definesSerializableFields;
288     }
289 }
290