8223358: Incorrect HTML structure in annotation pages

Reviewed-by: jjg
This commit is contained in:
Hannes Wallnöfer 2021-11-09 20:11:18 +00:00
parent a60e91259b
commit 055de6f566
18 changed files with 268 additions and 443 deletions

@ -26,6 +26,7 @@
package jdk.javadoc.internal.doclets.formats.html;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
@ -36,39 +37,71 @@ import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
/**
* Writes annotation type required member documentation in HTML format.
* Writes annotation interface member documentation in HTML format.
*
* <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>
*/
public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
implements AnnotationTypeRequiredMemberWriter, MemberSummaryWriter {
public class AnnotationTypeMemberWriterImpl extends AbstractMemberWriter
implements AnnotationTypeMemberWriter, MemberSummaryWriter {
/**
* Construct a new AnnotationTypeRequiredMemberWriterImpl.
* We generate separate summaries for required and optional annotation interface members,
* so we need dedicated writer instances for each kind. For the details section, a single
* shared list is generated so a special {@code ANY} value is provided for this case.
*/
enum Kind {
OPTIONAL,
REQUIRED,
ANY
}
private final Kind kind;
/**
* Constructs a new AnnotationTypeMemberWriterImpl for any kind of member.
*
* @param writer The writer for the class that the member belongs to.
*/
public AnnotationTypeMemberWriterImpl(SubWriterHolderWriter writer) {
super(writer);
this.kind = Kind.ANY;
}
/**
* Constructs a new AnnotationTypeMemberWriterImpl for a specific kind of member.
*
* @param writer the writer that will write the output.
* @param annotationType the AnnotationType that holds this member.
* @param kind the kind of annotation interface members to handle.
*/
public AnnotationTypeRequiredMemberWriterImpl(SubWriterHolderWriter writer,
TypeElement annotationType) {
public AnnotationTypeMemberWriterImpl(SubWriterHolderWriter writer,
TypeElement annotationType,
Kind kind) {
super(writer, annotationType);
this.kind = kind;
}
@Override
public Content getMemberSummaryHeader(TypeElement typeElement,
Content memberSummaryTree) {
memberSummaryTree.add(selectComment(
MarkerComments.START_OF_ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY,
MarkerComments.START_OF_ANNOTATION_INTERFACE_REQUIRED_MEMBER_SUMMARY));
switch (kind) {
case OPTIONAL -> memberSummaryTree.add(selectComment(
MarkerComments.START_OF_ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY,
MarkerComments.START_OF_ANNOTATION_INTERFACE_OPTIONAL_MEMBER_SUMMARY));
case REQUIRED -> memberSummaryTree.add(selectComment(
MarkerComments.START_OF_ANNOTATION_TYPE_REQUIRED_MEMBER_SUMMARY,
MarkerComments.START_OF_ANNOTATION_INTERFACE_REQUIRED_MEMBER_SUMMARY));
case ANY -> throw new UnsupportedOperationException("unsupported member kind");
}
Content memberTree = new ContentBuilder();
writer.addSummaryHeader(this, memberTree);
return memberTree;
@ -82,7 +115,12 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.memberSummary,
HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY, summariesList, content);
switch (kind) {
case REQUIRED -> HtmlIds.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY;
case OPTIONAL -> HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY;
case ANY -> throw new UnsupportedOperationException("unsupported member kind");
},
summariesList, content);
}
@Override
@ -95,12 +133,9 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
@Override
public Content getAnnotationDetailsTreeHeader() {
Content memberDetailsTree = new ContentBuilder();
if (!writer.printedAnnotationHeading) {
Content heading = HtmlTree.HEADING(Headings.TypeDeclaration.DETAILS_HEADING,
contents.annotationTypeDetailsLabel);
memberDetailsTree.add(heading);
writer.printedAnnotationHeading = true;
}
Content heading = HtmlTree.HEADING(Headings.TypeDeclaration.DETAILS_HEADING,
contents.annotationTypeDetailsLabel);
memberDetailsTree.add(heading);
return memberDetailsTree;
}
@ -151,7 +186,11 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
@Override
public void addSummaryLabel(Content memberTree) {
HtmlTree label = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING,
contents.annotateTypeRequiredMemberSummaryLabel);
switch (kind) {
case REQUIRED -> contents.annotateTypeRequiredMemberSummaryLabel;
case OPTIONAL -> contents.annotateTypeOptionalMemberSummaryLabel;
case ANY -> throw new UnsupportedOperationException("unsupported member kind");
});
memberTree.add(label);
}
@ -159,15 +198,24 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
* Get the caption for the summary table.
* @return the caption
*/
// Overridden by AnnotationTypeOptionalMemberWriterImpl
protected Content getCaption() {
return contents.getContent("doclet.Annotation_Type_Required_Members");
return contents.getContent(
switch (kind) {
case REQUIRED -> "doclet.Annotation_Type_Required_Members";
case OPTIONAL -> "doclet.Annotation_Type_Optional_Members";
case ANY -> throw new UnsupportedOperationException("unsupported member kind");
});
}
@Override
public TableHeader getSummaryTableHeader(Element member) {
return new TableHeader(contents.modifierAndTypeLabel,
contents.annotationTypeRequiredMemberLabel, contents.descriptionLabel);
switch (kind) {
case REQUIRED -> contents.annotationTypeRequiredMemberLabel;
case OPTIONAL -> contents.annotationTypeOptionalMemberLabel;
case ANY -> throw new UnsupportedOperationException("unsupported member kind");
},
contents.descriptionLabel);
}
@Override
@ -219,4 +267,17 @@ public class AnnotationTypeRequiredMemberWriterImpl extends AbstractMemberWriter
? utils.getReturnType(typeElement, (ExecutableElement) member)
: member.asType();
}
public void addDefaultValueInfo(Element member, Content annotationDocTree) {
if (utils.isAnnotationType(member)) {
ExecutableElement ee = (ExecutableElement) member;
AnnotationValue value = ee.getDefaultValue();
if (value != null) {
Content dl = HtmlTree.DL(HtmlStyle.notes);
dl.add(HtmlTree.DT(contents.default_));
dl.add(HtmlTree.DD(Text.of(value.toString())));
annotationDocTree.add(dl);
}
}
}
}

@ -1,113 +0,0 @@
/*
* Copyright (c) 2003, 2021, 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.formats.html;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
import jdk.javadoc.internal.doclets.formats.html.markup.Text;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
/**
* Writes annotation type optional member documentation in HTML format.
*
* <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>
*/
public class AnnotationTypeOptionalMemberWriterImpl extends
AnnotationTypeRequiredMemberWriterImpl
implements AnnotationTypeOptionalMemberWriter, MemberSummaryWriter {
/**
* Construct a new AnnotationTypeOptionalMemberWriterImpl.
*
* @param writer the writer that will write the output.
* @param annotationType the AnnotationType that holds this member.
*/
public AnnotationTypeOptionalMemberWriterImpl(SubWriterHolderWriter writer,
TypeElement annotationType) {
super(writer, annotationType);
}
@Override
public Content getMemberSummaryHeader(TypeElement typeElement,
Content memberSummaryTree) {
memberSummaryTree.add(selectComment(
MarkerComments.START_OF_ANNOTATION_TYPE_OPTIONAL_MEMBER_SUMMARY,
MarkerComments.START_OF_ANNOTATION_INTERFACE_OPTIONAL_MEMBER_SUMMARY));
Content memberTree = new ContentBuilder();
writer.addSummaryHeader(this, memberTree);
return memberTree;
}
@Override
public void addSummary(Content summariesList, Content content) {
writer.addSummary(HtmlStyle.memberSummary,
HtmlIds.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY, summariesList, content);
}
@Override
public void addDefaultValueInfo(Element member, Content annotationDocTree) {
if (utils.isAnnotationType(member)) {
ExecutableElement ee = (ExecutableElement) member;
AnnotationValue value = ee.getDefaultValue();
if (value != null) {
Content dl = HtmlTree.DL(HtmlStyle.notes);
dl.add(HtmlTree.DT(contents.default_));
dl.add(HtmlTree.DD(Text.of(value.toString())));
annotationDocTree.add(dl);
}
}
}
@Override
public void addSummaryLabel(Content memberTree) {
Content label = HtmlTree.HEADING(Headings.TypeDeclaration.SUMMARY_HEADING,
contents.annotateTypeOptionalMemberSummaryLabel);
memberTree.add(label);
}
@Override
protected Content getCaption() {
return contents.getContent("doclet.Annotation_Type_Optional_Members");
}
@Override
public TableHeader getSummaryTableHeader(Element member) {
return new TableHeader(contents.modifierAndTypeLabel,
contents.annotationTypeOptionalMemberLabel, contents.descriptionLabel);
}
}

@ -177,11 +177,6 @@ public class HtmlDocletWriter {
protected final HtmlIds htmlIds;
/**
* To check whether annotation heading is printed or not.
*/
protected boolean printedAnnotationHeading = false;
/**
* To check whether the repeated annotations is documented or not.
*/

@ -442,6 +442,8 @@ public class HtmlIds {
case FIELDS -> FIELD_SUMMARY;
case CONSTRUCTORS -> CONSTRUCTOR_SUMMARY;
case METHODS -> METHOD_SUMMARY;
// We generate separate summaries for optional and required annotation members
case ANNOTATION_TYPE_MEMBER -> throw new IllegalArgumentException("unsupported member kind");
case ANNOTATION_TYPE_MEMBER_OPTIONAL -> ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY;
case ANNOTATION_TYPE_MEMBER_REQUIRED -> ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY;
case PROPERTIES -> PROPERTY_SUMMARY;

@ -389,19 +389,9 @@ public class Navigation {
if (documentedPage == PageMode.CLASS) {
List<Content> listContents = new ArrayList<>();
VisibleMemberTable vmt = configuration.getVisibleMemberTable((TypeElement) element);
if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
// Handle annotation interfaces separately as required and optional elements
// share a combined details section.
addTypeDetailLink(FIELDS, !vmt.getVisibleMembers(FIELDS).isEmpty(), listContents);
boolean hasAnnotationElements =
!vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_OPTIONAL).isEmpty()
|| !vmt.getVisibleMembers(ANNOTATION_TYPE_MEMBER_REQUIRED).isEmpty();
addTypeDetailLink(ANNOTATION_TYPE_MEMBER_REQUIRED, hasAnnotationElements, listContents);
} else {
Set<VisibleMemberTable.Kind> detailSet = VisibleMemberTable.Kind.forDetailsOf(element.getKind());
for (VisibleMemberTable.Kind kind : detailSet) {
addTypeDetailLink(kind, !vmt.getVisibleMembers(kind).isEmpty(), listContents);
}
Set<VisibleMemberTable.Kind> detailSet = VisibleMemberTable.Kind.forDetailsOf(element.getKind());
for (VisibleMemberTable.Kind kind : detailSet) {
addTypeDetailLink(kind, !vmt.getVisibleMembers(kind).isEmpty(), listContents);
}
if (!listContents.isEmpty()) {
if (nested) {
@ -432,10 +422,8 @@ public class Navigation {
case FIELDS -> links.createLink(HtmlIds.FIELD_DETAIL, contents.navField, link);
case METHODS -> links.createLink(HtmlIds.METHOD_DETAIL, contents.navMethod, link);
case PROPERTIES -> links.createLink(HtmlIds.PROPERTY_DETAIL, contents.navProperty, link);
case ANNOTATION_TYPE_MEMBER_REQUIRED,
ANNOTATION_TYPE_MEMBER_OPTIONAL ->
links.createLink(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL,
contents.navAnnotationTypeMember, link);
case ANNOTATION_TYPE_MEMBER -> links.createLink(HtmlIds.ANNOTATION_TYPE_ELEMENT_DETAIL,
contents.navAnnotationTypeMember, link);
default -> Text.EMPTY;
});
}

@ -254,7 +254,8 @@ public class SummaryListWriter<L extends SummaryAPIListBuilder> extends SubWrite
case ENUM_CONSTANT -> new EnumConstantWriterImpl(this);
case RECORD_COMPONENT ->
throw new AssertionError("Record components are not supported by SummaryListWriter!");
default -> new AnnotationTypeOptionalMemberWriterImpl(this, null);
default ->
throw new UnsupportedOperationException("Unsupported element kind: " + e.getKind());
};
return writer.getSummaryLink(e);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -31,8 +31,6 @@ import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter;
import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
@ -80,19 +78,27 @@ public class WriterFactoryImpl implements WriterFactory {
}
@Override
public AnnotationTypeOptionalMemberWriter getAnnotationTypeOptionalMemberWriter(
public AnnotationTypeMemberWriterImpl getAnnotationTypeMemberWriter(
ClassWriter classWriter) {
TypeElement te = classWriter.getTypeElement();
return new AnnotationTypeOptionalMemberWriterImpl(
(ClassWriterImpl) classWriter, te);
return new AnnotationTypeMemberWriterImpl(
(ClassWriterImpl) classWriter, te, AnnotationTypeMemberWriterImpl.Kind.ANY);
}
@Override
public AnnotationTypeRequiredMemberWriter getAnnotationTypeRequiredMemberWriter(
public AnnotationTypeMemberWriterImpl getAnnotationTypeOptionalMemberWriter(
ClassWriter classWriter) {
TypeElement te = classWriter.getTypeElement();
return new AnnotationTypeRequiredMemberWriterImpl(
(ClassWriterImpl) classWriter, te);
return new AnnotationTypeMemberWriterImpl(
(ClassWriterImpl) classWriter, te, AnnotationTypeMemberWriterImpl.Kind.OPTIONAL);
}
@Override
public AnnotationTypeMemberWriterImpl getAnnotationTypeRequiredMemberWriter(
ClassWriter classWriter) {
TypeElement te = classWriter.getTypeElement();
return new AnnotationTypeMemberWriterImpl(
(ClassWriterImpl) classWriter, te, AnnotationTypeMemberWriterImpl.Kind.REQUIRED);
}
@Override
@ -132,11 +138,9 @@ public class WriterFactoryImpl implements WriterFactory {
case ENUM_CONSTANTS:
return getEnumConstantWriter(classWriter);
case ANNOTATION_TYPE_MEMBER_OPTIONAL:
return (AnnotationTypeOptionalMemberWriterImpl)
getAnnotationTypeOptionalMemberWriter(classWriter);
return getAnnotationTypeOptionalMemberWriter(classWriter);
case ANNOTATION_TYPE_MEMBER_REQUIRED:
return (AnnotationTypeRequiredMemberWriterImpl)
getAnnotationTypeRequiredMemberWriter(classWriter);
return getAnnotationTypeRequiredMemberWriter(classWriter);
case FIELDS:
return getFieldWriter(classWriter);
case PROPERTIES:

@ -36,31 +36,31 @@ import javax.lang.model.element.Element;
* deletion without notice.</b>
*/
public interface AnnotationTypeRequiredMemberWriter extends MemberWriter {
public interface AnnotationTypeMemberWriter extends MemberWriter {
/**
* Add the annotation type member tree header.
* Adds the annotation type member tree header.
*
* @return content tree for the member tree header
*/
Content getMemberTreeHeader();
/**
* Add the annotation type details marker.
* Adds the annotation type details marker.
*
* @param memberDetails the content tree representing details marker
*/
void addAnnotationDetailsMarker(Content memberDetails);
/**
* Add the annotation type details tree header.
* Adds the annotation type details tree header.
*
* @return content tree for the annotation details header
*/
Content getAnnotationDetailsTreeHeader();
/**
* Get the annotation type documentation tree header.
* Gets the annotation type documentation tree header.
*
* @param member the annotation type being documented
* @return content tree for the annotation type documentation header
@ -68,7 +68,7 @@ public interface AnnotationTypeRequiredMemberWriter extends MemberWriter {
Content getAnnotationDocTreeHeader(Element member);
/**
* Get the annotation type details tree.
* Gets the annotation type details tree.
*
* @param annotationDetailsTreeHeader the content tree representing annotation type details header
* @param annotationDetailsTree the content tree representing annotation type details
@ -77,7 +77,7 @@ public interface AnnotationTypeRequiredMemberWriter extends MemberWriter {
Content getAnnotationDetails(Content annotationDetailsTreeHeader, Content annotationDetailsTree);
/**
* Get the signature for the given member.
* Gets the signature for the given member.
*
* @param member the member being documented
* @return content tree for the annotation type signature
@ -85,7 +85,7 @@ public interface AnnotationTypeRequiredMemberWriter extends MemberWriter {
Content getSignature(Element member);
/**
* Add the deprecated output for the given member.
* Adds the deprecated output for the given member.
*
* @param member the member being documented
* @param annotationDocTree content tree to which the deprecated information will be added
@ -93,15 +93,15 @@ public interface AnnotationTypeRequiredMemberWriter extends MemberWriter {
void addDeprecated(Element member, Content annotationDocTree);
/**
* Add the preview output for the given member.
* Adds the preview output for the given member.
*
* @param member the member being documented
* @param annotationDocTree content tree to which the preview information will be added
* @param contentTree content tree to which the preview information will be added
*/
void addPreview(Element member, Content contentTree);
/**
* Add the comments for the given member.
* Adds the comments for the given member.
*
* @param member the member being documented
* @param annotationDocTree the content tree to which the comments will be added
@ -109,10 +109,18 @@ public interface AnnotationTypeRequiredMemberWriter extends MemberWriter {
void addComments(Element member, Content annotationDocTree);
/**
* Add the tags for the given member.
* Adds the tags for the given member.
*
* @param member the member being documented
* @param annotationDocTree the content tree to which the tags will be added
*/
void addTags(Element member, Content annotationDocTree);
/**
* Adds the default value documentation if the member has one.
*
* @param member the member being documented
* @param annotationDocTree content tree to which the default value will be added
*/
void addDefaultValueInfo(Element member, Content annotationDocTree);
}

@ -1,49 +0,0 @@
/*
* Copyright (c) 2003, 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. 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;
import javax.lang.model.element.Element;
/**
* The interface for writing annotation type optional member output.
*
* <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>
*/
public interface AnnotationTypeOptionalMemberWriter extends
AnnotationTypeRequiredMemberWriter {
/**
* Add the the default value documentation.
*
* @param member the member being documented
* @param annotationDocTree content tree to which the default value will be added
*/
void addDefaultValueInfo(Element member, Content annotationDocTree);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -89,6 +89,16 @@ public interface WriterFactory {
*/
MethodWriter getMethodWriter(ClassWriter classWriter);
/**
* Return the annotation type member writer for a given annotation
* type, or null if this writer is not supported by the doclet.
*
* @param classWriter the writer for the annotation type being documented
* @return the member writer
*/
AnnotationTypeMemberWriter getAnnotationTypeMemberWriter(
ClassWriter classWriter);
/**
* Return the annotation type optional member writer for a given annotation
* type, or null if this writer is not supported by the doclet.
@ -96,7 +106,7 @@ public interface WriterFactory {
* @param classWriter the writer for the annotation type being documented
* @return the member writer
*/
AnnotationTypeOptionalMemberWriter getAnnotationTypeOptionalMemberWriter(
AnnotationTypeMemberWriter getAnnotationTypeOptionalMemberWriter(
ClassWriter classWriter);
/**
@ -106,7 +116,7 @@ public interface WriterFactory {
* @param classWriter the writer for the annotation type being documented
* @return the member writer
*/
AnnotationTypeRequiredMemberWriter getAnnotationTypeRequiredMemberWriter(
AnnotationTypeMemberWriter getAnnotationTypeRequiredMemberWriter(
ClassWriter classWriter);
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -94,7 +94,7 @@ public abstract class AbstractMemberBuilder extends AbstractBuilder {
* @param kind of members
* @return a list of members
*/
protected List<? extends Element> getVisibleMembers(Kind kind) {
protected List<Element> getVisibleMembers(Kind kind) {
return visibleMemberTable.getVisibleMembers(kind);
}
}

@ -29,13 +29,11 @@ import java.util.*;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.formats.html.AbstractMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.BaseOptions;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.DocletException;
import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable;
import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
@ -47,18 +45,17 @@ import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder {
public class AnnotationTypeMemberBuilder extends AbstractMemberBuilder {
/**
* The writer to output the member documentation.
*/
protected AnnotationTypeRequiredMemberWriter writer;
protected AnnotationTypeMemberWriter writer;
/**
* The list of members being documented.
*/
protected List<? extends Element> members;
protected List<Element> members;
/**
* The index of the current member that is being documented at this point
@ -72,15 +69,15 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder {
* @param context the build context.
* @param typeElement the class whose members are being documented.
* @param writer the doclet specific writer.
* @param memberType the kind of member this builder processes.
*/
protected AnnotationTypeRequiredMemberBuilder(Context context,
TypeElement typeElement,
AnnotationTypeRequiredMemberWriter writer,
VisibleMemberTable.Kind memberType) {
protected AnnotationTypeMemberBuilder(Context context,
TypeElement typeElement,
AnnotationTypeMemberWriter writer) {
super(context, typeElement);
this.writer = Objects.requireNonNull(writer);
this.members = getVisibleMembers(memberType);
// In contrast to the annotation interface member summaries the details generated
// by this builder share a single list for both required and optional members.
this.members = getVisibleMembers(ANNOTATION_TYPE_MEMBER);
}
@ -92,11 +89,11 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder {
* @param writer the doclet specific writer.
* @return an instance of this object
*/
public static AnnotationTypeRequiredMemberBuilder getInstance(
public static AnnotationTypeMemberBuilder getInstance(
Context context, TypeElement typeElement,
AnnotationTypeRequiredMemberWriter writer) {
return new AnnotationTypeRequiredMemberBuilder(context, typeElement,
writer, ANNOTATION_TYPE_MEMBER_REQUIRED);
AnnotationTypeMemberWriter writer) {
return new AnnotationTypeMemberBuilder(context, typeElement,
writer);
}
/**
@ -110,18 +107,7 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder {
@Override
public void build(Content contentTree) throws DocletException {
buildAnnotationTypeRequiredMember(contentTree);
}
/**
* Build the annotation type required member documentation.
*
* @param memberDetailsTree the content tree to which the documentation will be added
* @throws DocletException if there is a problem while building the documentation
*/
protected void buildAnnotationTypeRequiredMember(Content memberDetailsTree)
throws DocletException {
buildAnnotationTypeMember(memberDetailsTree);
buildAnnotationTypeMember(contentTree);
}
/**
@ -156,6 +142,7 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder {
buildPreviewInfo(annotationDocTree);
buildMemberComments(annotationDocTree);
buildTagInfo(annotationDocTree);
buildDefaultValueInfo(annotationDocTree);
}
/**
@ -206,13 +193,22 @@ public class AnnotationTypeRequiredMemberBuilder extends AbstractMemberBuilder {
writer.addTags(currentMember, annotationDocTree);
}
/**
* Build the default value for this optional member.
*
* @param annotationDocTree the content tree to which the documentation will be added
*/
protected void buildDefaultValueInfo(Content annotationDocTree) {
writer.addDefaultValueInfo(currentMember, annotationDocTree);
}
/**
* Return the annotation type required member writer for this builder.
*
* @return the annotation type required member constant writer for this
* builder.
*/
public AnnotationTypeRequiredMemberWriter getWriter() {
public AnnotationTypeMemberWriter getWriter() {
return writer;
}
}

@ -1,112 +0,0 @@
/*
* Copyright (c) 2003, 2020, 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 javax.lang.model.element.TypeElement;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter;
import jdk.javadoc.internal.doclets.toolkit.Content;
import jdk.javadoc.internal.doclets.toolkit.DocletException;
import static jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberTable.Kind.*;
/**
* Builds documentation for optional annotation type members.
*
* <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>
*/
public class AnnotationTypeOptionalMemberBuilder extends AnnotationTypeRequiredMemberBuilder {
/**
* Construct a new AnnotationTypeMemberBuilder.
*
* @param context the build context.
* @param typeElement the class whose members are being documented.
* @param writer the doclet specific writer.
*/
private AnnotationTypeOptionalMemberBuilder(Context context,
TypeElement typeElement,
AnnotationTypeOptionalMemberWriter writer) {
super(context, typeElement, writer, ANNOTATION_TYPE_MEMBER_OPTIONAL);
}
/**
* Construct a new AnnotationTypeMemberBuilder.
*
* @param context the build context.
* @param typeElement the class whose members are being documented.
* @param writer the doclet specific writer.
* @return the new AnnotationTypeMemberBuilder
*/
public static AnnotationTypeOptionalMemberBuilder getInstance(
Context context, TypeElement typeElement,
AnnotationTypeOptionalMemberWriter writer) {
return new AnnotationTypeOptionalMemberBuilder(context,
typeElement, writer);
}
@Override
public void build(Content contentTree) throws DocletException {
buildAnnotationTypeOptionalMember(contentTree);
}
/**
* Build the annotation type optional member documentation.
*
* @param memberDetailsTree the content tree to which the documentation will be added
* @throws DocletException if there is a problem while building the documentation
*/
protected void buildAnnotationTypeOptionalMember(Content memberDetailsTree)
throws DocletException {
buildAnnotationTypeMember(memberDetailsTree);
}
@Override
protected void buildAnnotationTypeMemberChildren(Content annotationDocTree) {
super.buildAnnotationTypeMemberChildren(annotationDocTree);
buildDefaultValueInfo(annotationDocTree);
}
/**
* Build the default value for this optional member.
*
* @param annotationDocTree the content tree to which the documentation will be added
*/
protected void buildDefaultValueInfo(Content annotationDocTree) {
((AnnotationTypeOptionalMemberWriter) writer).addDefaultValueInfo(currentMember,
annotationDocTree);
}
@Override
public AnnotationTypeRequiredMemberWriter getWriter() {
return writer;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -38,9 +38,6 @@ import jdk.javadoc.internal.doclets.toolkit.PropertyWriter;
import jdk.javadoc.internal.doclets.toolkit.WriterFactory;
import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
/**
* The factory for constructing builders.
*
@ -133,26 +130,11 @@ public class BuilderFactory {
* @return an instance of the annotation type member builder for the given
* annotation type.
*/
public AbstractMemberBuilder getAnnotationTypeOptionalMemberBuilder(
public AbstractMemberBuilder getAnnotationTypeMemberBuilder(
ClassWriter classWriter) {
return AnnotationTypeOptionalMemberBuilder.getInstance(context,
return AnnotationTypeMemberBuilder.getInstance(context,
classWriter.getTypeElement(),
writerFactory.getAnnotationTypeOptionalMemberWriter(classWriter));
}
/**
* Return an instance of the annotation type member builder for the given
* class.
*
* @param classWriter the writer for the enclosing annotation type
* @return an instance of the annotation type member builder for the given
* annotation type.
*/
public AbstractMemberBuilder getAnnotationTypeRequiredMemberBuilder(
ClassWriter classWriter) {
return AnnotationTypeRequiredMemberBuilder.getInstance(context,
classWriter.getTypeElement(),
writerFactory.getAnnotationTypeRequiredMemberWriter(classWriter));
writerFactory.getAnnotationTypeMemberWriter(classWriter));
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, 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
@ -324,8 +324,7 @@ public class ClassBuilder extends AbstractBuilder {
buildPropertyDetails(detailsList);
buildFieldDetails(detailsList);
buildConstructorDetails(detailsList);
buildAnnotationTypeRequiredMemberDetails(detailsList);
buildAnnotationTypeOptionalMemberDetails(detailsList);
buildAnnotationTypeMemberDetails(detailsList);
buildMethodDetails(detailsList);
classContentTree.add(writer.getMemberDetailsTree(detailsList));
@ -387,20 +386,9 @@ public class ClassBuilder extends AbstractBuilder {
* @param memberDetailsTree the content tree to which the documentation will be added
* @throws DocletException if there is a problem building the documentation
*/
protected void buildAnnotationTypeOptionalMemberDetails(Content memberDetailsTree)
protected void buildAnnotationTypeMemberDetails(Content memberDetailsTree)
throws DocletException {
builderFactory.getAnnotationTypeOptionalMemberBuilder(writer).build(memberDetailsTree);
}
/**
* Build the annotation type required member documentation.
*
* @param memberDetailsTree the content tree to which the documentation will be added
* @throws DocletException if there is a problem building the documentation
*/
protected void buildAnnotationTypeRequiredMemberDetails(Content memberDetailsTree)
throws DocletException {
builderFactory.getAnnotationTypeRequiredMemberBuilder(writer).build(memberDetailsTree);
builderFactory.getAnnotationTypeMemberBuilder(writer).build(memberDetailsTree);
}
/**

@ -103,8 +103,9 @@ public class VisibleMemberTable {
FIELDS,
CONSTRUCTORS,
METHODS,
ANNOTATION_TYPE_MEMBER_OPTIONAL,
ANNOTATION_TYPE_MEMBER,
ANNOTATION_TYPE_MEMBER_REQUIRED,
ANNOTATION_TYPE_MEMBER_OPTIONAL,
PROPERTIES;
private static final EnumSet<Kind> defaultSummarySet = EnumSet.of(
@ -112,11 +113,13 @@ public class VisibleMemberTable {
private static final EnumSet<Kind> enumSummarySet = EnumSet.of(
NESTED_CLASSES, ENUM_CONSTANTS, FIELDS, METHODS);
private static final EnumSet<Kind> annotationSummarySet = EnumSet.of(
FIELDS, ANNOTATION_TYPE_MEMBER_OPTIONAL, ANNOTATION_TYPE_MEMBER_REQUIRED);
FIELDS, ANNOTATION_TYPE_MEMBER_REQUIRED, ANNOTATION_TYPE_MEMBER_OPTIONAL);
private static final EnumSet<Kind> defaultDetailSet = EnumSet.of(
FIELDS, CONSTRUCTORS, METHODS);
private static final EnumSet<Kind> enumDetailSet = EnumSet.of(
ENUM_CONSTANTS, FIELDS, METHODS);
private static final EnumSet<Kind> annotationDetailSet = EnumSet.of(
FIELDS, ANNOTATION_TYPE_MEMBER);
/**
* {@return the set of possible member kinds for the summaries section of a type element}
@ -135,9 +138,11 @@ public class VisibleMemberTable {
* @param kind the kind of type element being documented
*/
public static Set<Kind> forDetailsOf(ElementKind kind) {
return kind == ElementKind.ENUM
? enumDetailSet
: defaultDetailSet;
return switch (kind) {
case ANNOTATION_TYPE -> annotationDetailSet;
case ENUM -> enumDetailSet;
default -> defaultDetailSet;
};
}
}
@ -213,7 +218,7 @@ public class VisibleMemberTable {
* @param kind the member kind
* @return a list of all visible members
*/
public List<? extends Element> getAllVisibleMembers(Kind kind) {
public List<Element> getAllVisibleMembers(Kind kind) {
ensureInitialized();
return visibleMembers.getOrDefault(kind, Collections.emptyList());
}
@ -225,7 +230,7 @@ public class VisibleMemberTable {
* @param p the predicate used to filter the output
* @return a list of visible enclosed members
*/
public List<? extends Element> getVisibleMembers(Kind kind, Predicate<Element> p) {
public List<Element> getVisibleMembers(Kind kind, Predicate<Element> p) {
ensureInitialized();
return visibleMembers.getOrDefault(kind, Collections.emptyList()).stream()
@ -240,7 +245,7 @@ public class VisibleMemberTable {
* @param kind the member kind
* @return a list of visible enclosed members
*/
public List<? extends Element> getVisibleMembers(Kind kind) {
public List<Element> getVisibleMembers(Kind kind) {
Predicate<Element> declaredAndLeafMembers = e -> {
TypeElement encl = utils.getEnclosingTypeElement(e);
return encl == te || utils.isUndocumentedEnclosure(encl);
@ -255,7 +260,7 @@ public class VisibleMemberTable {
*
* @return a list of visible enclosed members in this type
*/
public List<? extends Element> getMembers(Kind kind) {
public List<Element> getMembers(Kind kind) {
Predicate<Element> onlyLocallyDeclaredMembers = e -> utils.getEnclosingTypeElement(e) == te;
return getVisibleMembers(kind, onlyLocallyDeclaredMembers);
}
@ -777,6 +782,7 @@ public class VisibleMemberTable {
case METHOD:
if (utils.isAnnotationType(te)) {
ExecutableElement ee = (ExecutableElement) e;
addMember(e, Kind.ANNOTATION_TYPE_MEMBER);
addMember(e, ee.getDefaultValue() == null
? Kind.ANNOTATION_TYPE_MEMBER_REQUIRED
: Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL);

@ -24,7 +24,7 @@
/*
* @test
* @bug 4973609 8015249 8025633 8026567 6469561 8071982 8162363 8182765 8223364
8242056 8261976
8242056 8261976 8223358
* @summary Make sure that annotation types with 0 members does not have
* extra HR tags.
* @library ../../lib
@ -72,27 +72,84 @@ public class TestAnnotationTypes extends JavadocTester {
checkOutput("pkg/AnnotationType.html", true,
"""
<ul class="sub-nav-list">
<li>Summary:&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>""",
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#annotation-interface-required-element-summary">Required</a>&nbsp;|&nbsp;</li>
<li><a href="#annotation-interface-optional-element-summary">Optional</a></li>
</ul>""",
"""
<ul class="sub-nav-list">
<li>Detail:&nbsp;</li>
<li>Field&nbsp;|&nbsp;</li>""");
<li>Field&nbsp;|&nbsp;</li>
<li><a href="#annotation-interface-element-detail">Element</a></li>
</ul>""");
checkOutput("pkg/AnnotationType.html", true,
"<!-- ============ ANNOTATION INTERFACE MEMBER DETAIL =========== -->",
"<ul class=\"member-list\">",
"<li>",
"""
<section class="details" id="annotation-interface-element-detail">""",
"<h2>Element Details</h2>",
"</a>",
"<ul class=\"member-list\">",
"<li>",
"""
<section class="detail" id="value()">""",
"<h3>value</h3>\n",
"""
<div class="member-signature"><span class="return-type">int</span>&nbsp;<span class="element-name">value</span></div>""");
"""
<section class="summary">
<ul class="summary-list">
<!-- =========== ANNOTATION INTERFACE REQUIRED MEMBER SUMMARY =========== -->
<li>
<section class="member-summary" id="annotation-interface-required-element-summary">
<h2>Required Element Summary</h2>
<div class="caption"><span>Required Elements</span></div>
<div class="summary-table three-column-summary">
<div class="table-header col-first">Modifier and Type</div>
<div class="table-header col-second">Required Element</div>
<div class="table-header col-last">Description</div>
<div class="col-first even-row-color"><code>int</code></div>
<div class="col-second even-row-color"><code><a href="#value()" class="member-name-link">value</a></code></div>
<div class="col-last even-row-color">&nbsp;</div>
</div>
</section>
</li>
<!-- =========== ANNOTATION INTERFACE OPTIONAL MEMBER SUMMARY =========== -->
<li>
<section class="member-summary" id="annotation-interface-optional-element-summary">
<h2>Optional Element Summary</h2>
<div class="caption"><span>Optional Elements</span></div>
<div class="summary-table three-column-summary">
<div class="table-header col-first">Modifier and Type</div>
<div class="table-header col-second">Optional Element</div>
<div class="table-header col-last">Description</div>
<div class="col-first even-row-color"><code>java.lang.String</code></div>
<div class="col-second even-row-color"><code><a href="#optional()" class="member-name-link">optional</a></code></div>
<div class="col-last even-row-color">&nbsp;</div>
</div>
</section>
</li>
</ul>
</section>""",
"""
<section class="details" id="annotation-interface-element-detail">
<ul class="details-list">
<!-- ============ ANNOTATION INTERFACE MEMBER DETAIL =========== -->
<li>
<section class="member-details">
<h2>Element Details</h2>
<ul class="member-list">
<li>
<section class="detail" id="value()">
<h3>value</h3>
<div class="member-signature"><span class="return-type">int</span>&nbsp;<span class="element-name">value</span></div>
</section>
</li>
<li>
<section class="detail" id="optional()">
<h3>optional</h3>
<div class="member-signature"><span class="return-type">java.lang.String</span>&nbsp;<span class="element-name">optional</span></div>
<dl class="notes">
<dt>Default:</dt>
<dd>""</dd>
</dl>
</section>
</li>
</ul>
</section>
</li>
</ul>
</section>""");
checkOutput("pkg/AnnotationType.html", false,
"""

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2021, 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
@ -30,4 +30,5 @@ import java.lang.annotation.*;
*/
@Documented public @interface AnnotationType {
int value();
String optional() default "";
}