langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/SerializedForm.java
changeset 37938 42baa89d2156
parent 37858 7c04fcb12bd4
child 37939 3eb8c2a89b77
equal deleted inserted replaced
37858:7c04fcb12bd4 37938:42baa89d2156
     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 
       
    26 package com.sun.tools.javadoc;
       
    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 class SerializedForm {
       
    70     ListBuffer<MethodDoc> methods = new ListBuffer<>();
       
    71 
       
    72     /* List of FieldDocImpl - Serializable fields.
       
    73      * Singleton list if class defines Serializable fields explicitly.
       
    74      * Otherwise, list of default serializable fields.
       
    75      * 0 length list for Externalizable.
       
    76      */
       
    77     private final ListBuffer<FieldDocImpl> fields = new ListBuffer<>();
       
    78 
       
    79     /* True if class specifies serializable fields explicitly.
       
    80      * using special static member, serialPersistentFields.
       
    81      */
       
    82     private boolean definesSerializableFields = false;
       
    83 
       
    84     // Specially treated field/method names defined by Serialization.
       
    85     private static final String SERIALIZABLE_FIELDS = "serialPersistentFields";
       
    86     private static final String READOBJECT  = "readObject";
       
    87     private static final String WRITEOBJECT = "writeObject";
       
    88     private static final String READRESOLVE  = "readResolve";
       
    89     private static final String WRITEREPLACE = "writeReplace";
       
    90     private static final String READOBJECTNODATA = "readObjectNoData";
       
    91 
       
    92     /**
       
    93      * Constructor.
       
    94      *
       
    95      * Catalog Serializable fields for Serializable class.
       
    96      * Catalog serialization methods for Serializable and
       
    97      * Externalizable classes.
       
    98      */
       
    99     SerializedForm(DocEnv env, ClassSymbol def, ClassDocImpl cd) {
       
   100         if (cd.isExternalizable()) {
       
   101             /* look up required public accessible methods,
       
   102              *   writeExternal and readExternal.
       
   103              */
       
   104             String[] readExternalParamArr = { "java.io.ObjectInput" };
       
   105             String[] writeExternalParamArr = { "java.io.ObjectOutput" };
       
   106             MethodDoc md = cd.findMethod("readExternal", readExternalParamArr);
       
   107             if (md != null) {
       
   108                 methods.append(md);
       
   109             }
       
   110             md = cd.findMethod("writeExternal", writeExternalParamArr);
       
   111             if (md != null) {
       
   112                 methods.append(md);
       
   113                 Tag tag[] = md.tags("serialData");
       
   114             }
       
   115         // } else { // isSerializable() //### ???
       
   116         } else if (cd.isSerializable()) {
       
   117 
       
   118             VarSymbol dsf = getDefinedSerializableFields(def);
       
   119             if (dsf != null) {
       
   120 
       
   121                 /* Define serializable fields with array of ObjectStreamField.
       
   122                  * Each ObjectStreamField should be documented by a
       
   123                  * serialField tag.
       
   124                  */
       
   125                 definesSerializableFields = true;
       
   126                 //### No modifier filtering applied here.
       
   127                 FieldDocImpl dsfDoc = env.getFieldDoc(dsf);
       
   128                 fields.append(dsfDoc);
       
   129                 mapSerialFieldTagImplsToFieldDocImpls(dsfDoc, env, def);
       
   130             } else {
       
   131 
       
   132                 /* Calculate default Serializable fields as all
       
   133                  * non-transient, non-static fields.
       
   134                  * Fields should be documented by serial tag.
       
   135                  */
       
   136                 computeDefaultSerializableFields(env, def, cd);
       
   137             }
       
   138 
       
   139            /* Check for optional customized readObject, writeObject,
       
   140             * readResolve and writeReplace, which can all contain
       
   141             * the serialData tag.        */
       
   142             addMethodIfExist(env, def, READOBJECT);
       
   143             addMethodIfExist(env, def, WRITEOBJECT);
       
   144             addMethodIfExist(env, def, READRESOLVE);
       
   145             addMethodIfExist(env, def, WRITEREPLACE);
       
   146             addMethodIfExist(env, def, READOBJECTNODATA);
       
   147         }
       
   148     }
       
   149 
       
   150     /*
       
   151      * Check for explicit Serializable fields.
       
   152      * Check for a private static array of ObjectStreamField with
       
   153      * name SERIALIZABLE_FIELDS.
       
   154      */
       
   155     private VarSymbol getDefinedSerializableFields(ClassSymbol def) {
       
   156         Names names = def.name.table.names;
       
   157 
       
   158         /* SERIALIZABLE_FIELDS can be private,
       
   159          * so must lookup by ClassSymbol, not by ClassDocImpl.
       
   160          */
       
   161         for (Symbol sym : def.members().getSymbolsByName(names.fromString(SERIALIZABLE_FIELDS))) {
       
   162             if (sym.kind == VAR) {
       
   163                 VarSymbol f = (VarSymbol)sym;
       
   164                 if ((f.flags() & Flags.STATIC) != 0 &&
       
   165                     (f.flags() & Flags.PRIVATE) != 0) {
       
   166                     return f;
       
   167                 }
       
   168             }
       
   169         }
       
   170         return null;
       
   171     }
       
   172 
       
   173     /*
       
   174      * Compute default Serializable fields from all members of ClassSymbol.
       
   175      *
       
   176      * Since the fields of ClassDocImpl might not contain private or
       
   177      * package accessible fields, must walk over all members of ClassSymbol.
       
   178      */
       
   179     private void computeDefaultSerializableFields(DocEnv env,
       
   180                                                   ClassSymbol def,
       
   181                                                   ClassDocImpl cd) {
       
   182         for (Symbol sym : def.members().getSymbols(NON_RECURSIVE)) {
       
   183             if (sym != null && sym.kind == VAR) {
       
   184                 VarSymbol f = (VarSymbol)sym;
       
   185                 if ((f.flags() & Flags.STATIC) == 0 &&
       
   186                     (f.flags() & Flags.TRANSIENT) == 0) {
       
   187                     //### No modifier filtering applied here.
       
   188                     FieldDocImpl fd = env.getFieldDoc(f);
       
   189                     //### Add to beginning.
       
   190                     //### Preserve order used by old 'javadoc'.
       
   191                     fields.prepend(fd);
       
   192                 }
       
   193             }
       
   194         }
       
   195     }
       
   196 
       
   197     /*
       
   198      * Catalog Serializable method if it exists in current ClassSymbol.
       
   199      * Do not look for method in superclasses.
       
   200      *
       
   201      * Serialization requires these methods to be non-static.
       
   202      *
       
   203      * @param method should be an unqualified Serializable method
       
   204      *               name either READOBJECT, WRITEOBJECT, READRESOLVE
       
   205      *               or WRITEREPLACE.
       
   206      * @param visibility the visibility flag for the given method.
       
   207      */
       
   208     private void addMethodIfExist(DocEnv env, ClassSymbol def, String methodName) {
       
   209         Names names = def.name.table.names;
       
   210 
       
   211         for (Symbol sym : def.members().getSymbolsByName(names.fromString(methodName))) {
       
   212             if (sym.kind == MTH) {
       
   213                 MethodSymbol md = (MethodSymbol)sym;
       
   214                 if ((md.flags() & Flags.STATIC) == 0) {
       
   215                     /*
       
   216                      * WARNING: not robust if unqualifiedMethodName is overloaded
       
   217                      *          method. Signature checking could make more robust.
       
   218                      * READOBJECT takes a single parameter, java.io.ObjectInputStream.
       
   219                      * WRITEOBJECT takes a single parameter, java.io.ObjectOutputStream.
       
   220                      */
       
   221                     methods.append(env.getMethodDoc(md));
       
   222                 }
       
   223             }
       
   224         }
       
   225     }
       
   226 
       
   227     /*
       
   228      * Associate serialField tag fieldName with FieldDocImpl member.
       
   229      * Note: A serialField tag does not have to map an existing field
       
   230      *       of a class.
       
   231      */
       
   232     private void mapSerialFieldTagImplsToFieldDocImpls(FieldDocImpl spfDoc,
       
   233                                                        DocEnv env,
       
   234                                                        ClassSymbol def) {
       
   235         Names names = def.name.table.names;
       
   236         for (SerialFieldTag tag : spfDoc.serialFieldTags()) {
       
   237             if (tag.fieldName() == null || tag.fieldType() == null) // ignore malformed @serialField tags
       
   238                 continue;
       
   239 
       
   240             Name fieldName = names.fromString(tag.fieldName());
       
   241 
       
   242             // Look for a FieldDocImpl that is documented by serialFieldTagImpl.
       
   243             for (Symbol sym : def.members().getSymbolsByName(fieldName)) {
       
   244                 if (sym.kind == VAR) {
       
   245                     VarSymbol f = (VarSymbol) sym;
       
   246                     FieldDocImpl fdi = env.getFieldDoc(f);
       
   247                     ((SerialFieldTagImpl) (tag)).mapToFieldDocImpl(fdi);
       
   248                     break;
       
   249                 }
       
   250             }
       
   251         }
       
   252     }
       
   253 
       
   254     /**
       
   255      * Return serializable fields in class. <p>
       
   256      *
       
   257      * Returns either a list of default fields documented by serial tag comment or
       
   258      *         javadoc comment<p>
       
   259      * Or Returns a single FieldDocImpl for serialPersistentField. There is a
       
   260      *         serialField tag for each serializable field.<p>
       
   261      *
       
   262      * @return an array of FieldDocImpl for representing the visible
       
   263      *         fields in this class.
       
   264      */
       
   265     FieldDoc[] fields() {
       
   266         return (FieldDoc[])fields.toArray(new FieldDocImpl[fields.length()]);
       
   267     }
       
   268 
       
   269     /**
       
   270      * Return serialization methods in class.
       
   271      *
       
   272      * @return an array of MethodDocImpl for serialization methods in this class.
       
   273      */
       
   274     MethodDoc[] methods() {
       
   275         return methods.toArray(new MethodDoc[methods.length()]);
       
   276     }
       
   277 
       
   278     /**
       
   279      * Returns true if Serializable fields are defined explicitly using
       
   280      * member, serialPersistentFields.
       
   281      *
       
   282      * @see #fields()
       
   283      */
       
   284     boolean definesSerializableFields() {
       
   285         return definesSerializableFields;
       
   286     }
       
   287 }