8219958: Automatically load taglets from a jar file
Reviewed-by: jjg
This commit is contained in:
parent
95b189916f
commit
1c0f35a5b4
src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit
test/langtools/jdk/javadoc/doclet/testAutoLoadTaglets
@ -837,39 +837,47 @@ public abstract class BaseConfiguration {
|
||||
tagletManager = tagletManager == null ?
|
||||
new TagletManager(nosince, showversion, showauthor, javafx, this) :
|
||||
tagletManager;
|
||||
for (List<String> args : customTagStrs) {
|
||||
if (args.get(0).equals("-taglet")) {
|
||||
tagletManager.addCustomTag(args.get(1), getFileManager(), tagletpath);
|
||||
continue;
|
||||
}
|
||||
List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3);
|
||||
switch (tokens.size()) {
|
||||
case 1:
|
||||
String tagName = args.get(1);
|
||||
if (tagletManager.isKnownCustomTag(tagName)) {
|
||||
//reorder a standard tag
|
||||
tagletManager.addNewSimpleCustomTag(tagName, null, "");
|
||||
} else {
|
||||
//Create a simple tag with the heading that has the same name as the tag.
|
||||
StringBuilder heading = new StringBuilder(tagName + ":");
|
||||
heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
|
||||
tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
//Add simple taglet without heading, probably to excluding it in the output.
|
||||
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), "");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1));
|
||||
break;
|
||||
|
||||
default:
|
||||
Messages messages = getMessages();
|
||||
messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1));
|
||||
JavaFileManager fileManager = getFileManager();
|
||||
Messages messages = getMessages();
|
||||
try {
|
||||
tagletManager.initTagletPath(fileManager, tagletpath);
|
||||
tagletManager.loadTaglets(fileManager);
|
||||
|
||||
for (List<String> args : customTagStrs) {
|
||||
if (args.get(0).equals("-taglet")) {
|
||||
tagletManager.addCustomTag(args.get(1), fileManager);
|
||||
continue;
|
||||
}
|
||||
List<String> tokens = tokenize(args.get(1), TagletManager.SIMPLE_TAGLET_OPT_SEPARATOR, 3);
|
||||
switch (tokens.size()) {
|
||||
case 1:
|
||||
String tagName = args.get(1);
|
||||
if (tagletManager.isKnownCustomTag(tagName)) {
|
||||
//reorder a standard tag
|
||||
tagletManager.addNewSimpleCustomTag(tagName, null, "");
|
||||
} else {
|
||||
//Create a simple tag with the heading that has the same name as the tag.
|
||||
StringBuilder heading = new StringBuilder(tagName + ":");
|
||||
heading.setCharAt(0, Character.toUpperCase(tagName.charAt(0)));
|
||||
tagletManager.addNewSimpleCustomTag(tagName, heading.toString(), "a");
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
//Add simple taglet without heading, probably to excluding it in the output.
|
||||
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(1), "");
|
||||
break;
|
||||
|
||||
case 3:
|
||||
tagletManager.addNewSimpleCustomTag(tokens.get(0), tokens.get(2), tokens.get(1));
|
||||
break;
|
||||
|
||||
default:
|
||||
messages.error("doclet.Error_invalid_custom_tag_argument", args.get(1));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
messages.error("doclet.taglet_could_not_set_location", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,8 @@ doclet.Notice_taglet_overriden=Note: Custom tags that override standard tags: {0
|
||||
doclet.Notice_taglet_conflict_warn=Note: Custom tags that could override future standard tags: {0}. To avoid potential overrides, use at least one period character (.) in custom tag names.
|
||||
doclet.Error_taglet_not_registered=Error - Exception {0} thrown while trying to register Taglet {1}...
|
||||
doclet.Error_invalid_custom_tag_argument=Error - {0} is an invalid argument to the -tag option...
|
||||
doclet.taglet_could_not_set_location = Could not set the taglet path: {0}
|
||||
doclet.not_standard_file_manager = Cannot set taglet path; the file manager is not a StandardJavaFileManager
|
||||
doclet.Author=Author:
|
||||
doclet.DefaultValue=Default value:
|
||||
doclet.PropertyDescription=Property description:
|
||||
|
@ -204,44 +204,77 @@ public class TagletManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new {@code Taglet}. Print a message to indicate whether or not
|
||||
* Initializes the location TAGLET_PATH which is used to locate the custom taglets.
|
||||
* @param fileManager the filemanager to load classes and resources.
|
||||
* @param tagletPath the path to the custom taglet.
|
||||
* @throws IOException if an error occurs while setting the location.
|
||||
*/
|
||||
public void initTagletPath(JavaFileManager fileManager, String tagletPath) throws IOException {
|
||||
if (fileManager instanceof StandardJavaFileManager) {
|
||||
StandardJavaFileManager sfm = (StandardJavaFileManager)fileManager;
|
||||
if (tagletPath != null) {
|
||||
List<File> paths = new ArrayList<>();
|
||||
for (String pathname : tagletPath.split(File.pathSeparator)) {
|
||||
paths.add(new File(pathname));
|
||||
}
|
||||
sfm.setLocation(TAGLET_PATH, paths);
|
||||
} else if (!sfm.hasLocation(TAGLET_PATH)) {
|
||||
sfm.setLocation(TAGLET_PATH, Collections.emptyList());
|
||||
}
|
||||
} else if (tagletPath != null) {
|
||||
messages.error("doclet.not_standard_file_manager");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new {@code Taglet}. Print a message to indicate whether or not
|
||||
* the Taglet was registered properly.
|
||||
* @param classname the name of the class representing the custom tag.
|
||||
* @param fileManager the filemanager to load classes and resources.
|
||||
* @param tagletPath the path to the class representing the custom tag.
|
||||
*/
|
||||
public void addCustomTag(String classname, JavaFileManager fileManager, String tagletPath) {
|
||||
public void addCustomTag(String classname, JavaFileManager fileManager) {
|
||||
try {
|
||||
ClassLoader tagClassLoader;
|
||||
if (!fileManager.hasLocation(TAGLET_PATH)) {
|
||||
List<File> paths = new ArrayList<>();
|
||||
if (tagletPath != null) {
|
||||
for (String pathname : tagletPath.split(File.pathSeparator)) {
|
||||
paths.add(new File(pathname));
|
||||
}
|
||||
}
|
||||
if (fileManager instanceof StandardJavaFileManager) {
|
||||
((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, paths);
|
||||
}
|
||||
}
|
||||
tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
|
||||
Class<? extends jdk.javadoc.doclet.Taglet> customTagClass =
|
||||
tagClassLoader.loadClass(classname).asSubclass(jdk.javadoc.doclet.Taglet.class);
|
||||
jdk.javadoc.doclet.Taglet instance = customTagClass.getConstructor().newInstance();
|
||||
instance.init(docEnv, doclet);
|
||||
Taglet newLegacy = new UserTaglet(instance);
|
||||
String tname = newLegacy.getName();
|
||||
Taglet t = allTaglets.get(tname);
|
||||
if (t != null) {
|
||||
allTaglets.remove(tname);
|
||||
}
|
||||
allTaglets.put(tname, newLegacy);
|
||||
messages.notice("doclet.Notice_taglet_registered", classname);
|
||||
} catch (Exception exc) {
|
||||
messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(), classname);
|
||||
registerTaglet(instance);
|
||||
} catch (ReflectiveOperationException exc) {
|
||||
messages.error("doclet.Error_taglet_not_registered", exc.getClass().getName(),
|
||||
classname);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads taglets from a taglet path using service loader.
|
||||
* @param fileManager the filemanager to load the taglets.
|
||||
* @throws IOException if an error occurs while getting the service loader.
|
||||
*/
|
||||
public void loadTaglets(JavaFileManager fileManager) throws IOException {
|
||||
Iterable<? extends File> location = ((StandardJavaFileManager)fileManager).getLocation(TAGLET_PATH);
|
||||
if (location != null && location.iterator().hasNext()) {
|
||||
ServiceLoader<jdk.javadoc.doclet.Taglet> serviceLoader =
|
||||
fileManager.getServiceLoader(TAGLET_PATH, jdk.javadoc.doclet.Taglet.class);
|
||||
Iterator<jdk.javadoc.doclet.Taglet> iterator = serviceLoader.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
jdk.javadoc.doclet.Taglet taglet = iterator.next();
|
||||
registerTaglet(taglet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the {@code Taglet}. Prints a message if a {@code Taglet} got registered properly.
|
||||
* @param instance the {@code Taglet} instance.
|
||||
*/
|
||||
private void registerTaglet(jdk.javadoc.doclet.Taglet instance) {
|
||||
instance.init(docEnv, doclet);
|
||||
Taglet newLegacy = new UserTaglet(instance);
|
||||
allTaglets.put(newLegacy.getName(), newLegacy);
|
||||
messages.notice("doclet.Notice_taglet_registered", instance.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new {@code SimpleTaglet}. If this tag already exists
|
||||
* and the header passed as an argument is null, move tag to the back of the
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8219958
|
||||
* @summary Automatically load taglets from a jar file
|
||||
* @library /tools/lib ../../lib
|
||||
* @modules
|
||||
* jdk.javadoc/jdk.javadoc.internal.tool
|
||||
* jdk.compiler/com.sun.tools.javac.api
|
||||
* jdk.compiler/com.sun.tools.javac.main
|
||||
* @build javadoc.tester.* toolbox.ToolBox builder.ClassBuilder toolbox.JarTask
|
||||
* @run main/othervm TestAutoLoadTaglets
|
||||
*/
|
||||
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import builder.ClassBuilder;
|
||||
import toolbox.JarTask;
|
||||
import toolbox.JavacTask;
|
||||
import toolbox.ToolBox;
|
||||
|
||||
import javadoc.tester.JavadocTester;
|
||||
|
||||
public class TestAutoLoadTaglets extends JavadocTester {
|
||||
|
||||
final ToolBox tb;
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
TestAutoLoadTaglets tester = new TestAutoLoadTaglets();
|
||||
tester.runTests(m -> new Object[]{Paths.get(m.getName())});
|
||||
}
|
||||
|
||||
TestAutoLoadTaglets() {
|
||||
tb = new ToolBox();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test(Path base) throws Exception {
|
||||
Path srcDir = base.resolve("src");
|
||||
Path outDir = base.resolve("out");
|
||||
|
||||
createTagletsJar(base, srcDir);
|
||||
|
||||
new ClassBuilder(tb, "pkg.A")
|
||||
.setComments("test {@taglet1} and {@taglet2}")
|
||||
.setModifiers("public", "class")
|
||||
.write(srcDir);
|
||||
|
||||
javadoc("-d", outDir.toString(),
|
||||
"-sourcepath", srcDir.toString(),
|
||||
"-tagletpath", "taglets.jar",
|
||||
"pkg");
|
||||
|
||||
checkExit(Exit.OK);
|
||||
|
||||
checkOutput("pkg/A.html", true,
|
||||
"test user taglet taglet1 and user taglet taglet2");
|
||||
}
|
||||
|
||||
private void createTagletsJar(Path base, Path srcDir) throws Exception {
|
||||
Path classes = base.resolve("classes");
|
||||
tb.createDirectories(classes);
|
||||
createTaglets(srcDir);
|
||||
|
||||
new JavacTask(tb).files(srcDir.resolve("Taglet1.java"), srcDir.resolve("Taglet2.java"))
|
||||
.outdir(classes).run();
|
||||
|
||||
Path services = classes.resolve("META-INF").resolve("services").resolve("jdk.javadoc.doclet.Taglet");
|
||||
tb.writeFile(services,
|
||||
"Taglet1\n"
|
||||
+ "Taglet2");
|
||||
|
||||
new JarTask(tb, srcDir).run("cf", "taglets.jar", "-C", classes.toString(), ".");
|
||||
}
|
||||
|
||||
private void createTaglets(Path srcDir) throws Exception {
|
||||
for (int i = 1; i < 3; i++) {
|
||||
tb.writeJavaFiles(srcDir,
|
||||
"import com.sun.source.doctree.DocTree;\n"
|
||||
+ "import jdk.javadoc.doclet.Taglet;\n"
|
||||
+ "import javax.lang.model.element.Element;\n"
|
||||
+ "import java.util.List;\n"
|
||||
+ "import java.util.Set;\n"
|
||||
+ "public class Taglet" + i + " implements Taglet {\n"
|
||||
+ " @Override\n"
|
||||
+ " public Set<Location> getAllowedLocations() {\n"
|
||||
+ " return null;\n"
|
||||
+ " }\n"
|
||||
+ " @Override\n"
|
||||
+ " public boolean isInlineTag() {\n"
|
||||
+ " return true;\n"
|
||||
+ " }\n"
|
||||
+ " @Override\n"
|
||||
+ " public String getName() {\n"
|
||||
+ " return \"taglet" + i + "\";\n"
|
||||
+ " }\n"
|
||||
+ " @Override\n"
|
||||
+ " public String toString(List<? extends DocTree> tags, Element "
|
||||
+ "element) {\n"
|
||||
+ " return \"user taglet taglet" + i + "\";\n"
|
||||
+ " }\n"
|
||||
+ "}\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user