8130880: Create sampleapi regression test
Reviewed-by: ksrini, vromero
Contributed-by: sergei.pikalev@oracle.com
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/README.txt Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,59 @@
+
+ SampleAPI Generator for javadoc
+
+1. General description
+
+ The primary goal is to provide one or more data sets to be used as input
+to the javadoc tool, such that it can be used to generate representative samples
+of all the different content on all the different types of pages that can be
+generated by javadoc.
+
+ The tool is implemented as generator based on xml descriptions of data sets.
+The xml description of data set provides top level entities (class, interface,
+enum, annotation) with all possible content. Desired output parameters (fields,
+methods, inner/nested classes) are also described in xml as lists of modifiers,
+types and annotations. The generator "multiply" the entities from the lists
+providing the set of all possible combinations.
+
+ After the api generation the tool connects the javadoc style comments to
+the generated entities with full possible sets of supported tags.
+
+2. Tool structure
+
+ Sources:
+ test/tools/javadoc/sampleapi/lib - generator sources
+ test/tools/javadoc/sampleapi/res/xml - sample data sets in xml
+ test/tools/javadoc/sampleapi/res/txt - sample texts for doc comments
+
+3. Public API
+
+3.1 Command line runner
+
+ * test/tools/javadoc/sampleapi/lib/sampleapi/SampleApiDefaultRunner.java
+
+ class sampleapi.SampleApiDefaultRunner
+
+ Options: [-?|-h|--help] [-o:<dir>|--outdir:<dir>]
+ -?|-h|--help - print help
+ -o:<dir>|--outdir:<dir> - set <dir> to generate output
+
+3.2 Programmatic access
+
+ * test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java
+
+ class sampleapi.SampleApi
+
+ public void generate(File dir)
+ public void generate(Path dir)
+ public void generate(String dir)
+
+3.3 How to run other xml data set description
+
+ Put data set xml description into res/xml directory
+
+ * test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java
+
+ class sampleapi.generator.PackageGenerator
+
+ public void processDataSet(String dsName)
+ public void generate(File outDir)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/SampleApiTest.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, 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 8130880
+ * @library lib
+ * @run main sampleapi.SampleApiDefaultRunner -o:out/src
+ * @run main SampleApiTest
+ */
+
+import com.sun.tools.javadoc.*;
+import java.nio.file.Paths;
+
+public class SampleApiTest {
+
+ public static void main(String... args) {
+
+ // html4
+ Main.execute(
+ new String[] {
+ "-d", "out/doc.html4",
+ "-verbose",
+ "-private",
+ "-use",
+ "-splitindex",
+ "-linksource",
+ "-html4",
+ "-javafx",
+ "-windowtitle", "SampleAPI",
+ "-sourcepath", "out/src",
+ "sampleapi.simple",
+ "sampleapi.tiny",
+ "sampleapi.fx"
+ });
+
+ // html5
+ Main.execute(
+ new String[] {
+ "-d", "out/doc.html5",
+ "-verbose",
+ "-private",
+ "-use",
+ "-splitindex",
+ "-linksource",
+ "-html5",
+ "-javafx",
+ "-windowtitle", "SampleAPI",
+ "-sourcepath", "out/src",
+ "sampleapi.simple",
+ "sampleapi.tiny",
+ "sampleapi.fx"
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApi.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi;
+
+import java.io.File;
+import java.nio.file.Path;
+
+import sampleapi.generator.PackageGenerator;
+
+public class SampleApi {
+
+ PackageGenerator pkgGen = new PackageGenerator();
+
+ public void generate(File dir) throws Fault {
+ pkgGen.processDataSet("simple");
+ pkgGen.generate(dir);
+ pkgGen.processDataSet("tiny");
+ pkgGen.generate(dir);
+ pkgGen.processDataSet("fx");
+ pkgGen.generate(dir);
+ }
+
+ public void generate(Path dir) throws Fault {
+ generate(dir.toFile());
+ }
+
+ public void generate(String dir) throws Fault {
+ generate(new File(dir));
+ }
+
+ public static class Fault extends Exception {
+ public Fault(String msg) {
+ super(msg);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/SampleApiDefaultRunner.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi;
+
+import java.io.File;
+
+import sampleapi.SampleApi.Fault;
+
+public class SampleApiDefaultRunner {
+
+ public static final String MSG_DUP_OUTDIR =
+ "SampleApi: duplicated outdir detected: ";
+ public static final String MSG_USE_FIRST =
+ " will use first occurance: ";
+ public static final String MSG_INVAL_OUTDIR =
+ "SampleApi: outdir is not valid: ";
+ public static final String MSG_CANNOT_GEN =
+ "SampleApi: cannot generate output: ";
+ public static final String MSG_WRONG_OPTION =
+ "SampleApi: incorrect option: ";
+ public static final String MSG_USE_HELP =
+ " use -? for help";
+
+ public static void main(String... args) throws Exception {
+ if (args.length == 0) {
+ printHelp();
+ System.exit(1);
+ }
+
+ String outDirName = "";
+
+ boolean isOutDirSet = false;
+ boolean isHelpPrinted = false;
+ for (String arg : args) {
+ Option option = new Option(arg);
+ switch (option.getOptionName()) {
+ case "-?":
+ case "-h":
+ case "--help":
+ if (!isHelpPrinted) {
+ printHelp();
+ isHelpPrinted = true;
+ }
+ break;
+ case "-o":
+ case "--outdir":
+ if (!isOutDirSet) {
+ outDirName = option.getOptionValue();
+ isOutDirSet = true;
+ } else {
+ System.err.println(MSG_DUP_OUTDIR + option.getOptionValue());
+ System.err.println(MSG_USE_FIRST + outDirName);
+ }
+ break;
+ default:
+ System.err.println(MSG_WRONG_OPTION + arg);
+ System.err.println(MSG_USE_HELP);
+ break;
+ }
+
+ }
+
+ if (!isOutDirSet) {
+ System.exit(1);
+ }
+
+ if (outDirName.length() == 0) {
+ System.err.println(MSG_INVAL_OUTDIR + outDirName);
+ System.exit(1);
+ }
+
+ File outDir = new File(outDirName);
+ outDir.mkdirs();
+ SampleApi apiGen = new SampleApi();
+
+ try {
+ apiGen.generate(outDir);
+ } catch (Fault e) {
+ System.err.println(MSG_CANNOT_GEN + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ private static void printHelp() {
+ System.out.println("SampleApi:");
+ System.out.println(" options: [-?|-h|--help] [-o:<dir>|--outdir:<dir>]");
+ System.out.println(" -?|-h|--help - print help");
+ System.out.println(" -o:<dir>|--outdir:<dir> - set <dir> to generate output");
+ }
+
+ private static class Option {
+
+ private String optionName;
+ private String optionValue;
+
+ public Option(String arg) {
+ int delimPos = arg.indexOf(':');
+
+ if (delimPos == -1) {
+ optionName = arg;
+ optionValue = "";
+ } else {
+ optionName = arg.substring(0, delimPos);
+ optionValue = arg.substring(delimPos + 1, arg.length());
+ }
+ }
+
+ public String getOptionName() {
+ return optionName;
+ }
+
+ public String getOptionValue() {
+ return optionValue;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/DocCommentGenerator.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi.generator;
+
+import java.io.File;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.List;
+
+class DocCommentGenerator {
+
+ public enum Text {
+ BROWNFOX(BROWNFOX_TEXT),
+ NOWISTHETIME(NOWISTHETIME_TEXT),
+ THISPANGRAM(THISPANGRAM_TEXT),
+ LOREMIPSUM(LOREMIPSUM_TEXT),
+ LIEUROPANLINGUES(LIEUROPANLINGUES_TEXT),
+ CODE(CODE_TEXT);
+
+ String commentText;
+
+ Text(String text) {
+ commentText = text;
+ }
+
+ @Override
+ public String toString() {
+ return commentText;
+ }
+ }
+
+ public enum Tag {
+ AUTHOR("@author", "Cody J. Writer"),
+ PARAM("@param", ""),
+ RETURN("@return", Text.NOWISTHETIME.toString()),
+ SINCE("@since", "1.0"),
+ THROWS("@throws", "If problem detected"),
+ EXCEPTION("@exception", "If problem detected"),
+ SERIAL("@serial", ""),
+ SERIALDATA("@serialData", "The types and order of data could be here."),
+ SERIALFIELD("@serialField", "\n Serial field in special array"),
+ FX_PROPSETTER("@propertySetter", "Set the property"),
+ FX_PROPGETTER("@propertyGetter", "Get the property"),
+ FX_PROPDESC("@propertyDescription", ""),
+ FX_DEFVALUE("@defaultValue", ""),
+ FX_TREATASPRIVATE("@treatAsPrivate", "");
+
+ String tagName;
+ String tagValue;
+
+ Tag(String tagName, String tagValue) {
+ this.tagName = tagName;
+ this.tagValue = tagValue;
+ }
+
+ public String toString() {
+ return value("", "");
+ }
+
+ public String value(String value) {
+ return value(value, "");
+ }
+
+ public String value(String value, String extra) {
+ return tagName
+ + ((value.length() != 0) ? " " + value : "")
+ + ((tagValue.length() != 0) ? " " + tagValue : "")
+ + ((extra.length() != 0) ? " " + extra : "");
+ }
+ }
+
+ public enum InlineTag {
+ LITERAL("@literal", "Use < and > brackets instead of < and > escapes."),
+ CODE("@code", "(i) -> new Abc<Object>((i > 0) ? (i << 1) : 0)"),
+ LINK("@link", ""),
+ VALUE("@value", "");
+
+ String tagName;
+ String tagValue;
+
+ InlineTag(String tagName, String tagValue) {
+ this.tagName = tagName;
+ this.tagValue = tagValue;
+ }
+
+ public String toString() {
+ return value("");
+ }
+
+ public String value(String value) {
+ return "{" + tagName
+ + ((tagValue.length() != 0) ? " " + tagValue : "")
+ + ((value.length() != 0) ? " " + value : "")
+ + "}";
+ }
+ }
+
+ public static class LinkTag {
+
+ static String[] links = new String[] {
+ "Boolean",
+ "Boolean#TRUE",
+ "Boolean#Boolean(boolean)",
+ "Boolean#Boolean(String s)",
+ "Boolean#compare(boolean, boolean)",
+ "Boolean#compareTo(Boolean b)",
+ "java.util.Vector",
+ "java.util.Vector#elementCount",
+ "java.util.Vector#Vector(int)",
+ "java.util.Vector#Vector(int initialCapacity, int capacityIncrement)",
+ "java.util.Vector#indexOf(Object)",
+ "java.util.Vector#indexOf(Object o, int index)",
+ "java.lang.annotation" };
+
+ static int index = 0;
+
+ public static String nextSee() {
+ String next = "@see " + links[index];
+ index = (index + 1) % links.length;
+ return next;
+ }
+
+ public static String nextLink() {
+ String next = "Also check "
+ + (((index % 2) == 0) ? "{@link " : "{@linkplain ")
+ + links[index]
+ + "} for details.\n";
+ index = (index + 1) % links.length;
+ return next;
+ }
+ }
+
+ public static class VersionTag {
+
+ static String[] versions = new String[] {
+ "1.5, 09/01/04",
+ "1.6, 12/11/06",
+ "1.7, 07/28/11",
+ "1.8, 04/19/14",
+ "1.9, 06/03/16" };
+
+ static int index = 0;
+
+ public static String nextVersion() {
+ String next = "@version " + versions[index];
+ index = (index + 1) % versions.length;
+ return next;
+ }
+ }
+
+ //
+ // getters (build comments for entities)
+ //
+
+ public String getPackageComment() {
+ return Text.LOREMIPSUM
+ + "\n <p>" + Text.LIEUROPANLINGUES
+ + "\n" + Text.CODE
+ + "\n" + LinkTag.nextLink()
+ + "\n" + LinkTag.nextSee()
+ + "\n" + Tag.SINCE;
+ }
+
+ String[] serialVals = new String[] { "include", "exclude" };
+ // static index to roll over "include/exclude"
+ static int serialValIdx = 0;
+
+ public String getBaseComment(JCClassDecl baseDecl, boolean toplevel) {
+ String buildComment = Text.LIEUROPANLINGUES + "\n";
+
+ buildComment += "<p>It is possible to see inlined code:\n"
+ + InlineTag.CODE
+ + " is the example.\n\n";
+
+ buildComment += "<p>Literal use example.\n"
+ + InlineTag.LITERAL + "\n\n";
+
+ buildComment += "<p>" + Text.THISPANGRAM + "\n"; // make comment longer
+
+ buildComment += "<p>" + LinkTag.nextLink() + "\n";
+
+ if (toplevel)
+ buildComment += "\n" + VersionTag.nextVersion() + "\n";
+
+ // @param for type params
+ List<JCTypeParameter> params = baseDecl.getTypeParameters();
+ int paramIndex = 0;
+ for (JCTypeParameter paramDecl : params) {
+ buildComment += Tag.PARAM.value(
+ "<" + paramDecl.getName().toString() + ">",
+ "the type of value set #" + paramIndex++)
+ + "\n";
+ }
+
+ buildComment += "\n" + LinkTag.nextSee();
+
+ buildComment += "\n";
+
+ if (toplevel)
+ buildComment += Tag.AUTHOR + "\n";
+
+ buildComment += Tag.SINCE + "\n";
+
+ // for serial; currently no need to dig too deep
+ if (isSerializable(baseDecl) || isErrorOrException(baseDecl)) {
+ buildComment += "\n" + Tag.SERIAL.value(serialVals[serialValIdx]);
+ serialValIdx = (serialValIdx + 1) % 2;
+ }
+
+ return buildComment;
+ }
+
+ public String getConstComment() {
+ String buildComment = Text.NOWISTHETIME + " " + Text.BROWNFOX + "\n";
+
+ buildComment += LinkTag.nextLink() + "\n";
+ buildComment += LinkTag.nextSee() + "\n";
+ buildComment += Tag.SINCE + "\n";
+
+ return buildComment;
+ }
+
+ public String getFieldComment(JCClassDecl baseDecl,
+ JCVariableDecl varDecl,
+ boolean isFxStyle) {
+ String buildComment = Text.BROWNFOX + "<p>" + Text.NOWISTHETIME + "\n";
+
+ Set<Modifier> mods = varDecl.getModifiers().getFlags();
+ String varName = varDecl.getName().toString();
+
+ if (mods.contains(Modifier.STATIC) && mods.contains(Modifier.FINAL)) {
+ JCExpression init = varDecl.getInitializer();
+ if (init != null
+ && !"null".equals(init.toString())
+ && !"serialPersistentFields".equals(varName))
+ buildComment += "<p>The value of this constant is "
+ + InlineTag.VALUE
+ + ".\n";
+ }
+
+ buildComment += "<p>" + LinkTag.nextLink() + "\n";
+
+ if (isSerializable(baseDecl)) {
+ if (isErrorOrException(baseDecl)) {
+ buildComment += Tag.SERIAL + "\n";
+ } else if ("serialPersistentFields".equals(varName)) {
+ JCNewArray sfList = (JCNewArray)varDecl.getInitializer();
+ for (JCExpression sf : sfList.getInitializers()) {
+ List<JCExpression> args = ((JCNewClass)sf).getArguments();
+ String sfName = ((JCLiteral)args.get(0)).getValue().toString();
+ String sfClass = ((JCIdent)args.get(1)).getName().toString();
+ String sfType = sfClass.substring(0, sfClass.indexOf(".class"));
+
+ buildComment += Tag.SERIALFIELD.value(sfName + " " + sfType)
+ + "\n";
+ }
+ } else {
+ buildComment += Tag.SERIAL.value("Very important value.") + "\n";
+ }
+ }
+
+ if (isFxStyle) {
+ // set default value
+ String varType = varDecl.getType().toString();
+ buildComment += Tag.FX_DEFVALUE.value(defValue(varType)) + "\n";
+ }
+
+ buildComment += LinkTag.nextSee() + "\n";
+
+ return buildComment;
+ }
+
+ public String getMethodComment(JCClassDecl baseDecl,
+ JCMethodDecl methodDecl,
+ boolean isFxStyle) {
+ String buildComment = Text.BROWNFOX + "\n<p>" + Text.THISPANGRAM + "\n";
+
+ buildComment += "<p>" + LinkTag.nextLink() + "\n";
+
+ buildComment += "<p>Literal use example.\n"
+ + InlineTag.LITERAL + "\n\n";
+
+ // @param for type params
+ List<JCTypeParameter> tparams = methodDecl.getTypeParameters();
+ int tparamIndex = 0;
+ for (JCTypeParameter paramDecl : tparams) {
+ String paramDeclString = paramDecl.getName().toString();
+ // simplify it (could contain 'extend'/'super' clauses
+ int spacePos = paramDeclString.indexOf(' ');
+ if (spacePos != -1)
+ paramDeclString = paramDeclString.substring(0, spacePos);
+ buildComment += Tag.PARAM.value(
+ "<" + paramDeclString + ">",
+ "the type of value set #" + tparamIndex++)
+ + "\n";
+ }
+
+ // @param
+ List<JCVariableDecl> params = methodDecl.getParameters();
+ int paramIndex = 0;
+ for (JCVariableDecl paramDecl : params) {
+ buildComment += Tag.PARAM.value(
+ paramDecl.getName().toString(),
+ "an income parameter #" + paramIndex++)
+ + "\n";
+ }
+
+ // @return
+ JCTree retType = methodDecl.getReturnType(); // null for constructors
+ if (retType != null && !"void".equals(retType.toString()))
+ buildComment += Tag.RETURN + "\n";
+
+ // @throws/@exception
+ Tag t = isDerived(baseDecl) ? Tag.EXCEPTION : Tag.THROWS;
+ List<JCExpression> throwTypes = methodDecl.getThrows();
+ for (JCExpression throwsExp : throwTypes) {
+ buildComment += t.value(throwsExp.toString()) + "\n";
+ }
+
+ if (isSerializable(baseDecl)) {
+ switch (methodDecl.getName().toString()) {
+ case "writeObject":
+ case "readObject":
+ case "writeExternal":
+ case "readExternal":
+ case "writeReplace":
+ case "readResolve":
+ buildComment += Tag.SERIALDATA + "\n";
+ break;
+ default:
+ }
+ }
+
+ if (isFxStyle) {
+ // @propertySetter/Getter + Description
+ if ("void".equals(retType.toString())) {
+ buildComment += Tag.FX_PROPSETTER + "\n";
+ } else {
+ buildComment += Tag.FX_PROPGETTER + "\n";
+ buildComment += Tag.FX_DEFVALUE.value(defValue(retType.toString()))
+ + "\n";
+ }
+ buildComment += Tag.FX_PROPDESC.value(Text.BROWNFOX.toString()) + "\n";
+
+ // @treatAsPrivate
+ if (methodDecl.getModifiers().getFlags().contains(Modifier.PUBLIC))
+ buildComment += Tag.FX_TREATASPRIVATE + "\n";
+ }
+
+ // @see
+ buildComment += LinkTag.nextSee() + "\n";
+
+ // @since
+ buildComment += Tag.SINCE + "\n";
+
+ return buildComment;
+ }
+
+ //
+ // util methods
+ //
+
+ private boolean isErrorOrException(JCClassDecl baseDecl) {
+ JCExpression ext = baseDecl.getExtendsClause();
+ if (ext != null) {
+ String extClassName = ext.toString();
+ if (extClassName.contains("Error") || extClassName.contains("Exception"))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isSerializable(JCClassDecl baseDecl) {
+ List<JCExpression> impls = baseDecl.getImplementsClause();
+ for (JCExpression impl : impls) {
+ if (impl.toString().contains("Serializable"))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isDerived(JCClassDecl baseDecl) {
+ return (baseDecl.getExtendsClause() == null) ? false : true;
+ }
+
+ private String defValue(String type) {
+ switch (type) {
+ case "boolean":
+ return "true";
+ case "byte": case "char": case "int": case "long":
+ case "Integer": case "Long":
+ return "1";
+ case "float": case "double": case "Float": case "Double":
+ return "1.0";
+ case "String":
+ return "string";
+ default:
+ return "null";
+ }
+ }
+
+ private static final String BROWNFOX_TEXT =
+ "The quick brown fox jumps over the lazy dog.\n";
+ private static final String NOWISTHETIME_TEXT =
+ "Now is the time for all good men to come to the aid of the party.\n";
+ private static final String THISPANGRAM_TEXT =
+ "This pangram contains four a's, one b, two c's, one d, thirty e's,\n" +
+ "six f's, five g's, seven h's, eleven i's, one j, one k, two l's,\n" +
+ "two m's, eighteen n's, fifteen o's, two p's, one q, five r's,\n" +
+ "twenty-seven s's, eighteen t's, two u's, seven v's, eight w's,\n" +
+ "two x's, three y's, & one z.";
+ private static final String LOREMIPSUM_TEXT =
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do\n" +
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut\n" +
+ "enim ad minim veniam, quis nostrud exercitation ullamco laboris\n" +
+ "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor\n" +
+ "in reprehenderit in voluptate velit esse cillum dolore eu fugiat\n" +
+ "nulla pariatur. Excepteur sint occaecat cupidatat non proident,\n" +
+ "sunt in culpa qui officia deserunt mollit anim id est laborum.\n";
+ private static final String LIEUROPANLINGUES_TEXT =
+ "Li Europan lingues es membres del sam familie. Lor separat existentie\n" +
+ "es un myth. Por scientie, musica, sport etc, litot Europa usa li sam\n" +
+ "vocabular. Li lingues differe solmen in li grammatica, li pronunciation\n" +
+ "e li plu commun vocabules. Omnicos directe al desirabilite de un nov\n" +
+ "lingua franca: On refusa continuar payar custosi traductores.\n" +
+ "\n" +
+ "<p>At solmen va esser necessi far uniform grammatica, pronunciation\n" +
+ "e plu commun paroles. Ma quande lingues coalesce, li grammatica del\n" +
+ "resultant lingue es plu simplic e regulari quam ti del coalescent\n" +
+ "lingues. Li nov lingua franca va esser plu simplic e regulari quam\n" +
+ "li existent Europan lingues. It va esser tam simplic quam Occidental\n" +
+ "in fact, it va esser Occidental. A un Angleso it va semblar un simplificat\n" +
+ "Angles, quam un skeptic Cambridge amico dit me que Occidental es.\n";
+ private static final String CODE_TEXT =
+ "<pre>\n" +
+ "public void checkLanguage(Language lang) throws Exception {\n" +
+ " if (lang.getName().equals(\"Java\")) {\n" +
+ " System.out.println(\"Warning! Hot!\");\n" +
+ " else {\n" +
+ " throw new LooserException();\n" +
+ " }\n" +
+ "}\n" +
+ "</pre>\n";
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/Documentifier.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi.generator;
+
+import java.util.ArrayList;
+import java.util.Set;
+import javax.lang.model.element.Modifier;
+
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.DocCommentTable;
+import com.sun.tools.javac.parser.ScannerFactory;
+import com.sun.tools.javac.parser.Scanner;
+import com.sun.tools.javac.parser.Tokens.Token;
+import com.sun.tools.javac.parser.Tokens.Comment;
+import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
+import com.sun.source.tree.Tree.Kind;
+
+import sampleapi.util.*;
+
+class Documentifier {
+
+ static Documentifier instance;
+
+ final DocCommentGenerator docGen;
+ final ScannerFactory scanners;
+
+ private Documentifier(Context context) {
+ docGen = new DocCommentGenerator();
+ scanners = ScannerFactory.instance(context);
+ }
+
+ public static Documentifier instance(Context context) {
+ if (instance == null)
+ instance = new Documentifier(context);
+ return instance;
+ }
+
+ private DocCommentTable curDocComments;
+
+ public void documentify(JCCompilationUnit topLevel, boolean isFxStyle) {
+ JCClassDecl base = (JCClassDecl)topLevel.getTypeDecls().get(0);
+ curDocComments = new PoorDocCommentTable();
+ documentifyBase(base, true, isFxStyle);
+ topLevel.docComments = curDocComments;
+ }
+
+ private void documentifyBase(JCClassDecl base, boolean isTopLevel, boolean isFxStyle) {
+ // add doc comment to class itself
+ Comment comm = comment(docGen.getBaseComment(base, isTopLevel));
+ curDocComments.putComment(base, comm);
+
+ // add doc comments to members
+ for (JCTree member : base.getMembers()) {
+ switch (member.getTag()) {
+ case VARDEF:
+ documentifyField(base, (JCVariableDecl)member, isFxStyle);
+ break;
+ case METHODDEF:
+ documentifyMethod(base, (JCMethodDecl)member, isFxStyle);
+ break;
+ case CLASSDEF:
+ documentifyBase((JCClassDecl)member, false, isFxStyle);
+ break;
+ }
+ }
+ }
+
+ private void documentifyField(JCClassDecl base, JCVariableDecl field, boolean isFxStyle) {
+ Kind baseKind = base.getKind();
+ Set<Modifier> fieldMods = field.getModifiers().getFlags();
+ String doc = (baseKind == Kind.ENUM
+ && fieldMods.contains(Modifier.PUBLIC)
+ && fieldMods.contains(Modifier.STATIC)
+ && fieldMods.contains(Modifier.FINAL)) ?
+ docGen.getConstComment() :
+ docGen.getFieldComment(base, field, isFxStyle);
+ Comment comm = comment(doc);
+ curDocComments.putComment(field, comm);
+ }
+
+ private void documentifyMethod(JCClassDecl base, JCMethodDecl method, boolean isFxStyle) {
+ Comment comm = comment(docGen.getMethodComment(base, method, isFxStyle));
+ curDocComments.putComment(method, comm);
+ }
+
+ private Comment comment(String docString) {
+ StringBuilder docComment = new StringBuilder()
+ .append("/**")
+ .append(docString)
+ .append("*/");
+ Scanner scanner = scanners.newScanner(docComment, true);
+ scanner.nextToken();
+ Token token = scanner.token();
+ return token.comment(CommentStyle.JAVADOC);
+ }
+
+ // provide package comment data ONLY
+ public DocCommentGenerator getDocGenerator() {
+ return docGen;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/generator/PackageGenerator.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,832 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi.generator;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+import org.xml.sax.SAXException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.api.JavacTool;
+import com.sun.tools.javac.api.JavacTaskImpl;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.TypeTag;
+import com.sun.tools.javac.code.TypeMetadata;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+
+import sampleapi.util.*;
+import sampleapi.SampleApi.Fault;
+
+public class PackageGenerator {
+
+ String packageName;
+ String packageDirName;
+
+ ArrayList<JCCompilationUnit> topLevels;
+ Hashtable<String, Integer> nameIndex;
+ Hashtable<String, JCClassDecl> idBases;
+ Hashtable<String, JCAnnotation> idAnnos;
+
+ TreeMaker make;
+ Names names;
+ Symtab syms;
+ DocumentBuilderFactory factory;
+ Documentifier documentifier;
+ boolean fx = false;
+
+ public PackageGenerator() {
+ JavacTool jt = JavacTool.create();
+ JavacTask task = jt.getTask(null, null, null, null, null, null);
+ Context ctx = ((JavacTaskImpl)task).getContext();
+
+ make = TreeMaker.instance(ctx);
+ names = Names.instance(ctx);
+ syms = Symtab.instance(ctx);
+ factory = DocumentBuilderFactory.newInstance();
+
+ documentifier = Documentifier.instance(ctx);
+ }
+
+ String dataSetName;
+
+ public void processDataSet(String dsName) throws Fault {
+ dataSetName = dsName;
+ topLevels = new ArrayList<>();
+ nameIndex = new Hashtable<>();
+ idBases = new Hashtable<>();
+ idAnnos = new Hashtable<>();
+
+ String dsPath = "res/xml/" + dsName + ".xml";
+
+ try {
+ InputStream is = getClass().getResourceAsStream("/" + dsPath);
+ if (is == null)
+ is = new FileInputStream(dsPath);
+
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document document = builder.parse(is);
+
+ Element rootElement = document.getDocumentElement();
+ packageName = rootElement.getAttribute("package");
+ fx = "fx".equals(rootElement.getAttribute("style"));
+ packageDirName = packageName.replace('.', '/');
+
+ // process nodes (toplevels)
+ NodeList nodeList = rootElement.getChildNodes();
+ for (int i = 0; i < nodeList.getLength(); i++) {
+ Node node = nodeList.item(i);
+
+ if (!(node instanceof Element))
+ continue;
+ processTopLevel((Element)node);
+ }
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ throw new Fault("Error parsing dataset " + dsName);
+ }
+
+ fx = false;
+ }
+
+ public void generate(File outDir) throws Fault {
+ if (dataSetName == null)
+ throw new Fault("No Data Set processed");
+
+ try {
+ File pkgDir = new File(outDir, packageDirName);
+ pkgDir.mkdirs();
+
+ for (JCCompilationUnit decl : topLevels) {
+ JCClassDecl classDecl = (JCClassDecl)decl.getTypeDecls().get(0);
+ File outFile = new File(pkgDir,
+ classDecl.getSimpleName().toString() + ".java");
+ FileWriter writer = new FileWriter(outFile);
+ writer.write(decl.toString());
+ writer.flush();
+ writer.close();
+ }
+
+ // package-info
+ File outFile = new File(pkgDir, "package-info.java");
+ FileWriter writer = new FileWriter(outFile);
+ writer.write("/**\n");
+ writer.write(documentifier.getDocGenerator().getPackageComment());
+ writer.write("*/\n");
+ writer.write("package " + packageName + ";");
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ throw new Fault("Error writing output");
+ }
+ }
+
+ // levels' processing methods
+
+ void processTopLevel(Element tlTag) {
+ String kind = tlTag.getTagName();
+
+ if (kind.equals("annodecl")) {
+ // decls stored separately, does not affect bases
+ String declId = tlTag.getAttribute("id");
+ if (!declId.startsWith("@"))
+ declId = "@" + declId;
+ idAnnos.put(declId, processAnnoDecl(tlTag));
+ return;
+ }
+
+ ListBuffer<JCTree>[] bases = processBases(tlTag, null);
+
+ for (JCTree base : bases[0]) { // [0] - bases namely
+ JCPackageDecl pkg = make.PackageDecl(
+ List.<JCAnnotation>nil(),
+ make.QualIdent(
+ new Symbol.PackageSymbol(
+ names.fromString(packageName),
+ null)));
+ ListBuffer<JCTree> topLevelParts = new ListBuffer<>();
+ topLevelParts.append(pkg);
+ topLevelParts.appendList(bases[1]); // [1] imports
+ topLevelParts.append(base);
+
+ JCCompilationUnit topLevel = make.TopLevel(topLevelParts.toList());
+ documentifier.documentify(topLevel, fx);
+ topLevels.add(topLevel);
+ }
+ }
+
+ ListBuffer<JCTree>[] processBases(Element baseTag, Hashtable<String, Integer> scope) {
+ String kind = baseTag.getTagName();
+ String baseName = baseTag.getAttribute("basename");
+ String typeParam = baseTag.getAttribute("tparam");
+ String baseId = baseTag.getAttribute("id");
+
+ long kindFlag = 0;
+ switch (kind) {
+ case "class":
+ // no flags for class
+ break;
+ case "interface":
+ kindFlag |= Flags.INTERFACE;
+ break;
+ case "enum":
+ kindFlag |= Flags.ENUM;
+ break;
+ case "annotation":
+ kindFlag |= Flags.ANNOTATION | Flags.INTERFACE;
+ break;
+ }
+
+ // go through other nodes; add modifiers to multiplier
+ NodeList nodes = baseTag.getChildNodes();
+ ListBuffer<JCTree> bases = new ListBuffer<>();
+ ListBuffer<JCTree> members = new ListBuffer<>();
+ ListBuffer<JCTree> imports = new ListBuffer<>();
+ JCExpression extType = null;
+ ListBuffer<JCExpression> implTypes = new ListBuffer<>();
+ SimpleMultiplier multiply = new SimpleMultiplier();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+
+ if (!(node instanceof Element))
+ continue;
+
+ switch (((Element)node).getTagName()) {
+ case "modifier":
+ multiply.addAxis(((Element)node).getTextContent());
+ break;
+ case "anno":
+ multiply.addAxis(((Element)node).getTextContent());
+ break;
+ case "member":
+ // process members here
+ members.appendList(processMembers((Element)node, baseName, kind));
+ break;
+ case "extend":
+ String classId = ((Element)node).getAttribute("id"); // this pkg
+ String classRef = ((Element)node).getAttribute("ref"); // external
+ if (classId.length() !=0 &&
+ idBases.containsKey(classId)) {
+ // if have base, take methods from base members
+ JCClassDecl baseDecl = idBases.get(classId);
+ extType = make.Type(
+ getTypeByName(
+ baseDecl.getSimpleName().toString()));
+ members.appendList(processMethods(baseDecl.getMembers(), false));
+ } else if (classRef.length() !=0) {
+ extType = make.Type(getTypeByName(classRef));
+ }
+ break;
+ case "implement":
+ String interfaceId = ((Element)node).getAttribute("id");
+ String interfaceRef = ((Element)node).getAttribute("ref");
+ if (interfaceId.length() != 0 &&
+ idBases.containsKey(interfaceId)) {
+ JCClassDecl baseDecl = idBases.get(interfaceId);
+ implTypes.add(
+ make.Type(
+ getTypeByName(
+ baseDecl.getSimpleName().toString())));
+ members.appendList(processMethods(baseDecl.getMembers(), true));
+ } else if (interfaceRef.length() != 0) {
+ implTypes.add(make.Type(getTypeByName(interfaceRef)));
+ }
+ break;
+ case "import":
+ imports.append(
+ make.Import(
+ make.Ident(names.fromString(((Element)node).getTextContent())),
+ false));
+ }
+ }
+
+ // process modifiers through multiplier
+ multiply.initIterator();
+ while (multiply.hasNext()) {
+ ArrayList<String> tuple = multiply.getNext();
+
+ long declFlags = kindFlag;
+ ListBuffer<JCAnnotation> annos = new ListBuffer<>();
+ for (String modifier : tuple) {
+ if (modifier.startsWith("@") && idAnnos.containsKey(modifier))
+ annos.add(idAnnos.get(modifier)); // it's anno
+ else
+ declFlags |= getFlagByName(modifier); // it's modifier
+ }
+
+ String declName = (scope == null)
+ ? getUniqName(baseName)
+ : baseName + getUniqIndex(scope, baseName);
+ JCClassDecl baseDecl = make.ClassDef(
+ make.Modifiers(declFlags, annos.toList()),
+ names.fromString(declName),
+ processTypeParams(typeParam), // type params
+ extType, // ext
+ implTypes.toList(), // impl
+ members.toList()); // members
+
+ // fix constructors names
+ fixConstructorNames(baseDecl);
+
+ bases.append(baseDecl);
+
+ // for non-empty ids store first base occurence from multiplied sequence
+ if (baseId.length() != 0) {
+ idBases.put(baseId, baseDecl);
+ baseId = "";
+ }
+ }
+
+ return new ListBuffer[] { bases, imports };
+ }
+
+ List<JCTypeParameter> processTypeParams(String typeParams) {
+
+ if (typeParams == null || typeParams.length() == 0)
+ return List.<JCTypeParameter>nil(); // empty
+
+ String[] typeVarsArr = typeParams.split(",");
+ ListBuffer<JCTypeParameter> typeParamsDecls = new ListBuffer<>();
+
+ for (String typeVar : typeVarsArr) {
+ typeParamsDecls.add(
+ make.TypeParameter(names.fromString(typeVar),
+ List.<JCExpression>nil()));
+ }
+
+ return typeParamsDecls.toList();
+ }
+
+ ListBuffer<JCTree> processMembers(Element memberTag, String name, String kind) {
+ ListBuffer<JCTree> members = new ListBuffer<>();
+ NodeList nodes = memberTag.getChildNodes();
+ Hashtable<String, Integer> scope = new Hashtable<>();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+
+ if (!(node instanceof Element))
+ continue;
+
+ switch (((Element)node).getTagName()) {
+ case "field":
+ members.appendList(processFields((Element)node, scope));
+ break;
+ case "serialfield":
+ members.append(processSerialFields((Element)node));
+ break;
+ case "constant":
+ members.appendList(processConstants((Element)node, scope));
+ break;
+ case "constructor":
+ members.appendList(processMethods((Element)node, scope, true, true));
+ break;
+ case "method":
+ boolean needBody = kind.equals("class") || kind.equals("enum");
+ members.appendList(processMethods((Element)node, scope, needBody, false));
+ break;
+ case "class":
+ case "interface":
+ case "enum":
+ case "annotation":
+ members.appendList(processBases((Element)node, scope)[0]);
+ break;
+ }
+ }
+
+ return members;
+ }
+
+ ListBuffer<JCTree> processFields(Element fieldsNode, Hashtable<String, Integer> scope) {
+ String kind = fieldsNode.getTagName();
+ String baseName = fieldsNode.getAttribute("basename");
+
+ ListBuffer<JCTree> fields = new ListBuffer<>();
+ NodeList nodes = fieldsNode.getChildNodes();
+ SimpleMultiplier multiply = new SimpleMultiplier(); // for modifiers
+ String[] types = new String[] {};
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+
+ if (!(node instanceof Element))
+ continue;
+
+ // parse type and modifiers
+ switch (((Element)node).getTagName()) {
+ case "modifier":
+ multiply.addAxis(((Element)node).getTextContent());
+ break;
+ case "anno":
+ multiply.addAxis(((Element)node).getTextContent());
+ case "type":
+ types = ((Element)node).getTextContent().split("\\|");
+ break;
+ }
+ }
+
+ // process through modifiers and types
+ multiply.initIterator();
+ while (multiply.hasNext()) {
+ ArrayList<String> tuple = multiply.getNext();
+
+ long declFlags = 0;
+ ListBuffer<JCAnnotation> annos = new ListBuffer<>();
+ for (String modifier : tuple) {
+ if (modifier.startsWith("@") && idAnnos.containsKey(modifier))
+ annos.add(idAnnos.get(modifier)); // it's anno
+ else
+ declFlags |= getFlagByName(modifier); // it's modifier
+ }
+
+
+ for (String type : types) {
+ String declName = baseName + getUniqIndex(scope, baseName);
+
+ Type initType = getTypeByName(type);
+ JCExpression initExpr = null;
+ if ((declFlags & Flags.STATIC) != 0) // static to be initialized
+ initExpr = make.Literal(initType.isPrimitive() ?
+ initType.getTag() :
+ TypeTag.BOT,
+ "String".equals(type)
+ ? new String("blah-blah-blah")
+ : new Integer(0));
+
+ JCVariableDecl fieldDecl = make.VarDef(
+ make.Modifiers(declFlags, annos.toList()),
+ names.fromString(declName),
+ make.Type(getTypeByName(type)),
+ initExpr);
+
+ fields.append(fieldDecl);
+ }
+ }
+
+ return fields;
+ }
+
+ JCTree processSerialFields(Element sfNode) {
+ String baseName = sfNode.getAttribute("basename");
+ String[] fieldTypes = sfNode.getTextContent().split(",");
+
+ ListBuffer<JCExpression> serialFields = new ListBuffer<>();
+ Hashtable<String, Integer> scope = new Hashtable<>();
+
+ for (String fType : fieldTypes) {
+ String fieldName = baseName + getUniqIndex(scope, baseName);
+ serialFields.add(
+ make.NewClass(
+ null,
+ null,
+ make.Type(getTypeByName("ObjectStreamField")),
+ List.from(
+ new JCTree.JCExpression[] {
+ make.Literal(fieldName),
+ make.Ident(names.fromString(fType + ".class"))
+ }),
+ null));
+ }
+
+ JCTree sfDecl = make.VarDef(
+ make.Modifiers(
+ Flags.PRIVATE | Flags.STATIC | Flags.FINAL),
+ names.fromString("serialPersistentFields"),
+ make.TypeArray(
+ make.Type(getTypeByName("ObjectStreamField"))),
+ make.NewArray(
+ null,
+ List.<JCExpression>nil(),
+ serialFields.toList()));
+
+ return sfDecl;
+ }
+
+ ListBuffer<JCTree> processConstants(Element constNode, Hashtable<String, Integer> scope) {
+ String baseName = constNode.getAttribute("basename");
+ int count = 1;
+ try {
+ count = Integer.parseInt(constNode.getAttribute("count"));
+ } catch (Exception e) {} // nothing to do, will use count = 1
+
+ long declFlags = Flags.PUBLIC | Flags.STATIC | Flags.FINAL | Flags.ENUM;
+ ListBuffer<JCTree> fields = new ListBuffer<>();
+
+ for (int i = 0; i < count; i++) {
+ String declName = baseName +
+ ((count == 1) ? "" : getUniqIndex(scope, baseName));
+
+ JCVariableDecl constDecl = make.VarDef(
+ make.Modifiers(declFlags),
+ names.fromString(declName),
+ null, // no need for type in enum decl
+ null); // no init
+
+ fields.append(constDecl);
+ }
+ return fields;
+ }
+
+ ListBuffer<JCTree> processMethods(Element methodsNode, Hashtable<String, Integer> scope, boolean needBody, boolean isConstructor) {
+ String kind = methodsNode.getTagName();
+ String baseName = methodsNode.getAttribute("basename");
+ String name = methodsNode.getAttribute("name");
+ String methodTypeParam = methodsNode.getAttribute("tparam");
+
+ ListBuffer<JCTree> methods = new ListBuffer<>();
+ NodeList nodes = methodsNode.getChildNodes();
+ SimpleMultiplier multiply = new SimpleMultiplier(); // for modifiers
+ String[] types = new String[0];
+ String[] params = new String[] { "none" }; // default - no params
+ ListBuffer<Type> throwTypes = new ListBuffer<>();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+
+ if (!(node instanceof Element))
+ continue;
+
+ // parse type and modifiers
+ switch (((Element)node).getTagName()) {
+ case "modifier":
+ multiply.addAxis(((Element)node).getTextContent());
+ break;
+ case "anno":
+ multiply.addAxis(((Element)node).getTextContent());
+ break;
+ case "type":
+ types = ((Element)node).getTextContent().split("\\|");
+ break;
+ case "param":
+ params = ((Element)node).getTextContent().split("\\|");
+ break;
+ case "throw":
+ throwTypes.add(
+ getTypeByName(((Element)node).getTextContent()));
+ break;
+
+ }
+ }
+
+ // constructor?
+ if (isConstructor) {
+ baseName = "constructor";
+ types = new String[] { "" };
+ }
+
+ // direct name not indexed
+ boolean isDirectName = false;
+ if (name.length() > 0) {
+ baseName = name;
+ isDirectName = true;
+ }
+
+ // process through modifiers and types
+ multiply.initIterator();
+ while (multiply.hasNext()) {
+ ArrayList<String> tuple = multiply.getNext();
+
+ long declFlags = 0;
+ ListBuffer<JCAnnotation> annos = new ListBuffer<>();
+ for (String modifier : tuple) {
+ if (modifier.startsWith("@") && idAnnos.containsKey(modifier))
+ annos.add(idAnnos.get(modifier)); // it's anno
+ else
+ declFlags |= getFlagByName(modifier); // it's modifier
+ }
+
+ for (String type : types) {
+ String declName = baseName
+ + ((isConstructor || isDirectName)
+ ? "" : getUniqIndex(scope, baseName));
+
+ JCBlock body = null;
+ if (needBody && (declFlags & Flags.ABSTRACT) == 0) { // create body
+ List<JCStatement> bodyStatements = List.<JCStatement>nil();
+ if (!type.equals("") && !type.equals("void")) { // create return statement
+ Type retType = getTypeByName(type);
+ bodyStatements = List.<JCStatement>of(
+ make.Return(
+ make.Literal(
+ retType.isPrimitive() ?
+ retType.getTag() :
+ TypeTag.BOT,
+ new Integer(0))));
+ }
+ body = make.Block(0, bodyStatements);
+ }
+
+ // same method by different params (if they exist)
+ for (String param : params) {
+
+ JCMethodDecl methodDecl =
+ make.MethodDef(
+ make.Modifiers(declFlags, annos.toList()),
+ names.fromString(declName),
+ isConstructor ? null : make.Type(getTypeByName(type)),
+ processTypeParams(methodTypeParam), // type params
+ null, // no receiver
+ processParams(param), // formal params
+ make.Types(throwTypes.toList()), // throws
+ body,
+ null); // no default value YET
+
+ methods.append(methodDecl);
+ }
+ }
+ }
+
+ return methods;
+ }
+
+ JCAnnotation processAnnoDecl(Element annoDeclNode) {
+ String annoId = annoDeclNode.getAttribute("id");
+
+ ListBuffer<JCExpression> args = new ListBuffer<>();
+ String className = "";
+
+ NodeList nodes = annoDeclNode.getChildNodes();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Node node = nodes.item(i);
+
+ if (!(node instanceof Element))
+ continue;
+
+ switch (((Element)node).getTagName()) {
+ case "class":
+ className = ((Element)node).getTextContent();
+ break;
+ case "arg":
+ String argName = ((Element)node).getAttribute("name");
+ String argValue = ((Element)node).getAttribute("value");
+
+ JCExpression arg;
+ if (argName.length() == 0)
+ arg = make.Ident(names.fromString(argValue));
+ else
+ arg = make.Assign(
+ make.Ident(names.fromString(argName)),
+ make.Ident(names.fromString(argValue)));
+
+ args.add(arg);
+ break;
+ }
+ }
+
+ return make.Annotation(
+ make.Ident(names.fromString(className)),
+ args.toList());
+ }
+
+ ListBuffer<JCTree> processMethods(List<JCTree> tree, boolean needBody) {
+ // for "extends" clause; returns methods only
+ ListBuffer<JCTree> methods = new ListBuffer<>();
+ for (JCTree memberDecl : tree) {
+ if (memberDecl instanceof JCMethodDecl) {
+ JCMethodDecl methodDecl = (JCMethodDecl)memberDecl;
+ JCTree retTypeTree = methodDecl.getReturnType();
+
+ // skip constructors
+ if (retTypeTree == null)
+ continue;
+
+ if (needBody) {
+ // here we need to 'implement' interface declared methods
+ Type retType = retTypeTree.type;
+
+ List<JCStatement> bodyStatements = List.<JCStatement>nil();
+ if (retType.getTag() != TypeTag.VOID)
+ bodyStatements = List.<JCStatement>of(
+ make.Return(
+ make.Literal(
+ retType.isPrimitive() ?
+ retType.getTag() :
+ TypeTag.BOT,
+ new Integer(0))));
+
+ JCBlock body = make.Block(0, bodyStatements);
+
+ methodDecl = make.MethodDef(
+ methodDecl.getModifiers(),
+ methodDecl.getName(),
+ (JCExpression)methodDecl.getReturnType(),
+ methodDecl.getTypeParameters(),
+ methodDecl.getReceiverParameter(),
+ methodDecl.getParameters(),
+ methodDecl.getThrows(),
+ body,
+ (JCExpression)methodDecl.getDefaultValue());
+ }
+
+ methods.add(methodDecl);
+ }
+ }
+ return methods;
+ }
+
+ void fixConstructorNames(JCClassDecl baseDecl) {
+ ListBuffer<JCTree> newMembers = new ListBuffer<>();
+ List<JCTree> members = baseDecl.getMembers();
+ Name name = baseDecl.getSimpleName();
+
+ for (JCTree memberDecl : members) {
+ JCTree newDecl = memberDecl;
+
+ if (memberDecl instanceof JCMethodDecl) {
+ JCMethodDecl methodDecl = (JCMethodDecl)memberDecl;
+ JCTree retTypeTree = methodDecl.getReturnType();
+
+ if (retTypeTree == null)
+ newDecl = make.MethodDef(
+ methodDecl.getModifiers(),
+ name,
+ (JCExpression)methodDecl.getReturnType(),
+ methodDecl.getTypeParameters(),
+ methodDecl.getReceiverParameter(),
+ methodDecl.getParameters(),
+ methodDecl.getThrows(),
+ methodDecl.getBody(),
+ (JCExpression)methodDecl.getDefaultValue());
+ }
+
+ newMembers.add(newDecl);
+ }
+
+ baseDecl.defs = newMembers.toList();
+ }
+
+ List<JCVariableDecl> processParams(String paramTypes) {
+
+ if ("none".equals(paramTypes))
+ return List.<JCVariableDecl>nil(); // empty
+
+ String[] typesArr = paramTypes.split(",(?!(\\w+,)*\\w+>)");
+ ListBuffer<JCVariableDecl> paramsDecls = new ListBuffer<>();
+
+ int i = 0;
+ for (String typeName : typesArr) {
+ String paramName = "param"
+ + (typesArr.length == 1 ? "" : String.valueOf(i));
+ paramsDecls.add(
+ make.VarDef(make.Modifiers(0),
+ names.fromString(paramName),
+ make.Type(getTypeByName(typeName)),
+ null));
+ i++;
+ }
+
+ return paramsDecls.toList();
+ }
+
+ //
+ // util methods
+ //
+
+ String getUniqName(String name) {
+ if (!nameIndex.containsKey(name))
+ nameIndex.put(name, new Integer(0));
+ Integer index = nameIndex.get(name);
+ String uniqName = name + index;
+ nameIndex.put(name, index + 1);
+ return uniqName;
+ }
+
+ int getUniqIndex(Hashtable<String, Integer> scope, String name) {
+ if (!scope.containsKey(name))
+ scope.put(name, new Integer(0));
+ Integer index = scope.get(name);
+ scope.put(name, index + 1);
+ return index;
+ }
+
+ long getFlagByName(String modifierName) {
+ switch (modifierName) {
+ case "public":
+ return Flags.PUBLIC;
+ case "private":
+ return Flags.PRIVATE;
+ case "protected":
+ return Flags.PROTECTED;
+ case "static":
+ return Flags.STATIC;
+ case "final":
+ return Flags.FINAL;
+ case "abstract":
+ return Flags.ABSTRACT;
+ case "strictfp":
+ return Flags.STRICTFP;
+ default:
+ return 0;
+ }
+ }
+
+ Type getTypeByName(String typeName) {
+ //check for primitive types
+ switch (typeName) {
+ case "void":
+ return syms.voidType;
+ case "boolean":
+ return syms.booleanType;
+ case "byte":
+ return syms.byteType;
+ case "char":
+ return syms.charType;
+ case "double":
+ return syms.doubleType;
+ case "float":
+ return syms.floatType;
+ case "int":
+ return syms.intType;
+ case "long":
+ return syms.longType;
+ default:
+ return getTypeByName(typeName, List.<Type>nil());
+ }
+ }
+
+ Type getTypeByName(String typeName, List<Type> tparams) {
+ return new Type.ClassType(
+ Type.noType,
+ tparams,
+ new Symbol.ClassSymbol(0, names.fromString(typeName), null));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/util/PoorDocCommentTable.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi.util;
+
+import java.util.HashMap;
+
+import com.sun.tools.javac.parser.Tokens.Comment;
+import com.sun.tools.javac.tree.DCTree.DCDocComment;
+import com.sun.tools.javac.tree.DocCommentTable;
+import com.sun.tools.javac.tree.JCTree;
+
+/*
+ * This class is replica of LazyDocCommentTable from com.sun.tools.javac.parser
+ * package. It's created due to restrictions of LazyDocCommentTable (cannot be
+ * used outside the package) and implements minimal functionality necessary
+ * for doc comment generation purposes.
+ */
+public class PoorDocCommentTable implements DocCommentTable {
+
+ HashMap<JCTree, Comment> table;
+
+ public PoorDocCommentTable() {
+ table = new HashMap<>();
+ }
+
+ public boolean hasComment(JCTree tree) {
+ return table.containsKey(tree);
+ }
+
+ public Comment getComment(JCTree tree) {
+ return table.get(tree);
+ }
+
+ public String getCommentText(JCTree tree) {
+ Comment c = getComment(tree);
+ return (c == null) ? null : c.getText();
+ }
+
+ public DCDocComment getCommentTree(JCTree tree) {
+ return null; // no need for generator purposes, Pretty does not call it
+ }
+
+ public void putComment(JCTree tree, Comment c) {
+ table.put(tree, c);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/lib/sampleapi/util/SimpleMultiplier.java Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+package sampleapi.util;
+
+import java.util.StringTokenizer;
+import java.util.ArrayList;
+
+/*
+ * The class implements unknown number of nested loops. The number of modifiers
+ * in class/interface definitions could be any size. Annotations are also multiplied
+ * by this class.
+ * That is, dataset xml can provide any number of modifier sets, and generator should
+ * iterate through all possible modifiers, annotations and types combinations.
+ *
+ * For example, class definition xml provides 3 modifiers sets:
+ *
+ * "public,private"
+ * "static"
+ * "final,abstract"
+ *
+ * and one types set "void,int"
+ *
+ * the class will generate the sequence like:
+ * "public static final void"
+ * "public static final int"
+ * "public static abstract void"
+ * "public static abstract int"
+ * "private static final void"
+ * "private static final int"
+ * "private static abstract void"
+ * "private static abstract int".
+ *
+ * This sequence could be processed by just one loop instead of four.
+ *
+ * In other places where the number of possible positions are known,
+ * the generator uses nested loops instead.
+ */
+public class SimpleMultiplier {
+
+ ArrayList<ArrayList<String>> valueSpace = new ArrayList<>();
+
+ int size = 0;
+ int index = 0;
+
+ public void addAxis(String values) {
+ ArrayList<String> valueAxis = new ArrayList<>();
+ StringTokenizer valuesTokens = new StringTokenizer(values, "|");
+ while (valuesTokens.hasMoreTokens())
+ valueAxis.add(valuesTokens.nextToken());
+ valueSpace.add(valueAxis);
+ }
+
+ public void initIterator() {
+ if (!valueSpace.isEmpty()) {
+ size = 1;
+ for (int i = 0; i < valueSpace.size(); i++)
+ size *= valueSpace.get(i).size();
+ }
+ index = 0;
+ }
+
+ public boolean hasNext() {
+ return index < size;
+ }
+
+ public ArrayList<String> getNext() {
+ ArrayList<String> next = new ArrayList<>();
+ int positionIndex = index;
+
+ // last added changing faster
+ for (int i = valueSpace.size() - 1; i >= 0; i--) {
+ ArrayList<String> valueAxis = valueSpace.get(i);
+ int axisSize = valueAxis.size();
+ next.add(valueAxis.get(positionIndex % axisSize));
+ positionIndex /= axisSize;
+ }
+ index += 1;
+
+ return next;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/res/xml/fx.xml Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015, 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.
+-->
+<dataset package="sampleapi.fx" style="fx">
+
+ <class basename="FXClass">
+ <modifier>public</modifier>
+ <member>
+ <field basename="id">
+ <modifier>public</modifier>
+ <type>int|boolean</type>
+ </field>
+ <method basename="setProp">
+ <modifier>public|protected|private</modifier>
+ <param>int|String</param>
+ <type>void</type>
+ </method>
+ <method basename="getProp">
+ <modifier>public|protected|private</modifier>
+ <type>int|int|String</type>
+ </method>
+ </member>
+ </class>
+
+</dataset>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/res/xml/simple.xml Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,529 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015, 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.
+-->
+<dataset package="sampleapi.simple">
+
+ <class basename="SampleClass" id="baseclass">
+ <modifier>public</modifier>
+ <modifier>none|abstract</modifier>
+ <member>
+ <field basename="field">
+ <modifier>none|public</modifier>
+ <modifier>none|static</modifier>
+ <modifier>none|final</modifier>
+ <type>boolean|int|String</type>
+ </field>
+ <field basename="field">
+ <modifier>protected|private</modifier>
+ <type>String</type>
+ </field>
+ <constructor>
+ <modifier>public</modifier>
+ <param>none|int|int,boolean|int,String</param>
+ </constructor>
+ <constructor>
+ <modifier>public</modifier>
+ <param>String</param>
+ <throw>NullPointerException</throw>
+ <throw>SampleException0</throw>
+ </constructor>
+ <method basename="set">
+ <modifier>public</modifier>
+ <type>void</type>
+ <param>int</param>
+ </method>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>int|boolean|String</type>
+ </method>
+ <method basename="doSomething">
+ <modifier>public</modifier>
+ <type>void|int</type>
+ <param>none|int|Object,int</param>
+ <throw>NullPointerException</throw>
+ <throw>ArithmeticException</throw>
+ </method>
+ </member>
+ </class>
+
+ <class basename="Derived">
+ <modifier>public</modifier>
+ <extend id="baseclass"/>
+ <member>
+ <field basename="myField">
+ <modifier>public</modifier>
+ <type>int|boolean</type>
+ </field>
+ <constructor>
+ <modifier>public</modifier>
+ <param>none|int|int,boolean|int,String</param>
+ </constructor>
+ <method basename="myGet">
+ <modifier>public</modifier>
+ <type>int|boolean</type>
+ </method>
+ </member>
+ </class>
+
+ <class basename="SampleSerial">
+ <import>java.io.Serializable</import>
+ <modifier>public</modifier>
+ <implement ref="Serializable"/>
+ <member>
+ <field basename="specialData">
+ <modifier>private|none|public</modifier>
+ <type>boolean|int|String</type>
+ </field>
+ </member>
+ </class>
+
+ <class basename="SampleSerial">
+ <import>java.io.Serializable</import>
+ <import>java.io.ObjectStreamField</import>
+ <modifier>public</modifier>
+ <implement ref="Serializable"/>
+ <member>
+ <serialfield basename="serialField">String,Long,Boolean</serialfield>
+ <method basename="justToBeHere">
+ <modifier>public</modifier>
+ <type>String|long|boolean</type>
+ </method>
+ </member>
+ </class>
+
+ <class basename="SampleSerial">
+ <import>java.io.Serializable</import>
+ <import>java.io.ObjectOutputStream</import>
+ <import>java.io.ObjectOutput</import>
+ <import>java.io.IOException</import>
+ <import>java.io.ObjectStreamException</import>
+ <modifier>public</modifier>
+ <implement ref="Serializable"/>
+ <member>
+ <method name="writeObject">
+ <modifier>private</modifier>
+ <param>ObjectOutputStream</param>
+ <type>void</type>
+ <throw>IOException</throw>
+ </method>
+ <method name="writeExternal">
+ <modifier>public</modifier>
+ <param>ObjectOutput</param>
+ <type>void</type>
+ <throw>IOException</throw>
+ </method>
+ <method name="writeReplace">
+ <modifier>protected</modifier>
+ <param>none</param>
+ <type>Object</type>
+ <throw>ObjectStreamException</throw>
+ </method>
+ <method name="writeSomethingElse">
+ <modifier>public</modifier>
+ <param>Object</param>
+ <type>void</type>
+ <throw>IOException</throw>
+ </method>
+ </member>
+ </class>
+
+ <class basename="SampleSerial">
+ <import>java.io.Serializable</import>
+ <import>java.io.ObjectInputStream</import>
+ <import>java.io.ObjectInput</import>
+ <import>java.io.IOException</import>
+ <import>java.io.ObjectStreamException</import>
+ <modifier>public</modifier>
+ <implement ref="Serializable"/>
+ <member>
+ <method name="readObject">
+ <modifier>private</modifier>
+ <param>ObjectInputStream</param>
+ <type>void</type>
+ <throw>IOException</throw>
+ <throw>ClassNotFoundException</throw>
+ </method>
+ <method name="readExternal">
+ <modifier>public</modifier>
+ <param>ObjectInput</param>
+ <type>void</type>
+ <throw>IOException</throw>
+ </method>
+ <method name="readResolve">
+ <modifier>protected</modifier>
+ <param>none</param>
+ <type>Object</type>
+ <throw>ObjectStreamException</throw>
+ </method>
+ <method name="readSomethingElse">
+ <modifier>public</modifier>
+ <param>Object</param>
+ <type>void</type>
+ <throw>IOException</throw>
+ </method>
+ </member>
+ </class>
+
+ <class basename="Container">
+ <modifier>public</modifier>
+ <member>
+ <class basename="Inner">
+ <modifier>public</modifier>
+ <member>
+ <field basename="value">
+ <modifier>public</modifier>
+ <type>int</type>
+ </field>
+ </member>
+ </class>
+ <class basename="Nested">
+ <modifier>public</modifier>
+ <modifier>static</modifier>
+ </class>
+ <interface basename="EventListener">
+ <modifier>public</modifier>
+ <modifier>static</modifier>
+ <member>
+ <method basename="onEvent">
+ <modifier>public</modifier>
+ <type>void</type>
+ </method>
+ </member>
+ </interface>
+ </member>
+ </class>
+
+ <!-- Errors and exceptions -->
+ <class basename="SampleError">
+ <modifier>public</modifier>
+ <extend ref="java.lang.Error"/>
+ <member>
+ <field basename="errorInfo">
+ <modifier>private</modifier>
+ <type>boolean|int|String</type>
+ </field>
+ <constructor>
+ <modifier>public</modifier>
+ <param>String</param>
+ </constructor>
+ <method basename="getSampleData">
+ <modifier>public</modifier>
+ <type>int|String</type>
+ </method>
+ </member>
+ </class>
+
+ <class basename="SampleException">
+ <modifier>public</modifier>
+ <extend ref="java.lang.Exception"/>
+ <member>
+ <field basename="exceptionInfo">
+ <modifier>private</modifier>
+ <type>boolean|int|String</type>
+ </field>
+ <constructor>
+ <modifier>public</modifier>
+ <param>String</param>
+ </constructor>
+ <method basename="getSampleData">
+ <modifier>public</modifier>
+ <type>int|String</type>
+ </method>
+ </member>
+ </class>
+
+ <interface basename="SampleInterface" id="baseinterface">
+ <modifier>public|none</modifier>
+ <member>
+ <method basename="method">
+ <modifier>public</modifier>
+ <type>void|int|Object</type>
+ </method>
+ </member>
+ </interface>
+
+ <class basename="Implementor">
+ <modifier>public</modifier>
+ <implement id="baseinterface"/>
+ <member>
+ <field basename="myField">
+ <modifier>public</modifier>
+ <type>int|boolean</type>
+ </field>
+ <method basename="myGet">
+ <modifier>public</modifier>
+ <type>int|boolean</type>
+ </method>
+ </member>
+ </class>
+
+ <class basename="GenericClass" tparam="T">
+ <import>java.util.List</import>
+ <modifier>public</modifier>
+ <member>
+ <method basename="put">
+ <modifier>public</modifier>
+ <type>void</type>
+ <param>T</param>
+ </method>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>T</type>
+ <param>int</param>
+ </method>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>List<T></type>
+ </method>
+ </member>
+ </class>
+
+ <class basename="GenericClass" tparam="K,V">
+ <import>java.util.Set</import>
+ <import>java.util.List</import>
+ <import>java.util.Map</import>
+ <modifier>public</modifier>
+ <member>
+ <method basename="put">
+ <modifier>public</modifier>
+ <type>void</type>
+ <param>K,V</param>
+ </method>
+ <method basename="putMap">
+ <modifier>public</modifier>
+ <type>void</type>
+ <param>Map<K,V></param>
+ </method>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>V</type>
+ <param>K</param>
+ </method>
+ <method basename="getV">
+ <modifier>public</modifier>
+ <type>Set<V>|List<V></type>
+ </method>
+ <method basename="getK">
+ <modifier>public</modifier>
+ <type>Set<K>|List<K></type>
+ </method>
+ </member>
+ </class>
+
+ <class basename="GenericClass" tparam="M,N,O">
+ <import>java.util.Set</import>
+ <import>java.util.List</import>
+ <import>java.util.Map</import>
+ <modifier>public</modifier>
+ <member>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>Set<M>|List<M></type>
+ <param>Map<N,O></param>
+ </method>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>Set<N>|List<N></type>
+ <param>Map<M,O></param>
+ </method>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>Set<O>|List<O></type>
+ <param>Map<M,N></param>
+ </method>
+ </member>
+ </class>
+
+ <class basename="GenericUtil"> <!-- public static generic methods like Collections -->
+ <import>java.util.Set</import>
+ <import>java.util.List</import>
+ <import>java.util.Map</import>
+ <import>java.util.function.Supplier</import>
+ <modifier>public</modifier>
+ <member>
+ <method tparam="E" basename="getSomething">
+ <modifier>public</modifier>
+ <modifier>static</modifier>
+ <type>Set<? extends E>|List<? extends E></type>
+ </method>
+ <method tparam="V,K" basename="getMore">
+ <modifier>public|private</modifier>
+ <modifier>static</modifier>
+ <type>Map<V,K></type>
+ </method>
+ <method tparam="E" basename="doSomething">
+ <modifier>public</modifier>
+ <modifier>static</modifier>
+ <type>void</type>
+ <param>E</param>
+ </method>
+ <method tparam="X extends Throwable" basename="orElseThrow">
+ <modifier>public|private</modifier>
+ <modifier>static</modifier>
+ <type>X</type>
+ <param>Supplier<? extends X></param>
+ <throw>X</throw>
+ </method>
+ </member>
+ </class>
+
+ <enum basename="SampleEnum">
+ <modifier>public</modifier>
+ <member>
+ <constant basename="VALUE" count="3"/>
+ </member>
+ </enum>
+
+ <enum basename="SampleEnum">
+ <modifier>public</modifier>
+ <member>
+ <constant basename="VALUE" count="2"/>
+ <constant basename="NOVALUE" count="1"/>
+ <field basename="field">
+ <modifier>private</modifier>
+ <type>int|String</type>
+ </field>
+ <method basename="method">
+ <modifier>public</modifier>
+ <type>void|String</type>
+ </method>
+ </member>
+ </enum>
+
+ <annodecl id="documented">
+ <class>Documented</class>
+ </annodecl>
+
+ <annodecl id="reten-source">
+ <class>Retention</class>
+ <arg name="value" value="RetentionPolicy.SOURCE"/>
+ </annodecl>
+
+ <annodecl id="reten-class">
+ <class>Retention</class>
+ <arg name="value" value="RetentionPolicy.CLASS"/>
+ </annodecl>
+
+ <annodecl id="reten-runtime">
+ <class>Retention</class>
+ <arg name="value" value="RetentionPolicy.RUNTIME"/>
+ </annodecl>
+
+ <annodecl id="target-method">
+ <class>Target</class>
+ <arg value="ElementType.METHOD"/>
+ </annodecl>
+
+ <annodecl id="target-field">
+ <class>Target</class>
+ <arg value="ElementType.FIELD"/>
+ </annodecl>
+
+ <annodecl id="target-type">
+ <class>Target</class>
+ <arg value="{ElementType.TYPE, ElementType.TYPE_USE}"/>
+ </annodecl>
+
+ <annotation basename="AnnotatedAnno">
+ <import>java.lang.annotation.Documented</import>
+ <anno>@documented</anno>
+ <modifier>public</modifier>
+ <member>
+ <method basename="value">
+ <modifier>public</modifier>
+ <type>boolean|String</type>
+ </method>
+ </member>
+ </annotation>
+
+ <annotation basename="AnnotatedAnno">
+ <import>java.lang.annotation.Retention</import>
+ <import>java.lang.annotation.RetentionPolicy</import>
+ <anno>@reten-source|@reten-class|@reten-runtime</anno>
+ <modifier>public</modifier>
+ <member>
+ <method basename="value">
+ <modifier>public</modifier>
+ <type>int</type>
+ </method>
+ </member>
+ </annotation>
+
+ <class basename="AnnoContainer">
+ <import>java.lang.annotation.Retention</import>
+ <import>java.lang.annotation.RetentionPolicy</import>
+ <import>java.lang.annotation.Target</import>
+ <import>java.lang.annotation.ElementType</import>
+ <modifier>public</modifier>
+ <member>
+ <annotation basename="AnnotatedAnno">
+ <anno>@reten-source|@reten-class|@reten-runtime</anno>
+ <anno>@target-method|@target-field|@target-type</anno>
+ <modifier>public</modifier>
+ <modifier>static</modifier>
+ <member>
+ <method basename="value">
+ <modifier>public</modifier>
+ <type>String</type>
+ </method>
+ </member>
+ </annotation>
+ </member>
+ </class>
+
+ <annodecl id="deprecated">
+ <class>Deprecated</class>
+ </annodecl>
+
+ <annodecl id="safevarargs">
+ <class>SafeVarargs</class>
+ </annodecl>
+
+ <annodecl id="suppresswarnings">
+ <class>SuppressWarnings</class>
+ <arg value="{"unchecked", "rawtypes"}"/>
+ </annodecl>
+
+ <class basename="AnnotatedClass">
+ <modifier>public</modifier>
+ <member>
+ <method basename="deprecatedMethod">
+ <anno>@deprecated</anno>
+ <modifier>public</modifier>
+ <type>void</type>
+ </method>
+ <method basename="safeVarargsMethod">
+ <anno>@safevarargs</anno>
+ <modifier>public</modifier>
+ <type>void|int</type>
+ <param>String...</param>
+ </method>
+ <method basename="suppressWarningsMethod">
+ <anno>@suppresswarnings</anno>
+ <modifier>public</modifier>
+ <type>void</type>
+ <param>int|Object</param>
+ </method>
+ </member>
+ </class>
+</dataset>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javadoc/sampleapi/res/xml/tiny.xml Thu Nov 19 13:14:16 2015 -0800
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015, 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.
+-->
+<dataset package="sampleapi.tiny">
+
+ <class basename="TinyClass">
+ <modifier>public</modifier>
+ <modifier>none|abstract</modifier>
+ <member>
+ <field basename="id">
+ <modifier>public</modifier>
+ <type>int</type>
+ </field>
+ <method basename="get">
+ <modifier>public</modifier>
+ <type>int</type>
+ </method>
+ </member>
+ </class>
+
+ <interface basename="TinyInterface">
+ <modifier>public</modifier>
+ <member>
+ <method basename="put">
+ <modifier>public</modifier>
+ <type>void</type>
+ <param>int</param>
+ </method>
+ </member>
+ </interface>
+
+ <enum basename="TinyEnum">
+ <modifier>public</modifier>
+ <member>
+ <constant basename="YES" count="1"/>
+ <constant basename="NO" count="1"/>
+ <constant basename="MAYBE" count="1"/>
+ </member>
+ </enum>
+
+ <annotation basename="TinyAnno">
+ <modifier>public</modifier>
+ <member>
+ <method basename="value">
+ <modifier>public</modifier>
+ <type>boolean</type>
+ </method>
+ </member>
+ </annotation>
+
+</dataset>