changeset 57915:05ce0bfac260 records-and-sealed

update support for records and sealed types
author jjg
date Thu, 10 Oct 2019 17:23:11 -0700
parents 22a2bee294f4
children 6b5311b6bf73
files src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Resources.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocMemberEnter.java test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/BinaryNode.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Coords.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Holder.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Node.java test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Point.java test/langtools/jdk/javadoc/doclet/testRecordTypes/jdk11/element-list test/langtools/jdk/javadoc/doclet/testSealedTypes/TestSealedTypes.java test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java
diffstat 21 files changed, 817 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java	Thu Oct 10 17:23:11 2019 -0700
@@ -155,6 +155,7 @@
     public final Content propertyLabel;
     public final Content propertyDetailsLabel;
     public final Content propertySummaryLabel;
+    public final Content record;
     public final Content seeLabel;
     public final Content serializedForm;
     public final Content servicesLabel;
@@ -282,6 +283,7 @@
         propertyLabel = getContent("doclet.Property");
         propertyDetailsLabel = getContent("doclet.Property_Detail");
         propertySummaryLabel = getContent("doclet.Property_Summary");
+        record = getContent("doclet.Record");
         seeLabel = getContent("doclet.See");
         serializedForm = getContent("doclet.Serialized_Form");
         servicesLabel = getContent("doclet.Services");
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Thu Oct 10 17:23:11 2019 -0700
@@ -1512,7 +1512,8 @@
                 @Override
                 public Boolean visitLink(LinkTree node, Content c) {
                     // we need to pass the DocTreeImpl here, so ignore node
-                    result.add(seeTagToContent(element, tag));
+                    Content content = seeTagToContent(element, tag);
+                    result.add(content);
                     return false;
                 }
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Thu Oct 10 17:23:11 2019 -0700
@@ -214,6 +214,15 @@
      * {@inheritDoc}
      */
     @Override
+    public void addRecordSummary(SortedSet<TypeElement> records, Content summaryContentTree) {
+        TableHeader tableHeader= new TableHeader(contents.record, contents.descriptionLabel);
+        addClassesSummary(records, resources.recordSummary, tableHeader, summaryContentTree);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     public void addExceptionSummary(SortedSet<TypeElement> exceptions, Content summaryContentTree) {
         TableHeader tableHeader= new TableHeader(contents.exception, contents.descriptionLabel);
         addClassesSummary(exceptions, resources.exceptionSummary, tableHeader, summaryContentTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/CommentUtils.java	Thu Oct 10 17:23:11 2019 -0700
@@ -38,11 +38,14 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.lang.model.element.Element;
 import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.Name;
 import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.RecordComponentElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.util.Elements;
@@ -195,8 +198,22 @@
      * @param ee the {@code equals} method
      */
     public void setRecordEqualsTree(ExecutableElement ee) {
-        List<DocTree> fullBody = List.of(makeTextTreeForResource("doclet.record_equals_doc.fullbody"));
+        List<DocTree> fullBody = new ArrayList<>();
+        add(fullBody, "doclet.record_equals_doc.fullbody.head");
+        fullBody.add(treeFactory.newTextTree(" "));
 
+        List<? extends RecordComponentElement> comps = ((TypeElement) ee.getEnclosingElement()).getRecordComponents();
+        boolean hasPrimitiveComponents =
+                comps.stream().anyMatch(e -> e.asType().getKind().isPrimitive());
+        boolean hasReferenceComponents =
+                comps.stream().anyMatch(e -> !e.asType().getKind().isPrimitive());
+        if (hasPrimitiveComponents && hasReferenceComponents) {
+            add(fullBody, "doclet.record_equals_doc.fullbody.tail.both");
+        } else if (hasPrimitiveComponents) {
+            add(fullBody, "doclet.record_equals_doc.fullbody.tail.primitive");
+        } else if (hasReferenceComponents) {
+            add(fullBody, "doclet.record_equals_doc.fullbody.tail.reference");
+        }
         Name paramName = ee.getParameters().get(0).getSimpleName();
         IdentifierTree id = treeFactory.newIdentifierTree(paramName);
         List<DocTree> paramDesc =
@@ -206,8 +223,31 @@
         DocTree returnTree = treeFactory.newReturnTree(
                 makeDescriptionWithName("doclet.record_equals_doc.return", paramName));
 
+        TreePath treePath = utils.getTreePath(ee.getEnclosingElement());
         DocCommentTree docTree = treeFactory.newDocCommentTree(fullBody, List.of(paramTree, returnTree));
-        dcTreesMap.put(ee, new DocCommentDuo(null, docTree));
+        dcTreesMap.put(ee, new DocCommentDuo(treePath, docTree));
+    }
+
+    private void add(List<DocTree> contents, String resourceKey) {
+        // Special case to allow '{@link ...}' to appear in the string.
+        // A less general case would be to detect literal use of Object.equals
+        // A more general case would be to allow access to DocCommentParser somehow
+        String body = resources.getText(resourceKey);
+        Pattern p = Pattern.compile("\\{@link (\\S*)(.*)}");
+        Matcher m = p.matcher(body);
+        int start = 0;
+        while (m.find(start)) {
+            if (m.start() > start) {
+                contents.add(treeFactory.newTextTree(body.substring(start, m.start())));
+            }
+            ReferenceTree refTree = treeFactory.newReferenceTree(m.group(1));
+            List<DocTree> descr = List.of(treeFactory.newTextTree(m.group(2).trim())) ;
+            contents.add(treeFactory.newLinkTree(refTree, descr));
+            start = m.end();
+        }
+        if (start < body.length()) {
+            contents.add(treeFactory.newTextTree(body.substring(start)));
+        }
     }
 
     /**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java	Thu Oct 10 17:23:11 2019 -0700
@@ -95,6 +95,15 @@
             Content summaryContentTree);
 
     /**
+     * Adds the table of records to the documentation tree.
+     *
+     * @param records the records to document.
+     * @param summaryContentTree the content tree to which the summaries will be added
+     */
+    public abstract void addRecordSummary(SortedSet<TypeElement> records,
+                                        Content summaryContentTree);
+
+    /**
      * Adds the table of exceptions to the documentation tree.
      *
      * @param exceptions the exceptions to document.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Resources.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/Resources.java	Thu Oct 10 17:23:11 2019 -0700
@@ -49,6 +49,7 @@
     public final String exceptionSummary;
     public final String interfaceSummary;
     public final String packageSummary;
+    public final String recordSummary;
 
     protected ResourceBundle commonBundle;
     protected ResourceBundle docletBundle;
@@ -76,6 +77,7 @@
         this.exceptionSummary = getText("doclet.Exception_Summary");
         this.interfaceSummary = getText("doclet.Interface_Summary");
         this.packageSummary = getText("doclet.Package_Summary");
+        this.recordSummary = getText("doclet.Record_Summary");
     }
 
     /**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java	Thu Oct 10 17:23:11 2019 -0700
@@ -227,7 +227,7 @@
                 : configuration.typeElementCatalog.records(packageElement);
         SortedSet<TypeElement> records = utils.filterOutPrivateClasses(rlist, configuration.javafx);
         if (!records.isEmpty()) {
-            packageWriter.addEnumSummary(records, summaryContentTree);
+            packageWriter.addRecordSummary(records, summaryContentTree);
         }
     }
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties	Thu Oct 10 17:23:11 2019 -0700
@@ -93,13 +93,13 @@
 doclet.Default=Default:
 doclet.Parameters=Parameters:
 doclet.TypeParameters=Type Parameters:
-doclet.StateComponents=State Components:
+doclet.RecordComponents=Record Components:
 doclet.Parameters_warn=@param argument "{0}" is not a parameter name.
 doclet.Parameters_dup_warn=Parameter "{0}" is documented more than once.
 doclet.TypeParameters_warn=@param argument "{0}" is not the name of a type parameter.
 doclet.TypeParameters_dup_warn=Type parameter "{0}" is documented more than once.
-doclet.StateComponents_warn=@param argument "{0}" is not the name of a state component.
-doclet.StateComponents_dup_warn=State component "{0}" is documented more than once.
+doclet.RecordComponents_warn=@param argument "{0}" is not the name of a record component.
+doclet.RecordComponents_dup_warn=Record component "{0}" is documented more than once.
 doclet.Returns=Returns:
 doclet.Return_tag_on_void_method=@return tag cannot be used in method with void return type.
 doclet.See_Also=See Also:
@@ -142,6 +142,7 @@
 doclet.Enum_Constant_Summary=Enum Constant Summary
 doclet.Constructor_Summary=Constructor Summary
 doclet.Method_Summary=Method Summary
+doclet.Record_Summary=Record Summary
 doclet.Interfaces=Interfaces
 doclet.Enums=Enums
 doclet.AnnotationTypes=Annotation Types
@@ -281,12 +282,24 @@
  Creates an instance of a {0} record.
 
 doclet.record_constructor_doc.param_name=\
- the value for the {0} state component
+ the value for the {0} record component
 
-doclet.record_equals_doc.fullbody=\
+doclet.record_equals_doc.fullbody.head=\
  Indicates whether some other object is "equal to" this one. \
  The objects are equal if the other object is of the same class \
- and if all the state components are equal.
+ and if all the record components are equal.
+
+doclet.record_equals_doc.fullbody.tail.both=\
+ Reference components are compared with \
+ {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}; \
+ primitive components are compared with '=='.
+
+doclet.record_equals_doc.fullbody.tail.primitive=\
+ All components are compared with '=='.
+
+doclet.record_equals_doc.fullbody.tail.reference=\
+ All components are compared with \
+ {@link java.util.Objects#equals(Object,Object) Objects::equals(Object,Object)}.
 
 doclet.record_equals_doc.param_name=\
  the object with which to compare
@@ -296,24 +309,24 @@
 
 doclet.record_hashCode_doc.fullbody=\
  Returns a hash code value for this object. \
- The value is derived from the hash code of each of the state components.
+ The value is derived from the hash code of each of the record components.
 
 doclet.record_hashCode_doc.return=\
  a hash code value for this object
 
 doclet.record_toString_doc.fullbody=\
- Returns a string representation of this object. \
+ Returns a string representation of this record. \
  The representation contains the name of the type, followed by \
- the name and value of each of the state components.
+ the name and value of each of the record components.
 
 doclet.record_toString_doc.return=\
  a string representation of this object
 
 doclet.record_accessor_doc.fullbody=\
- Returns the value of the {0} state component.
+ Returns the value of the {0} record component.
 
 doclet.record_accessor_doc.return=\
- the value of the {0} state component
+ the value of the {0} record component
 
 doclet.record_field_doc.fullbody=\
- The field for the {0} state component.
+ The field for the {0} record component.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java	Thu Oct 10 17:23:11 2019 -0700
@@ -58,7 +58,7 @@
         /** Parameter of an executable element. */
         PARAMETER,
         /** State components of a record. */
-        STATE_COMPONENT,
+        RECORD_COMPONENT,
         /** Type parameters of an executable element or type element. */
         TYPE_PARAMETER
     }
@@ -150,7 +150,7 @@
             TypeElement typeElement = (TypeElement) holder;
             Content output = getTagletOutput(ParamKind.TYPE_PARAMETER, typeElement, writer,
                 typeElement.getTypeParameters(), utils.getTypeParamTrees(typeElement));
-            output.add(getTagletOutput(ParamKind.STATE_COMPONENT, typeElement, writer,
+            output.add(getTagletOutput(ParamKind.RECORD_COMPONENT, typeElement, writer,
                     typeElement.getRecordComponents(), utils.getParamTrees(typeElement)));
             return output;
         }
@@ -259,7 +259,7 @@
                     switch (kind) {
                         case PARAMETER:       key = "doclet.Parameters_warn" ; break;
                         case TYPE_PARAMETER:  key = "doclet.TypeParameters_warn" ; break;
-                        case STATE_COMPONENT: key = "doclet.StateComponents_warn" ; break;
+                        case RECORD_COMPONENT: key = "doclet.RecordComponents_warn" ; break;
                         default: throw new IllegalArgumentException(kind.toString());
                     }
                     messages.warning(ch.getDocTreePath(dt), key, paramName);
@@ -270,7 +270,7 @@
                     switch (kind) {
                         case PARAMETER:       key = "doclet.Parameters_dup_warn" ; break;
                         case TYPE_PARAMETER:  key = "doclet.TypeParameters_dup_warn" ; break;
-                        case STATE_COMPONENT: key = "doclet.StateComponents_dup_warn" ; break;
+                        case RECORD_COMPONENT: key = "doclet.RecordComponents_dup_warn" ; break;
                         default: throw new IllegalArgumentException(kind.toString());
                     }
                     messages.warning(ch.getDocTreePath(dt), key, paramName);
@@ -305,7 +305,7 @@
             switch (kind) {
                 case PARAMETER:       key = "doclet.Parameters" ; break;
                 case TYPE_PARAMETER:  key = "doclet.TypeParameters" ; break;
-                case STATE_COMPONENT: key = "doclet.StateComponents" ; break;
+                case RECORD_COMPONENT: key = "doclet.RecordComponents" ; break;
                 default: throw new IllegalArgumentException(kind.toString());
             }
             String header = writer.configuration().getResources().getText(key);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java	Thu Oct 10 17:23:11 2019 -0700
@@ -100,12 +100,11 @@
 
     public void setOverrideElement(Element ove) {
         if (this.element == ove) {
-            throw new AssertionError("cannot set given element as overriden element");
+            throw new AssertionError("cannot set given element as overridden element");
         }
         overriddenElement = ove;
     }
 
-    @SuppressWarnings("fallthrough")
     public String getTagName(DocTree dtree) {
         switch (dtree.getKind()) {
             case AUTHOR:
@@ -148,6 +147,9 @@
     Element getElement(BaseConfiguration c, ReferenceTree rtree) {
         // likely a synthesized tree
         if (path == null) {
+            // NOTE: this code path only supports module/package/type signatures
+            //       and not member signatures. For more complete support,
+            //       set a suitable path and avoid this branch.
             TypeMirror symbol = c.utils.getSymbol(rtree.getSignature());
             if (symbol == null) {
                 return null;
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Thu Oct 10 17:23:11 2019 -0700
@@ -493,12 +493,12 @@
             void addSealed(TypeElement e) {
                 if (elementUtils.isSealed(e)) {
                     append("sealed");
-                } else if (needsNonSealed(e)) {
+                } else if (anySupertypeSealed(e) && !e.getModifiers().contains(FINAL)) {
                     append("non-sealed");
                 }
             }
 
-            boolean needsNonSealed(TypeElement te) {
+            boolean anySupertypeSealed(TypeElement te) {
                 return isSealed(te.getSuperclass())
                         || te.getInterfaces().stream().anyMatch(this::isSealed);
             }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocMemberEnter.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/JavadocMemberEnter.java	Thu Oct 10 17:23:11 2019 -0700
@@ -31,7 +31,10 @@
 import com.sun.tools.javac.comp.MemberEnter;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.TreeInfo;
 import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Names;
 
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
@@ -61,6 +64,7 @@
 
     final ToolEnvironment toolEnv;
 
+
     protected JavadocMemberEnter(Context context) {
         super(context);
         toolEnv = ToolEnvironment.instance(context);
@@ -79,7 +83,12 @@
             toolEnv.setElementToTreePath(meth, treePath);
         }
         // release resources
-        tree.body = null;
+        // handle constructors for record types specially, because of downstream checks
+        if ((env.enclClass.mods.flags & Flags.RECORD) != 0 && TreeInfo.isConstructor(tree)) {
+            tree.body.stats = List.nil();
+        } else {
+            tree.body = null;
+        }
     }
 
     @Override
--- a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java	Thu Oct 10 17:23:11 2019 -0700
@@ -39,7 +39,6 @@
 import toolbox.ToolBox;
 
 public class TestRecordTypes extends JavadocTester {
-
     public static void main(String... args) throws Exception {
         TestRecordTypes tester = new TestRecordTypes();
         tester.runTests(m -> new Object[] { Path.of(m.getName()) });
@@ -47,6 +46,14 @@
 
     private final ToolBox tb = new ToolBox();
 
+    // The following constants are set up for use with -linkoffline
+    // (but note: JDK 11 does not include java.lang.Record, so expect
+    // some 404 broken links until we can update this to a stable version.)
+    private static final String externalDocs = 
+	"https://docs.oracle.com/en/java/javase/11/docs/api";
+    private static final String localDocs =
+	Path.of(testSrc).resolve("jdk11").toUri().toString();
+
     @Test
     public void testRecordKeywordUnnamedPackage(Path base) throws IOException {
         Path src = base.resolve("src");
@@ -55,6 +62,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 src.resolve("R.java").toString());
         checkExit(Exit.OK);
 
@@ -72,6 +80,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -89,6 +98,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -109,6 +119,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -116,7 +127,7 @@
                 "<h1 title=\"Record R\" class=\"title\">Record R</h1>",
                 "public record <span class=\"typeNameLabel\">R</span>",
                 "<dl>\n"
-                + "<dt><span class=\"paramLabel\">State Components:</span></dt>\n"
+                + "<dt><span class=\"paramLabel\">Record Components:</span></dt>\n"
                 + "<dd><code><a id=\"param-r1\">r1</a></code> - This is a component.</dd>\n"
                 + "</dl>",
                 "<code><span class=\"memberNameLink\"><a href=\"#%3Cinit%3E(int)\">R</a></span>&#8203;(int&nbsp;r1)</code>");
@@ -134,6 +145,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -143,7 +155,7 @@
                 "<dl>\n"
                 + "<dt><span class=\"paramLabel\">Type Parameters:</span></dt>\n"
                 + "<dd><code>T</code> - This is a type parameter.</dd>\n"
-                + "<dt><span class=\"paramLabel\">State Components:</span></dt>\n"
+                + "<dt><span class=\"paramLabel\">Record Components:</span></dt>\n"
                 + "<dd><code><a id=\"param-r1\">r1</a></code> - This is a component.</dd>\n"
                 + "</dl>",
                 "<code><span class=\"memberNameLink\"><a href=\"#%3Cinit%3E(int)\">R</a></span>&#8203;(int&nbsp;r1)</code>");
@@ -160,6 +172,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -176,13 +189,115 @@
                 "<a href=\"#hashCode()\">hashCode</a>",
                 "Returns a hash code value for this object.",
                 "<a href=\"#r1()\">r1</a>",
-                "Returns the value of the <a href=\"#param-r1\"><code>r1</code></a> state component.",
+                "Returns the value of the <a href=\"#param-r1\"><code>r1</code></a> record component.",
                 "<a href=\"#toString()\">toString</a>",
-                "Returns a string representation of this object."
+                "Returns a string representation of this record.",
+		"Method Details",
+		"<span class=\"memberName\">toString</span>",
+		"Returns a string representation of this record. The representation "
+		+ "contains the name of the type, followed by the name and value of "
+		+ "each of the record components.",
+		"<span class=\"memberName\">hashCode</span>",
+		"Returns a hash code value for this object. The value is derived "
+		+ "from the hash code of each of the record components.",
+		"<span class=\"memberName\">equals</span>",
+		"Indicates whether some other object is \"equal to\" this one. "
+		+ "The objects are equal if the other object is of the same class "
+		+ "and if all the record components are equal. All components "
+		+ "are compared with '=='.",
+		"<span class=\"memberName\">r1</span>",
+		"Returns the value of the <a href=\"#param-r1\"><code>r1</code></a> "
+		+ "record component."
         );
     }
 
     @Test
+    public void testGeneratedCommentsWithLinkOffline(Path base) throws IOException {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src,
+                "package p; /** This is record R. \n"
+                        + " * @param r1  This is a component.\n"
+                        + " */\n"
+                        + "public record R(int r1) { }");
+
+        javadoc("-d", base.resolve("out").toString(),
+                "-sourcepath", src.toString(),
+                "-linkoffline", externalDocs, localDocs,
+                "--enable-preview", "--source", thisRelease,
+                "p");
+        checkExit(Exit.OK);
+
+        // While we don't normally test values that just come from resource files,
+        // in these cases, we want to verify that something non-empty was put into
+        // the documentation for the generated members.
+        checkOrder("p/R.html",
+                "<section class=\"constructorSummary\">",
+                "<a href=\"#%3Cinit%3E(int)\">R</a>",
+                "Creates an instance of a <code>R</code> record.",
+                "<section class=\"methodSummary\">",
+                "<a href=\"#equals(java.lang.Object)\">equals</a>",
+                "Indicates whether some other object is \"equal to\" this one.",
+                "<a href=\"#hashCode()\">hashCode</a>",
+                "Returns a hash code value for this object.",
+                "<a href=\"#r1()\">r1</a>",
+                "Returns the value of the <a href=\"#param-r1\"><code>r1</code></a> record component.",
+                "<a href=\"#toString()\">toString</a>",
+                "Returns a string representation of this record.",
+		"Method Details",
+		"<span class=\"memberName\">toString</span>",
+		"Returns a string representation of this record. The representation "
+		+ "contains the name of the type, followed by the name and value of "
+		+ "each of the record components.",
+		"<span class=\"memberName\">hashCode</span>",
+		"Returns a hash code value for this object. The value is derived "
+		+ "from the hash code of each of the record components.",
+		"<span class=\"memberName\">equals</span>",
+		"Indicates whether some other object is \"equal to\" this one. "
+		+ "The objects are equal if the other object is of the same class "
+		+ "and if all the record components are equal. All components "
+		+ "are compared with '=='.",
+		"<span class=\"memberName\">r1</span>",
+		"Returns the value of the <a href=\"#param-r1\"><code>r1</code></a> "
+		+ "record component."
+        );
+    }
+
+    @Test
+    public void testGeneratedEqualsPrimitive(Path base) throws IOException {
+	testGeneratedEquals(base, "int a, int b", 
+             "All components are compared with '=='.");
+    }
+
+    @Test
+    public void testGeneratedEqualsReference(Path base) throws IOException {
+	testGeneratedEquals(base, "Object a, Object b", 
+             "All components are compared with <code>Objects::equals(Object,Object)</code>");
+    }
+
+    @Test
+    public void testGeneratedEqualsMixed(Path base) throws IOException {
+	testGeneratedEquals(base, "int a, Object b", 
+             "Reference components are compared with <code>Objects::equals(Object,Object)</code>; "
+	     + "primitive components are compared with '=='.");
+    }
+
+    private void testGeneratedEquals(Path base, String comps, String expect) throws IOException {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src,
+                "package p; /** This is record R. \n"
+                        + " */\n"
+                        + "public record R(" + comps + ") { }");
+
+        javadoc("-d", base.resolve("out").toString(),
+                "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
+                "p");
+        checkExit(Exit.OK);
+
+        checkOrder("p/R.html", expect);
+    }
+
+    @Test
     public void testUserComments(Path base) throws IOException {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
@@ -199,6 +314,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -218,4 +334,21 @@
         );
     }
 
+    @Test
+    public void testExamples(Path base) throws IOException {
+        javadoc("-d", base.resolve("out-no-link").toString(),
+                "-sourcepath", testSrc.toString(),
+                "-linksource",
+                "--enable-preview", "--source", thisRelease,
+                "examples");
+
+        checkExit(Exit.OK);
+        javadoc("-d", base.resolve("out-with-link").toString(),
+                "-sourcepath", testSrc.toString(),
+                "-linksource",
+                "-linkoffline", externalDocs, localDocs,
+                "--enable-preview", "--source", thisRelease,
+                "examples");
+        checkExit(Exit.OK);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/BinaryNode.java	Thu Oct 10 17:23:11 2019 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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 examples;
+
+/**
+ * A binary node.
+ *
+ * <em>This example illustrates the use of user provided methods
+ *     and documentation comments.</em>
+ *
+ * @param left  the left node
+ * @param right the right node
+ */
+public record BinaryNode(Node left, Node right) {
+    /**
+     * This is an example of a user-provided method.
+     *
+     * @param other the object with which to be compared
+     * @return      {@code true} if and only the two are equal
+     */
+    public boolean equals(Object other) {
+        return super.equals(other);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Coords.java	Thu Oct 10 17:23:11 2019 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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 examples;
+
+/**
+ * Two-dimensional coordinates that can be represented
+ * in either Cartesian or polar form.
+ */
+public sealed interface Coords
+    permits Coords.Cartesian, Coords.Polar {
+
+    /**
+     * Returns the Cartesian x-coordinate.
+     *
+     * @return the Cartesian x-coordinate
+     */
+    public double x();
+
+    /**
+     * Returns the Cartesian y-coordinate.
+     *
+     * @return the Cartesian y-coordinate
+     */
+    public double y();
+
+    /**
+     * Returns the polar r-coordinate, or radius.
+     *
+     * @return the polar r-coordinate
+     */
+    public double r();
+
+    /**
+     * Returns the polar theta-coordinate, or angle.
+     *
+     * @return the polar theta-coordinate
+     */
+    public double theta();
+
+    /**
+      * Cartesian coordinates.
+      *
+      * @param x the x-coordinate
+      * @param y the y-coordinate
+      */
+    public record Cartesian(double x, double y) implements Coords {
+        @Override
+        public double r() {
+            return Math.sqrt(x * x + y * y);
+        }
+
+        @Override
+        public double theta() {
+            return (x == 0) ? Math.PI / 2.d : Math.atan(y / x);
+        }
+    }
+
+    /**
+      * Polar coordinates.
+      *
+      * @param r     the radius
+      * @param theta the angle
+      */
+    public record Polar(double r, double theta) implements Coords {
+        @Override
+        public double x() {
+          return r * Math.cos(theta);
+        }
+
+        @Override
+        public double y() {
+          return r * Math.sin(theta);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Holder.java	Thu Oct 10 17:23:11 2019 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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 examples;
+
+/**
+ * A holder for an object.
+ *
+ * <em>This example illustrates the use of a generic record.</em>
+ *
+ * @param <T> the type of the enclosed item
+ * @param t   the item
+ */
+public record Holder<T>(T t) { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Node.java	Thu Oct 10 17:23:11 2019 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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 examples;
+
+/**
+ * A node.
+ *
+ * <em>This is just a supporting class for {@link BinaryNode}.</em>
+ */
+public interface Node { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/examples/Point.java	Thu Oct 10 17:23:11 2019 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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 examples;
+
+/**
+ * A cartesian point.
+ *
+ * <em>This example illustrates the use of implicitly provided methods
+ *     and documentation comments.</em>
+ *
+ * @param x the x coordinate
+ * @param y the y coordinate
+ */
+public record Point(int x, int y) { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/jdk11/element-list	Thu Oct 10 17:23:11 2019 -0700
@@ -0,0 +1,283 @@
+module:java.base
+java.io
+java.lang
+java.lang.annotation
+java.lang.invoke
+java.lang.module
+java.lang.ref
+java.lang.reflect
+java.math
+java.net
+java.net.spi
+java.nio
+java.nio.channels
+java.nio.channels.spi
+java.nio.charset
+java.nio.charset.spi
+java.nio.file
+java.nio.file.attribute
+java.nio.file.spi
+java.security
+java.security.acl
+java.security.cert
+java.security.interfaces
+java.security.spec
+java.text
+java.text.spi
+java.time
+java.time.chrono
+java.time.format
+java.time.temporal
+java.time.zone
+java.util
+java.util.concurrent
+java.util.concurrent.atomic
+java.util.concurrent.locks
+java.util.function
+java.util.jar
+java.util.regex
+java.util.spi
+java.util.stream
+java.util.zip
+javax.crypto
+javax.crypto.interfaces
+javax.crypto.spec
+javax.net
+javax.net.ssl
+javax.security.auth
+javax.security.auth.callback
+javax.security.auth.login
+javax.security.auth.spi
+javax.security.auth.x500
+javax.security.cert
+module:java.compiler
+javax.annotation.processing
+javax.lang.model
+javax.lang.model.element
+javax.lang.model.type
+javax.lang.model.util
+javax.tools
+module:java.datatransfer
+java.awt.datatransfer
+module:java.desktop
+java.applet
+java.awt
+java.awt.color
+java.awt.desktop
+java.awt.dnd
+java.awt.event
+java.awt.font
+java.awt.geom
+java.awt.im
+java.awt.im.spi
+java.awt.image
+java.awt.image.renderable
+java.awt.print
+java.beans
+java.beans.beancontext
+javax.accessibility
+javax.imageio
+javax.imageio.event
+javax.imageio.metadata
+javax.imageio.plugins.bmp
+javax.imageio.plugins.jpeg
+javax.imageio.plugins.tiff
+javax.imageio.spi
+javax.imageio.stream
+javax.print
+javax.print.attribute
+javax.print.attribute.standard
+javax.print.event
+javax.sound.midi
+javax.sound.midi.spi
+javax.sound.sampled
+javax.sound.sampled.spi
+javax.swing
+javax.swing.border
+javax.swing.colorchooser
+javax.swing.event
+javax.swing.filechooser
+javax.swing.plaf
+javax.swing.plaf.basic
+javax.swing.plaf.metal
+javax.swing.plaf.multi
+javax.swing.plaf.nimbus
+javax.swing.plaf.synth
+javax.swing.table
+javax.swing.text
+javax.swing.text.html
+javax.swing.text.html.parser
+javax.swing.text.rtf
+javax.swing.tree
+javax.swing.undo
+module:java.instrument
+java.lang.instrument
+module:java.logging
+java.util.logging
+module:java.management
+java.lang.management
+javax.management
+javax.management.loading
+javax.management.modelmbean
+javax.management.monitor
+javax.management.openmbean
+javax.management.relation
+javax.management.remote
+javax.management.timer
+module:java.management.rmi
+javax.management.remote.rmi
+module:java.naming
+javax.naming
+javax.naming.directory
+javax.naming.event
+javax.naming.ldap
+javax.naming.spi
+module:java.net.http
+java.net.http
+module:java.prefs
+java.util.prefs
+module:java.rmi
+java.rmi
+java.rmi.activation
+java.rmi.dgc
+java.rmi.registry
+java.rmi.server
+javax.rmi.ssl
+module:java.scripting
+javax.script
+module:java.se
+module:java.security.jgss
+javax.security.auth.kerberos
+org.ietf.jgss
+module:java.security.sasl
+javax.security.sasl
+module:java.smartcardio
+javax.smartcardio
+module:java.sql
+java.sql
+javax.sql
+module:java.sql.rowset
+javax.sql.rowset
+javax.sql.rowset.serial
+javax.sql.rowset.spi
+module:java.transaction.xa
+javax.transaction.xa
+module:java.xml
+javax.xml
+javax.xml.catalog
+javax.xml.datatype
+javax.xml.namespace
+javax.xml.parsers
+javax.xml.stream
+javax.xml.stream.events
+javax.xml.stream.util
+javax.xml.transform
+javax.xml.transform.dom
+javax.xml.transform.sax
+javax.xml.transform.stax
+javax.xml.transform.stream
+javax.xml.validation
+javax.xml.xpath
+org.w3c.dom
+org.w3c.dom.bootstrap
+org.w3c.dom.events
+org.w3c.dom.ls
+org.w3c.dom.ranges
+org.w3c.dom.traversal
+org.w3c.dom.views
+org.xml.sax
+org.xml.sax.ext
+org.xml.sax.helpers
+module:java.xml.crypto
+javax.xml.crypto
+javax.xml.crypto.dom
+javax.xml.crypto.dsig
+javax.xml.crypto.dsig.dom
+javax.xml.crypto.dsig.keyinfo
+javax.xml.crypto.dsig.spec
+module:jdk.accessibility
+com.sun.java.accessibility.util
+module:jdk.attach
+com.sun.tools.attach
+com.sun.tools.attach.spi
+module:jdk.charsets
+module:jdk.compiler
+com.sun.source.doctree
+com.sun.source.tree
+com.sun.source.util
+com.sun.tools.javac
+module:jdk.crypto.cryptoki
+module:jdk.crypto.ec
+module:jdk.dynalink
+jdk.dynalink
+jdk.dynalink.beans
+jdk.dynalink.linker
+jdk.dynalink.linker.support
+jdk.dynalink.support
+module:jdk.editpad
+module:jdk.hotspot.agent
+module:jdk.httpserver
+com.sun.net.httpserver
+com.sun.net.httpserver.spi
+module:jdk.jartool
+com.sun.jarsigner
+jdk.security.jarsigner
+module:jdk.javadoc
+com.sun.javadoc
+com.sun.tools.javadoc
+jdk.javadoc.doclet
+module:jdk.jcmd
+module:jdk.jconsole
+com.sun.tools.jconsole
+module:jdk.jdeps
+module:jdk.jdi
+com.sun.jdi
+com.sun.jdi.connect
+com.sun.jdi.connect.spi
+com.sun.jdi.event
+com.sun.jdi.request
+module:jdk.jdwp.agent
+module:jdk.jfr
+jdk.jfr
+jdk.jfr.consumer
+module:jdk.jlink
+module:jdk.jshell
+jdk.jshell
+jdk.jshell.execution
+jdk.jshell.spi
+jdk.jshell.tool
+module:jdk.jsobject
+netscape.javascript
+module:jdk.jstatd
+module:jdk.localedata
+module:jdk.management
+com.sun.management
+module:jdk.management.agent
+module:jdk.management.jfr
+jdk.management.jfr
+module:jdk.naming.dns
+module:jdk.naming.rmi
+module:jdk.net
+jdk.net
+jdk.nio
+module:jdk.pack
+module:jdk.rmic
+module:jdk.scripting.nashorn
+jdk.nashorn.api.scripting
+jdk.nashorn.api.tree
+module:jdk.sctp
+com.sun.nio.sctp
+module:jdk.security.auth
+com.sun.security.auth
+com.sun.security.auth.callback
+com.sun.security.auth.login
+com.sun.security.auth.module
+module:jdk.security.jgss
+com.sun.security.jgss
+module:jdk.xml.dom
+org.w3c.dom.css
+org.w3c.dom.html
+org.w3c.dom.stylesheets
+org.w3c.dom.xpath
+module:jdk.zipfs
+
--- a/test/langtools/jdk/javadoc/doclet/testSealedTypes/TestSealedTypes.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testSealedTypes/TestSealedTypes.java	Thu Oct 10 17:23:11 2019 -0700
@@ -31,7 +31,6 @@
  * @run main TestSealedTypes
  */
 
-
 import java.io.IOException;
 import java.nio.file.Path;
 
@@ -55,6 +54,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -70,6 +70,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "-sourcepath", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -86,6 +87,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -105,6 +107,7 @@
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -116,14 +119,15 @@
     }
 
     @Test
-    public void testImplicitSealedModifierClass(Path base) throws IOException {
+    public void testSealedSubtypeModifierClass(Path base) throws IOException {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A permits B { }",
-                "package p; public abstract class B extends A { }");
+                "package p; public sealed abstract class B extends A { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -135,14 +139,15 @@
     }
 
     @Test
-    public void testImplicitSealedModifierInterface(Path base) throws IOException {
+    public void testSealedSubtypeInterface(Path base) throws IOException {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed interface A permits B { }",
-                "package p; public interface B extends A { }");
+                "package p; public sealed interface B extends A { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -158,10 +163,11 @@
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A permits B { }",
-                "package p; public class B extends A { }");
+                "package p; public final class B extends A { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -176,12 +182,13 @@
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A permits B,C,D { }",
-                "package p; public class B extends A { }",
-                "package p; public class C extends A { }",
-                "package p; public class D extends A { }");
+                "package p; public final class B extends A { }",
+                "package p; public final class C extends A { }",
+                "package p; public final class D extends A { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -198,12 +205,13 @@
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A permits B,C,D { }",
-                "package p; public class B extends A { }",
-                "package p; public class C extends A { }",
-                "package p;        class D extends A { }");
+                "package p; public final class B extends A { }",
+                "package p; public final class C extends A { }",
+                "package p;        final class D extends A { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -214,19 +222,20 @@
                 + "<a href=\"C.html\" title=\"class in p\">C</a>, p.D</pre>");
     }
 
-    @Test
+    // @Test // javac incorrectly rejects the source
     public void testPartialMultiplePermitsWithSubtypes1(Path base) throws IOException {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A permits B,C,D { }",
-                "package p; public class B extends A { }",
-                "package p; public class C extends A { }",
+                "package p; public final  class B extends A { }",
+                "package p; public final  class C extends A { }",
                 "package p;        sealed class D extends A permits D1, D2 { }",
-                "package p; public class D1 extends D { }",
-                "package p; public class D2 extends D { }");
+                "package p; public final  class D1 extends D { }",
+                "package p; public final  class D2 extends D { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -242,14 +251,15 @@
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A permits B,C,D { }",
-                "package p; public class B extends A { }",
-                "package p; public class C extends A { }",
-                "package p;        non-sealed class D extends A { }",
-                "package p; public class D1 extends D { }",
-                "package p; public class D2 extends D { }");
+                "package p; public final  class B extends A { }",
+                "package p; public final  class C extends A { }",
+                "package p;    non-sealed class D extends A { }",
+                "package p; public final  class D1 extends D { }",
+                "package p; public final  class D2 extends D { }");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -265,13 +275,14 @@
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A { }\n"
-                + "class B extends A { }\n"
-                + "class C extends A { }\n"
-                + "class D extends A { }\n");
+                + "final class B extends A { }\n"
+                + "final class C extends A { }\n"
+                + "final class D extends A { }\n");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
                 "-package",
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
@@ -288,13 +299,14 @@
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package p; public sealed class A {\n"
-                + "  public static class B extends A { }\n"
-                + "  public static class C extends A { }\n"
-                + "  public static class D extends A { }\n"
+                + "  public static final class B extends A { }\n"
+                + "  public static final class C extends A { }\n"
+                + "  public static final class D extends A { }\n"
                 + "}");
 
         javadoc("-d", base.resolve("out").toString(),
                 "--source-path", src.toString(),
+                "--enable-preview", "--source", thisRelease,
                 "p");
         checkExit(Exit.OK);
 
--- a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java	Thu Oct 10 17:14:11 2019 -0700
+++ b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java	Thu Oct 10 17:23:11 2019 -0700
@@ -144,6 +144,8 @@
     public static final String FS = System.getProperty("file.separator");
     public static final String PS = System.getProperty("path.separator");
     public static final String NL = System.getProperty("line.separator");
+    public static final String thisRelease = System.getProperty("java.specification.version");
+
     public static final Path currDir = Paths.get(".").toAbsolutePath().normalize();
 
     public enum Output {