1/*
2 * Copyright (c) 1998, 2014, 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
26package com.sun.tools.javadoc.main;
27
28import com.sun.javadoc.*;
29import com.sun.tools.javac.code.*;
30import com.sun.tools.javac.code.Symbol.ClassSymbol;
31import com.sun.tools.javac.code.Symbol.MethodSymbol;
32import com.sun.tools.javac.code.Symbol.VarSymbol;
33import com.sun.tools.javac.util.*;
34
35import static com.sun.tools.javac.code.Kinds.Kind.*;
36import 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
70class SerializedForm {
71    ListBuffer<MethodDoc> methods = new ListBuffer<>();
72
73    /* List of FieldDocImpl - Serializable fields.
74     * Singleton list if class defines Serializable fields explicitly.
75     * Otherwise, list of default serializable fields.
76     * 0 length list for Externalizable.
77     */
78    private final ListBuffer<FieldDocImpl> fields = new ListBuffer<>();
79
80    /* True if class specifies serializable fields explicitly.
81     * using special static member, serialPersistentFields.
82     */
83    private boolean definesSerializableFields = false;
84
85    // Specially treated field/method names defined by Serialization.
86    private static final String SERIALIZABLE_FIELDS = "serialPersistentFields";
87    private static final String READOBJECT  = "readObject";
88    private static final String WRITEOBJECT = "writeObject";
89    private static final String READRESOLVE  = "readResolve";
90    private static final String WRITEREPLACE = "writeReplace";
91    private static final String READOBJECTNODATA = "readObjectNoData";
92
93    /**
94     * Constructor.
95     *
96     * Catalog Serializable fields for Serializable class.
97     * Catalog serialization methods for Serializable and
98     * Externalizable classes.
99     */
100    SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd) {
101        if (cd.isExternalizable()) {
102            /* look up required public accessible methods,
103             *   writeExternal and readExternal.
104             */
105            String[] readExternalParamArr = { "java.io.ObjectInput" };
106            String[] writeExternalParamArr = { "java.io.ObjectOutput" };
107            MethodDoc md = cd.findMethod("readExternal", readExternalParamArr);
108            if (md != null) {
109                methods.append(md);
110            }
111            md = cd.findMethod("writeExternal", writeExternalParamArr);
112            if (md != null) {
113                methods.append(md);
114                Tag tag[] = md.tags("serialData");
115            }
116        // } else { // isSerializable() //### ???
117        } else if (cd.isSerializable()) {
118
119            VarSymbol dsf = getDefinedSerializableFields(def);
120            if (dsf != null) {
121
122                /* Define serializable fields with array of ObjectStreamField.
123                 * Each ObjectStreamField should be documented by a
124                 * serialField tag.
125                 */
126                definesSerializableFields = true;
127                //### No modifier filtering applied here.
128                FieldDocImpl dsfDoc = env.getFieldDoc(dsf);
129                fields.append(dsfDoc);
130                mapSerialFieldTagImplsToFieldDocImpls(dsfDoc, env, def);
131            } else {
132
133                /* Calculate default Serializable fields as all
134                 * non-transient, non-static fields.
135                 * Fields should be documented by serial tag.
136                 */
137                computeDefaultSerializableFields(env, def, cd);
138            }
139
140           /* Check for optional customized readObject, writeObject,
141            * readResolve and writeReplace, which can all contain
142            * the serialData tag.        */
143            addMethodIfExist(env, def, READOBJECT);
144            addMethodIfExist(env, def, WRITEOBJECT);
145            addMethodIfExist(env, def, READRESOLVE);
146            addMethodIfExist(env, def, WRITEREPLACE);
147            addMethodIfExist(env, def, READOBJECTNODATA);
148        }
149    }
150
151    /*
152     * Check for explicit Serializable fields.
153     * Check for a private static array of ObjectStreamField with
154     * name SERIALIZABLE_FIELDS.
155     */
156    private VarSymbol getDefinedSerializableFields(ClassSymbol def) {
157        Names names = def.name.table.names;
158
159        /* SERIALIZABLE_FIELDS can be private,
160         * so must lookup by ClassSymbol, not by ClassDocImpl.
161         */
162        for (Symbol sym : def.members().getSymbolsByName(names.fromString(SERIALIZABLE_FIELDS))) {
163            if (sym.kind == VAR) {
164                VarSymbol f = (VarSymbol)sym;
165                if ((f.flags() & Flags.STATIC) != 0 &&
166                    (f.flags() & Flags.PRIVATE) != 0) {
167                    return f;
168                }
169            }
170        }
171        return null;
172    }
173
174    /*
175     * Compute default Serializable fields from all members of ClassSymbol.
176     *
177     * Since the fields of ClassDocImpl might not contain private or
178     * package accessible fields, must walk over all members of ClassSymbol.
179     */
180    private void computeDefaultSerializableFields(DocEnv env,
181                                                  ClassSymbol def,
182                                                  ClassDocImpl cd) {
183        for (Symbol sym : def.members().getSymbols(NON_RECURSIVE)) {
184            if (sym != null && sym.kind == VAR) {
185                VarSymbol f = (VarSymbol)sym;
186                if ((f.flags() & Flags.STATIC) == 0 &&
187                    (f.flags() & Flags.TRANSIENT) == 0) {
188                    //### No modifier filtering applied here.
189                    FieldDocImpl fd = env.getFieldDoc(f);
190                    //### Add to beginning.
191                    //### Preserve order used by old 'javadoc'.
192                    fields.prepend(fd);
193                }
194            }
195        }
196    }
197
198    /*
199     * Catalog Serializable method if it exists in current ClassSymbol.
200     * Do not look for method in superclasses.
201     *
202     * Serialization requires these methods to be non-static.
203     *
204     * @param method should be an unqualified Serializable method
205     *               name either READOBJECT, WRITEOBJECT, READRESOLVE
206     *               or WRITEREPLACE.
207     * @param visibility the visibility flag for the given method.
208     */
209    private void addMethodIfExist(DocEnv env, ClassSymbol def, String methodName) {
210        Names names = def.name.table.names;
211
212        for (Symbol sym : def.members().getSymbolsByName(names.fromString(methodName))) {
213            if (sym.kind == MTH) {
214                MethodSymbol md = (MethodSymbol)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(FieldDocImpl spfDoc,
234                                                       DocEnv env,
235                                                       ClassSymbol def) {
236        Names names = def.name.table.names;
237        for (SerialFieldTag tag : spfDoc.serialFieldTags()) {
238            if (tag.fieldName() == null || tag.fieldType() == null) // ignore malformed @serialField tags
239                continue;
240
241            Name fieldName = names.fromString(tag.fieldName());
242
243            // Look for a FieldDocImpl that is documented by serialFieldTagImpl.
244            for (Symbol sym : def.members().getSymbolsByName(fieldName)) {
245                if (sym.kind == VAR) {
246                    VarSymbol f = (VarSymbol) sym;
247                    FieldDocImpl fdi = env.getFieldDoc(f);
248                    ((SerialFieldTagImpl) (tag)).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.length()]);
268    }
269
270    /**
271     * Return serialization methods in class.
272     *
273     * @return an array of MethodDocImpl for serialization methods in this class.
274     */
275    MethodDoc[] methods() {
276        return methods.toArray(new MethodDoc[methods.length()]);
277    }
278
279    /**
280     * Returns true if Serializable fields are defined explicitly using
281     * member, serialPersistentFields.
282     *
283     * @see #fields()
284     */
285    boolean definesSerializableFields() {
286        return definesSerializableFields;
287    }
288}
289