src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java
changeset 47216 71c04702a3d5
parent 45599 8bc3a019f948
child 48087 f5d7096cfdc0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,617 @@
+/*
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.javadoc.internal.doclets.toolkit.builders;
+
+
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+
+import com.sun.source.doctree.DocTree;
+import com.sun.source.doctree.SerialFieldTree;
+import jdk.javadoc.internal.doclets.toolkit.Content;
+import jdk.javadoc.internal.doclets.toolkit.DocletException;
+import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
+import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
+import jdk.javadoc.internal.doclets.toolkit.util.Utils;
+
+/**
+ * Builds the serialized form.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ * @author Jamie Ho
+ * @author Bhavesh Patel (Modified)
+ */
+public class SerializedFormBuilder extends AbstractBuilder {
+
+    /**
+     * The writer for this builder.
+     */
+    private SerializedFormWriter writer;
+
+    /**
+     * The writer for serializable fields.
+     */
+    private SerializedFormWriter.SerialFieldWriter fieldWriter;
+
+    /**
+     * The writer for serializable method documentation.
+     */
+    private SerializedFormWriter.SerialMethodWriter methodWriter;
+
+    /**
+     * The header for the serial version UID.  Save the string
+     * here instead of the properties file because we do not want
+     * this string to be localized.
+     */
+    private static final String SERIAL_VERSION_UID = "serialVersionUID";
+    private static final String SERIAL_VERSION_UID_HEADER = SERIAL_VERSION_UID + ":";
+
+    /**
+     * The current package being documented.
+     */
+    private PackageElement currentPackage;
+
+    /**
+     * The current class being documented.
+     */
+    private TypeElement currentTypeElement;
+
+    /**
+     * The current member being documented.
+     */
+    protected Element currentMember;
+
+    /**
+     * The content that will be added to the serialized form documentation tree.
+     */
+    private Content contentTree;
+
+
+    /**
+     * Construct a new SerializedFormBuilder.
+     * @param context  the build context.
+     */
+    private SerializedFormBuilder(Context context) {
+        super(context);
+    }
+
+    /**
+     * Construct a new SerializedFormBuilder.
+     *
+     * @param context  the build context.
+     * @return the new SerializedFormBuilder
+     */
+    public static SerializedFormBuilder getInstance(Context context) {
+        return new SerializedFormBuilder(context);
+    }
+
+    /**
+     * Build the serialized form.
+     *
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    @Override
+    public void build() throws DocletException {
+        SortedSet<TypeElement> rootclasses = new TreeSet<>(utils.makeGeneralPurposeComparator());
+        rootclasses.addAll(configuration.getIncludedTypeElements());
+        if (!serialClassFoundToDocument(rootclasses)) {
+            //Nothing to document.
+            return;
+        }
+        writer = configuration.getWriterFactory().getSerializedFormWriter();
+        if (writer == null) {
+            //Doclet does not support this output.
+            return;
+        }
+        buildSerializedForm(contentTree);
+    }
+
+    /**
+     * Build the serialized form.
+     *
+     * @param serializedTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildSerializedForm(Content serializedTree) throws DocletException {
+        serializedTree = writer.getHeader(configuration.getText(
+                "doclet.Serialized_Form"));
+
+        buildSerializedFormSummaries(serializedTree);
+
+        writer.addFooter(serializedTree);
+        writer.printDocument(serializedTree);
+    }
+
+    /**
+     * Build the serialized form summaries.
+     *
+     * @param serializedTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildSerializedFormSummaries(Content serializedTree)
+            throws DocletException {
+        Content serializedSummariesTree = writer.getSerializedSummariesHeader();
+        for (PackageElement pkg : configuration.packages) {
+            currentPackage = pkg;
+
+            buildPackageSerializedForm(serializedSummariesTree);
+        }
+        serializedTree.addContent(writer.getSerializedContent(
+                serializedSummariesTree));
+    }
+
+    /**
+     * Build the package serialized form for the current package being processed.
+     *
+     * @param serializedSummariesTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildPackageSerializedForm(Content serializedSummariesTree) throws DocletException {
+        Content packageSerializedTree = writer.getPackageSerializedHeader();
+        SortedSet<TypeElement> classes = utils.getAllClassesUnfiltered(currentPackage);
+        if (classes.isEmpty()) {
+            return;
+        }
+        if (!serialInclude(utils, currentPackage)) {
+            return;
+        }
+        if (!serialClassFoundToDocument(classes)) {
+            return;
+        }
+
+        buildPackageHeader(packageSerializedTree);
+        buildClassSerializedForm(packageSerializedTree);
+
+        writer.addPackageSerializedTree(serializedSummariesTree, packageSerializedTree);
+    }
+
+    /**
+     * Build the package header.
+     *
+     * @param packageSerializedTree content tree to which the documentation will be added
+     */
+    protected void buildPackageHeader(Content packageSerializedTree) {
+        packageSerializedTree.addContent(writer.getPackageHeader(
+                utils.getPackageName(currentPackage)));
+    }
+
+    /**
+     * Build the class serialized form.
+     *
+     * @param packageSerializedTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildClassSerializedForm(Content packageSerializedTree)
+            throws DocletException {
+        Content classSerializedTree = writer.getClassSerializedHeader();
+        SortedSet<TypeElement> typeElements = utils.getAllClassesUnfiltered(currentPackage);
+        for (TypeElement typeElement : typeElements) {
+            currentTypeElement = typeElement;
+            fieldWriter = writer.getSerialFieldWriter(currentTypeElement);
+            methodWriter = writer.getSerialMethodWriter(currentTypeElement);
+            if (utils.isClass(currentTypeElement) && utils.isSerializable(currentTypeElement)) {
+                if (!serialClassInclude(utils, currentTypeElement)) {
+                    continue;
+                }
+                Content classTree = writer.getClassHeader(currentTypeElement);
+
+                buildSerialUIDInfo(classTree);
+                buildClassContent(classTree);
+
+                classSerializedTree.addContent(classTree);
+            }
+        }
+        packageSerializedTree.addContent(classSerializedTree);
+    }
+
+    /**
+     * Build the serial UID information for the given class.
+     *
+     * @param classTree content tree to which the serial UID information will be added
+     */
+    protected void buildSerialUIDInfo(Content classTree) {
+        Content serialUidTree = writer.getSerialUIDInfoHeader();
+        for (Element e : utils.getFieldsUnfiltered(currentTypeElement)) {
+            VariableElement field = (VariableElement)e;
+            if (field.getSimpleName().toString().compareTo(SERIAL_VERSION_UID) == 0 &&
+                field.getConstantValue() != null) {
+                writer.addSerialUIDInfo(SERIAL_VERSION_UID_HEADER,
+                                        utils.constantValueExpresion(field), serialUidTree);
+                break;
+            }
+        }
+        classTree.addContent(serialUidTree);
+    }
+
+    /**
+     * Build the summaries for the methods and fields.
+     *
+     * @param classTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildClassContent(Content classTree) throws DocletException {
+        Content classContentTree = writer.getClassContentHeader();
+
+        buildSerializableMethods(classContentTree);
+        buildFieldHeader(classContentTree);
+        buildSerializableFields(classContentTree);
+
+        classTree.addContent(classContentTree);
+    }
+
+    /**
+     * Build the summaries for the methods that belong to the given class.
+     *
+     * @param classContentTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildSerializableMethods(Content classContentTree) throws DocletException {
+        Content serializableMethodTree = methodWriter.getSerializableMethodsHeader();
+        SortedSet<ExecutableElement> members = utils.serializationMethods(currentTypeElement);
+        if (!members.isEmpty()) {
+            for (ExecutableElement member : members) {
+                currentMember = member;
+                Content methodsContentTree = methodWriter.getMethodsContentHeader(
+                        currentMember == members.last());
+
+                buildMethodSubHeader(methodsContentTree);
+                buildDeprecatedMethodInfo(methodsContentTree);
+                buildMethodInfo(methodsContentTree);
+
+                serializableMethodTree.addContent(methodsContentTree);
+            }
+        }
+        if (!utils.serializationMethods(currentTypeElement).isEmpty()) {
+            classContentTree.addContent(methodWriter.getSerializableMethods(
+                    configuration.getText("doclet.Serialized_Form_methods"),
+                    serializableMethodTree));
+            if (utils.isSerializable(currentTypeElement) && !utils.isExternalizable(currentTypeElement)) {
+                if (utils.serializationMethods(currentTypeElement).isEmpty()) {
+                    Content noCustomizationMsg = methodWriter.getNoCustomizationMsg(
+                            configuration.getText("doclet.Serializable_no_customization"));
+                    classContentTree.addContent(methodWriter.getSerializableMethods(
+                    configuration.getText("doclet.Serialized_Form_methods"),
+                    noCustomizationMsg));
+                }
+            }
+        }
+    }
+
+    /**
+     * Build the method sub header.
+     *
+     * @param methodsContentTree content tree to which the documentation will be added
+     */
+    protected void buildMethodSubHeader(Content methodsContentTree)  {
+        methodWriter.addMemberHeader((ExecutableElement)currentMember, methodsContentTree);
+    }
+
+    /**
+     * Build the deprecated method description.
+     *
+     * @param methodsContentTree content tree to which the documentation will be added
+     */
+    protected void buildDeprecatedMethodInfo(Content methodsContentTree) {
+        methodWriter.addDeprecatedMemberInfo((ExecutableElement)currentMember, methodsContentTree);
+    }
+
+    /**
+     * Build the information for the method.
+     *
+     * @param methodsContentTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildMethodInfo(Content methodsContentTree) throws DocletException  {
+        if (configuration.nocomment) {
+            return;
+        }
+
+        buildMethodDescription(methodsContentTree);
+        buildMethodTags(methodsContentTree);
+    }
+
+    /**
+     * Build method description.
+     *
+     * @param methodsContentTree content tree to which the documentation will be added
+     */
+    protected void buildMethodDescription(Content methodsContentTree) {
+        methodWriter.addMemberDescription((ExecutableElement)currentMember, methodsContentTree);
+    }
+
+    /**
+     * Build the method tags.
+     *
+     * @param methodsContentTree content tree to which the documentation will be added
+     */
+    protected void buildMethodTags(Content methodsContentTree) {
+        methodWriter.addMemberTags((ExecutableElement)currentMember, methodsContentTree);
+        ExecutableElement method = (ExecutableElement)currentMember;
+        if (method.getSimpleName().toString().compareTo("writeExternal") == 0
+                && utils.getSerialDataTrees(method).isEmpty()) {
+            if (configuration.serialwarn) {
+                TypeElement encl  = (TypeElement) method.getEnclosingElement();
+                messages.warning(currentMember,
+                        "doclet.MissingSerialDataTag", encl.getQualifiedName().toString(),
+                        method.getSimpleName().toString());
+            }
+        }
+    }
+
+    /**
+     * Build the field header.
+     *
+     * @param classContentTree content tree to which the documentation will be added
+     */
+    protected void buildFieldHeader(Content classContentTree) {
+        if (!utils.serializableFields(currentTypeElement).isEmpty()) {
+            buildFieldSerializationOverview(currentTypeElement, classContentTree);
+        }
+    }
+
+    /**
+     * Build the serialization overview for the given class.
+     *
+     * @param typeElement the class to print the overview for.
+     * @param classContentTree content tree to which the documentation will be added
+     */
+    public void buildFieldSerializationOverview(TypeElement typeElement, Content classContentTree) {
+        if (utils.definesSerializableFields(typeElement)) {
+            VariableElement ve = utils.serializableFields(typeElement).first();
+            // Check to see if there are inline comments, tags or deprecation
+            // information to be printed.
+            if (fieldWriter.shouldPrintOverview(ve)) {
+                Content serializableFieldsTree = fieldWriter.getSerializableFieldsHeader();
+                Content fieldsOverviewContentTree = fieldWriter.getFieldsContentHeader(true);
+                fieldWriter.addMemberDeprecatedInfo(ve, fieldsOverviewContentTree);
+                if (!configuration.nocomment) {
+                    fieldWriter.addMemberDescription(ve, fieldsOverviewContentTree);
+                    fieldWriter.addMemberTags(ve, fieldsOverviewContentTree);
+                }
+                serializableFieldsTree.addContent(fieldsOverviewContentTree);
+                classContentTree.addContent(fieldWriter.getSerializableFields(
+                        configuration.getText("doclet.Serialized_Form_class"),
+                        serializableFieldsTree));
+            }
+        }
+    }
+
+    /**
+     * Build the summaries for the fields that belong to the given class.
+     *
+     * @param classContentTree content tree to which the documentation will be added
+     * @throws DocletException if there is a problem while building the documentation
+     */
+    protected void buildSerializableFields(Content classContentTree)
+            throws DocletException {
+        SortedSet<VariableElement> members = utils.serializableFields(currentTypeElement);
+        if (!members.isEmpty()) {
+            Content serializableFieldsTree = fieldWriter.getSerializableFieldsHeader();
+            for (VariableElement ve : members) {
+                currentMember = ve;
+                if (!utils.definesSerializableFields(currentTypeElement)) {
+                    Content fieldsContentTree = fieldWriter.getFieldsContentHeader(
+                            currentMember == members.last());
+
+                    buildFieldSubHeader(fieldsContentTree);
+                    buildFieldDeprecationInfo(fieldsContentTree);
+                    buildFieldInfo(fieldsContentTree);
+
+                    serializableFieldsTree.addContent(fieldsContentTree);
+                } else {
+                    buildSerialFieldTagsInfo(serializableFieldsTree);
+                }
+            }
+            classContentTree.addContent(fieldWriter.getSerializableFields(
+                    configuration.getText("doclet.Serialized_Form_fields"),
+                    serializableFieldsTree));
+        }
+    }
+
+    /**
+     * Build the field sub header.
+     *
+     * @param fieldsContentTree content tree to which the documentation will be added
+     */
+    protected void buildFieldSubHeader(Content fieldsContentTree) {
+        if (!utils.definesSerializableFields(currentTypeElement)) {
+            VariableElement field = (VariableElement) currentMember;
+            fieldWriter.addMemberHeader(utils.asTypeElement(field.asType()),
+                    utils.getTypeName(field.asType(), false), utils.getDimension(field.asType()),
+                    utils.getSimpleName(field),
+                    fieldsContentTree);
+        }
+    }
+
+    /**
+     * Build the field deprecation information.
+     *
+     * @param fieldsContentTree content tree to which the documentation will be added
+     */
+    protected void buildFieldDeprecationInfo(Content fieldsContentTree) {
+        if (!utils.definesSerializableFields(currentTypeElement)) {
+            fieldWriter.addMemberDeprecatedInfo((VariableElement)currentMember,
+                    fieldsContentTree);
+        }
+    }
+
+    /**
+     * Build the serial field tags information.
+     *
+     * @param serializableFieldsTree content tree to which the documentation will be added
+     */
+    protected void buildSerialFieldTagsInfo(Content serializableFieldsTree) {
+        if (configuration.nocomment) {
+            return;
+        }
+        VariableElement field = (VariableElement)currentMember;
+        // Process Serializable Fields specified as array of
+        // ObjectStreamFields. Print a member for each serialField tag.
+        // (There should be one serialField tag per ObjectStreamField
+        // element.)
+        SortedSet<SerialFieldTree> tags = new TreeSet<>(utils.makeSerialFieldTreeComparator());
+        // sort the elements
+        for (DocTree dt : utils.getSerialFieldTrees(field)) {
+            SerialFieldTree st = (SerialFieldTree) dt;
+            tags.add(st);
+        }
+
+        CommentHelper ch = utils.getCommentHelper(field);
+        for (SerialFieldTree tag : tags) {
+            if (tag.getName() == null || tag.getType() == null)  // ignore malformed @serialField tags
+                continue;
+            Content fieldsContentTree = fieldWriter.getFieldsContentHeader(tag.equals(tags.last()));
+            TypeElement te = ch.getReferencedClass(configuration, tag);
+            String fieldType = ch.getReferencedMemberName(tag);
+            if (te != null && utils.isPrimitive(te.asType())) {
+                fieldType = utils.getTypeName(te.asType(), false);
+                te = null;
+            }
+            String refSignature = ch.getReferencedSignature(tag);
+            // TODO: Print the signature directly, if it is an array, the
+            // current DocTree APIs makes it very hard to distinguish
+            // an as these are returned back as "Array" a DeclaredType.
+            if (refSignature.endsWith("[]")) {
+                te = null;
+                fieldType = refSignature;
+            }
+            fieldWriter.addMemberHeader(te, fieldType, "",
+                    tag.getName().getName().toString(), fieldsContentTree);
+            fieldWriter.addMemberDescription(field, tag, fieldsContentTree);
+            serializableFieldsTree.addContent(fieldsContentTree);
+        }
+    }
+
+    /**
+     * Build the field information.
+     *
+     * @param fieldsContentTree content tree to which the documentation will be added
+     */
+    protected void buildFieldInfo(Content fieldsContentTree) {
+        if (configuration.nocomment) {
+            return;
+        }
+        VariableElement field = (VariableElement)currentMember;
+        TypeElement te = utils.getEnclosingTypeElement(currentMember);
+        // Process default Serializable field.
+        if ((utils.getSerialTrees(field).isEmpty()) /*&& !field.isSynthetic()*/
+                && configuration.serialwarn) {
+            messages.warning(field,
+                    "doclet.MissingSerialTag", utils.getFullyQualifiedName(te),
+                    utils.getSimpleName(field));
+        }
+        fieldWriter.addMemberDescription(field, fieldsContentTree);
+        fieldWriter.addMemberTags(field, fieldsContentTree);
+    }
+
+    /**
+     * Returns true if the given Element should be included
+     * in the serialized form.
+     *
+     * @param utils the utils object
+     * @param element the Element object to check for serializability
+     * @return true if the element should be included in the serial form
+     */
+    public static boolean serialInclude(Utils utils, Element element) {
+        if (element == null) {
+            return false;
+        }
+        return utils.isClass(element)
+                ? serialClassInclude(utils, (TypeElement)element)
+                : serialDocInclude(utils, element);
+    }
+
+    /**
+     * Returns true if the given TypeElement should be included
+     * in the serialized form.
+     *
+     * @param te the TypeElement object to check for serializability.
+     */
+    private static boolean serialClassInclude(Utils utils, TypeElement te) {
+        if (utils.isEnum(te)) {
+            return false;
+        }
+        if (utils.isSerializable(te)) {
+            if (!utils.getSerialTrees(te).isEmpty()) {
+                return serialDocInclude(utils, te);
+            } else if (utils.isPublic(te) || utils.isProtected(te)) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Return true if the given Element should be included
+     * in the serialized form.
+     *
+     * @param element the Element to check for serializability.
+     */
+    private static boolean serialDocInclude(Utils utils, Element element) {
+        if (utils.isEnum(element)) {
+            return false;
+        }
+        List<? extends DocTree> serial = utils.getSerialTrees(element);
+        if (!serial.isEmpty()) {
+            CommentHelper ch = utils.getCommentHelper(element);
+            String serialtext = Utils.toLowerCase(ch.getText(serial.get(0)));
+            if (serialtext.contains("exclude")) {
+                return false;
+            } else if (serialtext.contains("include")) {
+                return true;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Return true if any of the given typeElements have a @serialinclude tag.
+     *
+     * @param classes the typeElements to check.
+     * @return true if any of the given typeElements have a @serialinclude tag.
+     */
+    private boolean serialClassFoundToDocument(SortedSet<TypeElement> classes) {
+        for (TypeElement aClass : classes) {
+            if (serialClassInclude(utils, aClass)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}