Skip to content

Commit a9d287a

Browse files
committed
8260388: Listing (sub)packages at package level of API documentation
Reviewed-by: jjg
1 parent 8120064 commit a9d287a

File tree

8 files changed

+357
-1
lines changed

8 files changed

+357
-1
lines changed

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Contents.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ public class Contents {
162162
public final Content record;
163163
public final Content recordComponents;
164164
public final Content referencedIn;
165+
public final Content relatedPackages;
165166
public final Content returns;
166167
public final Content seeAlso;
167168
public final Content serializedForm;
@@ -311,6 +312,7 @@ public class Contents {
311312
record = getContent("doclet.RecordClass");
312313
recordComponents = getContent("doclet.RecordComponents");
313314
referencedIn = getContent("doclet.ReferencedIn");
315+
relatedPackages = getContent("doclet.Related_Packages");
314316
returns = getContent("doclet.Returns");
315317
seeAlso = getContent("doclet.See_Also");
316318
serializedForm = getContent("doclet.Serialized_Form");

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ public Content getSummariesList() {
162162
return new HtmlTree(TagName.UL).setStyle(HtmlStyle.summaryList);
163163
}
164164

165+
@Override
166+
public void addRelatedPackagesSummary(List<PackageElement> relatedPackages, Content summaryContentTree) {
167+
boolean showModules = configuration.showModules && hasRelatedPackagesInOtherModules(relatedPackages);
168+
TableHeader tableHeader= showModules
169+
? new TableHeader(contents.moduleLabel, contents.packageLabel, contents.descriptionLabel)
170+
: new TableHeader(contents.packageLabel, contents.descriptionLabel);
171+
addPackageSummary(relatedPackages, contents.relatedPackages, tableHeader,
172+
summaryContentTree, showModules);
173+
}
174+
165175
@Override
166176
public void addInterfaceSummary(SortedSet<TypeElement> interfaces, Content summaryContentTree) {
167177
TableHeader tableHeader= new TableHeader(contents.interfaceLabel, contents.descriptionLabel);
@@ -235,6 +245,49 @@ public void addClassesSummary(SortedSet<TypeElement> classes, String label,
235245
}
236246
}
237247

248+
public void addPackageSummary(List<PackageElement> packages, Content label,
249+
TableHeader tableHeader, Content summaryContentTree,
250+
boolean showModules) {
251+
if (!packages.isEmpty()) {
252+
Table table = new Table(HtmlStyle.summaryTable)
253+
.setCaption(label)
254+
.setHeader(tableHeader);
255+
if (showModules) {
256+
table.setColumnStyles(HtmlStyle.colPlain, HtmlStyle.colFirst, HtmlStyle.colLast);
257+
} else {
258+
table.setColumnStyles(HtmlStyle.colFirst, HtmlStyle.colLast);
259+
}
260+
261+
for (PackageElement pkg : packages) {
262+
Content packageLink = getPackageLink(pkg, Text.of(pkg.getQualifiedName()));
263+
Content moduleLink = HtmlTree.EMPTY;
264+
if (showModules) {
265+
ModuleElement module = (ModuleElement) pkg.getEnclosingElement();
266+
if (module != null && !module.isUnnamed()) {
267+
moduleLink = getModuleLink(module, Text.of(module.getQualifiedName()));
268+
}
269+
}
270+
ContentBuilder description = new ContentBuilder();
271+
addPreviewSummary(pkg, description);
272+
if (utils.isDeprecated(pkg)) {
273+
description.add(getDeprecatedPhrase(pkg));
274+
List<? extends DeprecatedTree> tags = utils.getDeprecatedTrees(pkg);
275+
if (!tags.isEmpty()) {
276+
addSummaryDeprecatedComment(pkg, tags.get(0), description);
277+
}
278+
} else {
279+
addSummaryComment(pkg, description);
280+
}
281+
if (showModules) {
282+
table.addRow(moduleLink, packageLink, description);
283+
} else {
284+
table.addRow(packageLink, description);
285+
}
286+
}
287+
summaryContentTree.add(HtmlTree.LI(table));
288+
}
289+
}
290+
238291
@Override
239292
public void addPackageDescription(Content packageContentTree) {
240293
addPreviewInfo(packageElement, packageContentTree);
@@ -282,4 +335,9 @@ public void printDocument(Content contentTree) throws DocFileIOException {
282335
public Content getPackageSummary(Content summaryContentTree) {
283336
return HtmlTree.SECTION(HtmlStyle.summary, summaryContentTree);
284337
}
338+
339+
private boolean hasRelatedPackagesInOtherModules(List<PackageElement> relatedPackages) {
340+
final ModuleElement module = (ModuleElement) packageElement.getEnclosingElement();
341+
return relatedPackages.stream().anyMatch(pkg -> module != pkg.getEnclosingElement());
342+
}
285343
}

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,12 @@ public enum HtmlStyle {
438438
*/
439439
colSummaryItemName,
440440

441+
/**
442+
* The class of the cells in a table column used to display additional
443+
* information without any particular style.
444+
*/
445+
colPlain,
446+
441447
/**
442448
* The class of the second column of cells in a table.
443449
* This is typically the column that defines the name of a field or the

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/PackageSummaryWriter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@
2525

2626
package jdk.javadoc.internal.doclets.toolkit;
2727

28+
import java.util.List;
2829
import java.util.SortedSet;
2930

31+
import javax.lang.model.element.PackageElement;
3032
import javax.lang.model.element.TypeElement;
3133

3234
import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -63,6 +65,14 @@ public interface PackageSummaryWriter {
6365
*/
6466
Content getSummariesList();
6567

68+
/**
69+
* Adds the table of related packages to the documentation tree.
70+
*
71+
* @param relatedPackages the interfaces to document.
72+
* @param summaryContentTree the content tree to which the summaries will be added
73+
*/
74+
void addRelatedPackagesSummary(List<PackageElement> relatedPackages, Content summaryContentTree);
75+
6676
/**
6777
* Adds the table of interfaces to the documentation tree.
6878
*

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/PackageSummaryBuilder.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,13 @@
2525

2626
package jdk.javadoc.internal.doclets.toolkit.builders;
2727

28+
import java.util.ArrayList;
29+
import java.util.List;
2830
import java.util.Set;
2931
import java.util.SortedSet;
32+
import java.util.function.Predicate;
33+
import java.util.regex.Pattern;
34+
import java.util.stream.Collectors;
3035

3136
import javax.lang.model.element.PackageElement;
3237
import javax.lang.model.element.TypeElement;
@@ -57,6 +62,10 @@ public class PackageSummaryBuilder extends AbstractBuilder {
5762
*/
5863
private final PackageSummaryWriter packageWriter;
5964

65+
// Maximum number of subpackages and sibling packages to list in related packages table
66+
private final static int MAX_SUBPACKAGES = 20;
67+
private final static int MAX_SIBLING_PACKAGES = 5;
68+
6069
/**
6170
* Construct a new PackageSummaryBuilder.
6271
*
@@ -146,6 +155,7 @@ protected void buildContent() throws DocletException {
146155
protected void buildSummary(Content packageContentTree) throws DocletException {
147156
Content summariesList = packageWriter.getSummariesList();
148157

158+
buildRelatedPackagesSummary(summariesList);
149159
buildInterfaceSummary(summariesList);
150160
buildClassSummary(summariesList);
151161
buildEnumSummary(summariesList);
@@ -157,6 +167,18 @@ protected void buildSummary(Content packageContentTree) throws DocletException {
157167
packageContentTree.add(packageWriter.getPackageSummary(summariesList));
158168
}
159169

170+
/**
171+
* Builds a list of "nearby" packages (subpackages, super and sibling packages).
172+
*
173+
* @param summariesList the list of summaries to which the summary will be added
174+
*/
175+
protected void buildRelatedPackagesSummary(Content summariesList) {
176+
List<PackageElement> packages = findRelatedPackages();
177+
if (!packages.isEmpty()) {
178+
packageWriter.addRelatedPackagesSummary(packages, summariesList);
179+
}
180+
}
181+
160182
/**
161183
* Builds the summary for any interfaces in this package.
162184
*
@@ -291,4 +313,40 @@ protected void buildPackageTags(Content packageContentTree) {
291313
}
292314
packageWriter.addPackageTags(packageContentTree);
293315
}
316+
317+
private List<PackageElement> findRelatedPackages() {
318+
String pkgName = packageElement.getQualifiedName().toString();
319+
320+
// always add super package
321+
int lastdot = pkgName.lastIndexOf('.');
322+
String pkgPrefix = lastdot > 0 ? pkgName.substring(0, lastdot) : null;
323+
List<PackageElement> packages = new ArrayList<>(
324+
filterPackages(p -> p.getQualifiedName().toString().equals(pkgPrefix)));
325+
326+
// add subpackages unless there are very many of them
327+
Pattern subPattern = Pattern.compile(pkgName.replace(".", "\\.") + "\\.\\w+");
328+
List<PackageElement> subpackages = filterPackages(
329+
p -> subPattern.matcher(p.getQualifiedName().toString()).matches());
330+
if (subpackages.size() <= MAX_SUBPACKAGES) {
331+
packages.addAll(subpackages);
332+
}
333+
334+
// only add sibling packages if we are beneath threshold, and number of siblings is beneath threshold as well
335+
if (pkgPrefix != null && packages.size() <= MAX_SIBLING_PACKAGES) {
336+
Pattern siblingPattern = Pattern.compile(pkgPrefix.replace(".", "\\.") + "\\.\\w+");
337+
338+
List<PackageElement> siblings = filterPackages(
339+
p -> siblingPattern.matcher(p.getQualifiedName().toString()).matches());
340+
if (siblings.size() <= MAX_SIBLING_PACKAGES) {
341+
packages.addAll(siblings);
342+
}
343+
}
344+
return packages;
345+
}
346+
347+
private List<PackageElement> filterPackages(Predicate<? super PackageElement> filter) {
348+
return configuration.packages.stream()
349+
.filter(p -> p != packageElement && filter.test(p))
350+
.collect(Collectors.toList());
351+
}
294352
}

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ doclet.Exception_Summary=Exception Summary
133133
doclet.Error_Summary=Error Summary
134134
doclet.Class_Summary=Class Summary
135135
doclet.Nested_Class_Summary=Nested Class Summary
136+
doclet.Related_Packages=Related Packages
136137
doclet.Annotation_Type_Optional_Member_Summary=Optional Element Summary
137138
doclet.Annotation_Type_Required_Member_Summary=Required Element Summary
138139
doclet.Field_Summary=Field Summary

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3175,7 +3175,7 @@ public boolean isPreviewAPI(Element el) {
31753175
boolean parentPreviewAPI = false;
31763176
Element enclosing = el.getEnclosingElement();
31773177
if (enclosing != null && (enclosing.getKind().isClass() || enclosing.getKind().isInterface())) {
3178-
parentPreviewAPI = configuration.workArounds.isPreviewAPI(el.getEnclosingElement());
3178+
parentPreviewAPI = configuration.workArounds.isPreviewAPI(enclosing);
31793179
}
31803180
boolean previewAPI = configuration.workArounds.isPreviewAPI(el);
31813181
return !parentPreviewAPI && previewAPI;

0 commit comments

Comments
 (0)