Skip to content

Commit 2321722

Browse files
committed
8346109: Create JDK taglet for additional preview notes
Reviewed-by: ihse, liach, rriggs
1 parent 9ead2b7 commit 2321722

File tree

8 files changed

+318
-60
lines changed

8 files changed

+318
-60
lines changed

make/Docs.gmk

+2
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ JAVADOC_TAGS := \
7979
-tag see \
8080
-taglet build.tools.taglet.ExtLink \
8181
-taglet build.tools.taglet.Incubating \
82+
-taglet build.tools.taglet.PreviewNote \
83+
--preview-note-tag previewNote \
8284
-tagletpath $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
8385
$(CUSTOM_JAVADOC_TAGS) \
8486
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package build.tools.taglet;
27+
28+
import java.util.EnumSet;
29+
import java.util.List;
30+
import java.util.Set;
31+
32+
33+
import javax.lang.model.element.Element;
34+
import javax.tools.Diagnostic;
35+
36+
37+
import com.sun.source.doctree.DocTree;
38+
import com.sun.source.doctree.UnknownInlineTagTree;
39+
import jdk.javadoc.doclet.Doclet;
40+
import jdk.javadoc.doclet.DocletEnvironment;
41+
import jdk.javadoc.doclet.Reporter;
42+
import jdk.javadoc.doclet.StandardDoclet;
43+
import jdk.javadoc.doclet.Taglet;
44+
45+
import static com.sun.source.doctree.DocTree.Kind.UNKNOWN_INLINE_TAG;
46+
47+
/**
48+
* An inline tag to insert a note formatted as preview note.
49+
* The tag can be used as follows:
50+
*
51+
* <pre>
52+
* {&commat;previewNote jep-number [Preview note heading]}
53+
* Preview note content
54+
* {&commat;previewNote}
55+
* </pre>
56+
*
57+
*/
58+
public class PreviewNote implements Taglet {
59+
60+
static final String TAG_NAME = "previewNote";
61+
Reporter reporter = null;
62+
63+
@Override
64+
public void init(DocletEnvironment env, Doclet doclet) {
65+
if (doclet instanceof StandardDoclet stdoclet) {
66+
reporter = stdoclet.getReporter();
67+
}
68+
}
69+
70+
/**
71+
* Returns the set of locations in which the tag may be used.
72+
*/
73+
@Override
74+
public Set<Location> getAllowedLocations() {
75+
return EnumSet.allOf(Taglet.Location.class);
76+
}
77+
78+
@Override
79+
public boolean isInlineTag() {
80+
return true;
81+
}
82+
83+
@Override
84+
public String getName() {
85+
return TAG_NAME;
86+
}
87+
88+
@Override
89+
public String toString(List<? extends DocTree> tags, Element elem) {
90+
91+
for (DocTree tag : tags) {
92+
if (tag.getKind() == UNKNOWN_INLINE_TAG) {
93+
UnknownInlineTagTree inlineTag = (UnknownInlineTagTree) tag;
94+
String[] content = inlineTag.getContent().toString().trim().split("\\s+", 2);
95+
if (!content[0].isBlank()) {
96+
StringBuilder sb = new StringBuilder("""
97+
<div class="preview-block" style="margin-top:10px; display:block; max-width:max-content;">
98+
""");
99+
if (content.length == 2) {
100+
sb.append("""
101+
<div class="preview-label">
102+
""")
103+
.append(content[1])
104+
.append("""
105+
</div>
106+
""");
107+
}
108+
sb.append("""
109+
<div class="preview-comment">
110+
""");
111+
return sb.toString();
112+
} else {
113+
return """
114+
</div>
115+
</div>
116+
""";
117+
}
118+
}
119+
}
120+
121+
if (reporter == null) {
122+
throw new IllegalArgumentException("@" + TAG_NAME + " taglet content must be begin or end");
123+
}
124+
reporter.print(Diagnostic.Kind.ERROR, "@" + TAG_NAME + " taglet content must be begin or end");
125+
return "";
126+
}
127+
}

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

+17
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import jdk.javadoc.internal.doclets.toolkit.util.PreviewAPIListBuilder;
3939
import jdk.javadoc.internal.html.Content;
4040
import jdk.javadoc.internal.html.ContentBuilder;
41+
import jdk.javadoc.internal.html.HtmlId;
4142
import jdk.javadoc.internal.html.HtmlStyle;
4243
import jdk.javadoc.internal.html.HtmlTree;
4344
import jdk.javadoc.internal.html.Text;
@@ -96,6 +97,22 @@ protected void addContentSelectors(Content target) {
9697
}
9798
}
9899

100+
@Override
101+
protected void addExtraSection(Content content) {
102+
var notes = builder.getElementNotes();
103+
if (!notes.isEmpty()) {
104+
addSummaryAPI(notes, HtmlId.of("preview-api-notes"),
105+
"doclet.Preview_Notes_Elements", "doclet.Element", content);
106+
}
107+
}
108+
109+
@Override
110+
protected void addExtraIndexLink(Content target) {
111+
if (!builder.getElementNotes().isEmpty()) {
112+
addIndexLink(HtmlId.of("preview-api-notes"), "doclet.Preview_Notes", target);
113+
}
114+
}
115+
99116
@Override
100117
protected void addComments(Element e, Content desc) {
101118
List<? extends DocTree> tags = utils.getFirstSentenceTrees(e);

src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties

+2
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ doclet.Preview_API_Checkbox_Toggle_All=Toggle all
136136
doclet.Preview_JEP_URL=https://openjdk.org/jeps/{0}
137137
doclet.Preview_Label=Preview
138138
doclet.Preview_Mark=PREVIEW
139+
doclet.Preview_Notes=Preview API Notes
140+
doclet.Preview_Notes_Elements=Elements containing Preview Notes
139141
doclet.Restricted_Methods=Restricted Methods
140142
doclet.Restricted_Mark=RESTRICTED
141143
doclet.searchTag=Search Tag

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

+22
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,14 @@ public enum ModularityMismatchPolicy {
236236
*/
237237
private boolean noTimestamp = false;
238238

239+
240+
/**
241+
* Argument for command-line option {@code --preview-note-tag}.
242+
* If set, the JavaDoc inline tag with the given name is considered
243+
* a preview note and added to the preview API page.
244+
*/
245+
private String previewNoteTag = null;
246+
239247
/**
240248
* Argument for command-line option {@code -quiet}.
241249
* Suppress all messages
@@ -549,6 +557,14 @@ public boolean process(String opt, List<String> args) {
549557
}
550558
},
551559

560+
new Hidden(resources, "--preview-note-tag", 1) {
561+
@Override
562+
public boolean process(String option, List<String> args) {
563+
previewNoteTag = args.getFirst();
564+
return true;
565+
}
566+
},
567+
552568
new Hidden(resources, "-quiet") {
553569
@Override
554570
public boolean process(String opt, List<String> args) {
@@ -940,6 +956,12 @@ public boolean noTimestamp() {
940956
return noTimestamp;
941957
}
942958

959+
/**
960+
* Argument for command-line option {@code --preview-note-tag}.
961+
* Name of inline tag for preview notes.
962+
*/
963+
public String previewNoteTag() { return previewNoteTag; }
964+
943965
/**
944966
* Argument for command-line option {@code -quiet}.
945967
* Suppress all messages

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

-28
Original file line numberDiff line numberDiff line change
@@ -396,34 +396,6 @@ public boolean accessInternalAPI() {
396396
return compilerOptions.isSet("accessInternalAPI");
397397
}
398398

399-
/**
400-
* Returns a map containing {@code jdk.internal.javac.PreviewFeature.JEP} element values associated with the
401-
* {@code jdk.internal.javac.PreviewFeature.Feature} enum constant identified by {@code feature}.
402-
*
403-
* This method uses internal javac features (although only reflectively).
404-
*
405-
* @param feature the name of the PreviewFeature.Feature enum value
406-
* @return the map of PreviewFeature.JEP annotation element values, or an empty map
407-
*/
408-
public Map<String, Object> getJepInfo(String feature) {
409-
TypeElement featureType = elementUtils.getTypeElement("jdk.internal.javac.PreviewFeature.Feature");
410-
TypeElement jepType = elementUtils.getTypeElement("jdk.internal.javac.PreviewFeature.JEP");
411-
var featureVar = featureType.getEnclosedElements().stream()
412-
.filter(e -> feature.equals(e.getSimpleName().toString())).findFirst();
413-
if (featureVar.isPresent()) {
414-
for (AnnotationMirror anno : featureVar.get().getAnnotationMirrors()) {
415-
if (anno.getAnnotationType().asElement().equals(jepType)) {
416-
return anno.getElementValues().entrySet()
417-
.stream()
418-
.collect(Collectors.toMap(
419-
e -> e.getKey().getSimpleName().toString(),
420-
e -> e.getValue().getValue()));
421-
}
422-
}
423-
}
424-
return Map.of();
425-
}
426-
427399
/*
428400
* If a similar query is ever added to javax.lang.model, use that instead.
429401
*/

0 commit comments

Comments
 (0)