Skip to content
Permalink
Browse files
8223358: Incorrect HTML structure in annotation pages
Reviewed-by: jjg
  • Loading branch information
hns committed Nov 9, 2021
1 parent a60e912 commit 055de6f566208b168818be1dc3ad29cdb9caa1cf
Showing 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.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 Content getMemberTreeHeader() {
@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 void addAnnotationDetailsMarker(Content memberDetails) {
@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,23 +186,36 @@ public Content getAnnotationDetails(Content annotationDetailsTreeHeader, Content
@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);
}

/**
* 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 @@ private TypeMirror getType(Element member) {
? 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);
}
}
}
}

This file was deleted.

@@ -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 @@ static HtmlId forMemberSummary(VisibleMemberTable.Kind kind) {
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 @@ private void addDetailLinks(Content tree, boolean nested) {
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 @@ protected void addTypeDetailLink(VisibleMemberTable.Kind kind, boolean link, Lis
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 @@ protected Content getSummaryLink(Element e) {
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 comment on commit 055de6f

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 055de6f Nov 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.