8000416: refactor javadoc to provide and use an abstraction for relative URIs
authorjjg
Tue, 23 Oct 2012 13:58:56 -0700
changeset 14358 9eda9239cba0
parent 14357 faf9cde2817b
child 14359 d4099818ab70
8000416: refactor javadoc to provide and use an abstraction for relative URIs Reviewed-by: darcy
langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/SplitIndexWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java
langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocLink.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocPath.java
langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Extern.java
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AnnotationTypeWriterImpl.java	Tue Oct 23 13:58:56 2012 -0700
@@ -81,7 +81,7 @@
      * @return a content tree for the package link
      */
     protected Content getNavLinkPackage() {
-        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, "",
+        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
                 packageLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
@@ -103,7 +103,7 @@
      * @return a content tree for the class use link
      */
     protected Content getNavLinkClassUse() {
-        Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), "", useLabel);
+        Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), useLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
     }
@@ -287,7 +287,7 @@
      */
     protected Content getNavLinkTree() {
         Content treeLinkContent = getHyperLink(DocPaths.PACKAGE_TREE,
-                "", treeLabel, "", "");
+                treeLabel, "", "");
         Content li = HtmlTree.LI(treeLinkContent);
         return li;
     }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -465,7 +465,7 @@
      */
     protected Content getNavLinkPackage() {
         Content linkContent =
-                getHyperLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY), "", packageLabel);
+                getHyperLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY), packageLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
     }
@@ -500,8 +500,8 @@
      */
     protected Content getNavLinkTree() {
         Content linkContent = classdoc.containingPackage().isIncluded() ?
-            getHyperLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), "", treeLabel) :
-            getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), "", treeLabel);
+            getHyperLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), treeLabel) :
+            getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), treeLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
     }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassWriterImpl.java	Tue Oct 23 13:58:56 2012 -0700
@@ -87,7 +87,7 @@
      * @return a content tree for the package link
      */
     protected Content getNavLinkPackage() {
-        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, "",
+        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
                 packageLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
@@ -109,7 +109,7 @@
      * @return a content tree for the class use link
      */
     protected Content getNavLinkClassUse() {
-        Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), "", useLabel);
+        Content linkContent = getHyperLink(DocPaths.CLASS_USE.resolve(filename), useLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
     }
@@ -565,7 +565,7 @@
      */
     protected Content getNavLinkTree() {
         Content treeLinkContent = getHyperLink(DocPaths.PACKAGE_TREE,
-                "", treeLabel, "", "");
+                treeLabel, "", "");
         Content li = HtmlTree.LI(treeLinkContent);
         return li;
     }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ConstantsSummaryWriterImpl.java	Tue Oct 23 13:58:56 2012 -0700
@@ -107,13 +107,13 @@
         //add link to summary
         Content link;
         if (packageName.length() == 0) {
-            link = getHyperLink("#" + DocletConstants.UNNAMED_PACKAGE_ANCHOR,
-                    "", defaultPackageLabel, "", "");
+            link = getHyperLink(DocLink.fragment(DocletConstants.UNNAMED_PACKAGE_ANCHOR),
+                    defaultPackageLabel, "", "");
         } else {
             Content packageNameContent = getPackageLabel(parsedPackageName);
             packageNameContent.addContent(".*");
-            link = getHyperLink("#" + parsedPackageName,
-                    "", packageNameContent, "", "");
+            link = getHyperLink(DocLink.fragment(parsedPackageName),
+                    packageNameContent, "", "");
             printedPackageHeaders.add(parsedPackageName);
         }
         contentListTree.addContent(HtmlTree.LI(link));
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/HtmlDocletWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -287,7 +287,7 @@
      */
     public Content getTargetPackageLink(PackageDoc pd, String target,
             Content label) {
-        return getHyperLink(pathString(pd, DocPaths.PACKAGE_SUMMARY), "", label, "", target);
+        return getHyperLink(pathString(pd, DocPaths.PACKAGE_SUMMARY), label, "", target);
     }
 
     /**
@@ -407,9 +407,10 @@
                 allClassesId += "navbar_top";
                 Content a = getMarkerAnchor("navbar_top");
                 navDiv.addContent(a);
-                Content skipLinkContent = getHyperLink("",
-                        "skip-navbar_top", HtmlTree.EMPTY, configuration.getText(
-                        "doclet.Skip_navigation_links"), "");
+                Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_top"),
+                        HtmlTree.EMPTY,
+                        configuration.getText("doclet.Skip_navigation_links"),
+                        "");
                 navDiv.addContent(skipLinkContent);
             } else {
                 body.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
@@ -417,9 +418,10 @@
                 allClassesId += "navbar_bottom";
                 Content a = getMarkerAnchor("navbar_bottom");
                 navDiv.addContent(a);
-                Content skipLinkContent = getHyperLink("",
-                        "skip-navbar_bottom", HtmlTree.EMPTY, configuration.getText(
-                        "doclet.Skip_navigation_links"), "");
+                Content skipLinkContent = getHyperLink(DocLink.fragment("skip-navbar_bottom"),
+                        HtmlTree.EMPTY,
+                        configuration.getText("doclet.Skip_navigation_links"),
+                        "");
                 navDiv.addContent(skipLinkContent);
             }
             if (header) {
@@ -515,7 +517,7 @@
      */
     protected Content getNavLinkContents() {
         Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_SUMMARY),
-                "", overviewLabel, "", "");
+                overviewLabel, "", "");
         Content li = HtmlTree.LI(linkContent);
         return li;
     }
@@ -562,7 +564,7 @@
     public Content getNavLinkPrevious(DocPath prev) {
         Content li;
         if (prev != null) {
-            li = HtmlTree.LI(getHyperLink(prev, "", prevLabel, "", ""));
+            li = HtmlTree.LI(getHyperLink(prev, prevLabel, "", ""));
         }
         else
             li = HtmlTree.LI(prevLabel);
@@ -579,7 +581,7 @@
     public Content getNavLinkNext(DocPath next) {
         Content li;
         if (next != null) {
-            li = HtmlTree.LI(getHyperLink(next, "", nextLabel, "", ""));
+            li = HtmlTree.LI(getHyperLink(next, nextLabel, "", ""));
         }
         else
             li = HtmlTree.LI(nextLabel);
@@ -593,8 +595,8 @@
      * @return a content tree for the link
      */
     protected Content getNavShowLists(DocPath link) {
-        Content framesContent = getHyperLink(link.getPath() + "?" + path.getPath(),
-                "", framesLabel, "", "_top");
+        DocLink dl = new DocLink(link, path.getPath(), null);
+        Content framesContent = getHyperLink(dl, framesLabel, "", "_top");
         Content li = HtmlTree.LI(framesContent);
         return li;
     }
@@ -615,7 +617,7 @@
      * @return a content tree for the link
      */
     protected Content getNavHideLists(DocPath link) {
-        Content noFramesContent = getHyperLink(link, "", noframesLabel, "", "_top");
+        Content noFramesContent = getHyperLink(link, noframesLabel, "", "_top");
         Content li = HtmlTree.LI(noFramesContent);
         return li;
     }
@@ -633,11 +635,11 @@
         PackageDoc[] packages = configuration.root.specifiedPackages();
         if (packages.length == 1 && configuration.root.specifiedClasses().length == 0) {
             treeLinkContent = getHyperLink(pathString(packages[0],
-                    DocPaths.PACKAGE_TREE), "", treeLabel,
+                    DocPaths.PACKAGE_TREE), treeLabel,
                     "", "");
         } else {
             treeLinkContent = getHyperLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE),
-                    "", treeLabel, "", "");
+                    treeLabel, "", "");
         }
         Content li = HtmlTree.LI(treeLinkContent);
         return li;
@@ -673,7 +675,7 @@
      */
     protected Content getNavLinkDeprecated() {
         Content linkContent = getHyperLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
-                "", deprecatedLabel, "", "");
+                deprecatedLabel, "", "");
         Content li = HtmlTree.LI(linkContent);
         return li;
     }
@@ -687,7 +689,7 @@
      */
     protected Content getNavLinkClassIndex() {
         Content allClassesContent = getHyperLink(pathToRoot.resolve(
-                DocPaths.ALLCLASSES_NOFRAME), "",
+                DocPaths.ALLCLASSES_NOFRAME),
                 allclassesLabel, "", "");
         Content li = HtmlTree.LI(allClassesContent);
         return li;
@@ -702,7 +704,7 @@
         Content linkContent = getHyperLink(pathToRoot.resolve(
                 (configuration.splitindex
                     ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
-                    : DocPaths.INDEX_ALL)), "",
+                    : DocPaths.INDEX_ALL)),
             indexLabel, "", "");
         Content li = HtmlTree.LI(linkContent);
         return li;
@@ -723,7 +725,7 @@
         } else {
             helpfilenm = DocPath.create(new File(helpfile).getName());
         }
-        Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm), "",
+        Content linkContent = getHyperLink(pathToRoot.resolve(helpfilenm),
                 helpLabel, "", "");
         Content li = HtmlTree.LI(linkContent);
         return li;
@@ -917,11 +919,11 @@
         }
         if (included || pkg == null) {
             return getHyperLinkString(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
-                                "", label, isStrong, style);
+                                label, isStrong, style);
         } else {
-            String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
+            DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
             if (crossPkgLink != null) {
-                return getHyperLinkString(/*TEMP*/ DocPath.create(crossPkgLink), "", label, isStrong, style);
+                return getHyperLinkString(crossPkgLink, label, isStrong, style);
             } else {
                 return label;
             }
@@ -948,11 +950,11 @@
         }
         if (included || pkg == null) {
             return getHyperLink(pathString(pkg, DocPaths.PACKAGE_SUMMARY),
-                                "", label);
+                    label);
         } else {
-            String crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
+            DocLink crossPkgLink = getCrossPackageLink(Util.getPackageName(pkg));
             if (crossPkgLink != null) {
-                return getHyperLink(/*TEMP*/ DocPath.create(crossPkgLink), "", label);
+                return getHyperLink(crossPkgLink, label);
             } else {
                 return label;
             }
@@ -983,7 +985,7 @@
         DocPath href = pathToRoot
                 .resolve(DocPaths.SOURCE_OUTPUT)
                 .resolve(DocPath.forClass(cd));
-        Content linkContent = getHyperLink(href, SourceToHTMLConverter.getAnchorName(doc), label, "", "");
+        Content linkContent = getHyperLink(href.fragment(SourceToHTMLConverter.getAnchorName(doc)), label, "", "");
         htmltree.addContent(linkContent);
     }
 
@@ -996,7 +998,7 @@
      */
     public String getLink(LinkInfoImpl linkInfo) {
         LinkFactoryImpl factory = new LinkFactoryImpl(this);
-        String link = ((LinkOutputImpl) factory.getLinkOutput(linkInfo)).toString();
+        String link = factory.getLinkOutput(linkInfo).toString();
         displayLength += linkInfo.displayLength;
         return link;
     }
@@ -1009,8 +1011,7 @@
      */
     public String getTypeParameterLinks(LinkInfoImpl linkInfo) {
         LinkFactoryImpl factory = new LinkFactoryImpl(this);
-        return ((LinkOutputImpl)
-            factory.getTypeParameterLinks(linkInfo, false)).toString();
+        return factory.getTypeParameterLinks(linkInfo, false).toString();
     }
 
     /*************************************************************
@@ -1030,10 +1031,10 @@
     public String getCrossClassLink(String qualifiedClassName, String refMemName,
                                     String label, boolean strong, String style,
                                     boolean code) {
-        String className = "",
-            packageName = qualifiedClassName == null ? "" : qualifiedClassName;
+        String className = "";
+        String packageName = qualifiedClassName == null ? "" : qualifiedClassName;
         int periodIndex;
-        while((periodIndex = packageName.lastIndexOf('.')) != -1) {
+        while ((periodIndex = packageName.lastIndexOf('.')) != -1) {
             className = packageName.substring(periodIndex + 1, packageName.length()) +
                 (className.length() > 0 ? "." + className : "");
             String defaultLabel = code ? codeText(className) : className;
@@ -1044,11 +1045,12 @@
                 //the -link option.  There are ways to determine if an external package
                 //exists, but no way to determine if the external class exists.  We just
                 //have to assume that it does.
-                return getHyperLinkString(
-                    configuration.extern.getExternalLink(packageName, pathToRoot,
-                                className + ".html?is-external=true"),
-                    refMemName == null ? "" : refMemName,
-                    label == null || label.length() == 0 ? defaultLabel : label,
+                DocLink link = configuration.extern.getExternalLink(packageName, pathToRoot,
+                                className + ".html", refMemName);
+                return getHyperLinkString(link,
+                    (label == null) || label.length() == 0 ? defaultLabel : label,
+
+
                     strong, style,
                     configuration.getText("doclet.Href_Class_Or_Interface_Title", packageName),
                     "");
@@ -1064,9 +1066,9 @@
         return configuration.extern.isExternal(cd);
     }
 
-    public String getCrossPackageLink(String pkgName) {
+    public DocLink getCrossPackageLink(String pkgName) {
         return configuration.extern.getExternalLink(pkgName, pathToRoot,
-            "package-summary.html?is-external=true");
+            DocPaths.PACKAGE_SUMMARY.getPath());
     }
 
     /**
@@ -1094,7 +1096,7 @@
 
     /**
      * Retrieve the class link with the package portion of the label in
-     * plain text.  If the qualifier is excluded, it willnot be included in the
+     * plain text.  If the qualifier is excluded, it will not be included in the
      * link label.
      *
      * @param cd the class to link to.
@@ -1278,10 +1280,11 @@
                 return getPackageLinkString(refPackage, label, false);
             } else {
                 //@see is not referencing an included class or package.  Check for cross links.
-                String classCrossLink, packageCrossLink = getCrossPackageLink(refClassName);
+                String classCrossLink;
+                DocLink packageCrossLink = getCrossPackageLink(refClassName);
                 if (packageCrossLink != null) {
                     //Package cross link found
-                    return getHyperLinkString(/*TEMP*/ DocPath.create(packageCrossLink), "",
+                    return getHyperLinkString(packageCrossLink,
                         (label.isEmpty() ? text : label), false);
                 } else if ((classCrossLink = getCrossClassLink(refClassName,
                         refMemName, label, false, "", !plain)) != null) {
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java	Tue Oct 23 13:58:56 2012 -0700
@@ -81,8 +81,9 @@
                 DocPath filename = getPath(classLinkInfo);
                 if (linkInfo.linkToSelf ||
                                 !(DocPath.forName(classDoc)).equals(m_writer.filename)) {
-                        linkOutput.append(m_writer.getHyperLinkString(filename,
-                            classLinkInfo.where, label.toString(),
+                        linkOutput.append(m_writer.getHyperLinkString(
+                                filename.fragment(classLinkInfo.where),
+                            label.toString(),
                             classLinkInfo.isStrong, classLinkInfo.styleName,
                             title, classLinkInfo.target));
                         if (noLabel && !classLinkInfo.excludeTypeParameterLinks) {
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexFrameWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -109,12 +109,12 @@
         if (pd.name().length() > 0) {
             packageLabel = getPackageLabel(pd.name());
             packageLinkContent = getHyperLink(pathString(pd,
-                     DocPaths.PACKAGE_FRAME), "", packageLabel, "",
+                     DocPaths.PACKAGE_FRAME), packageLabel, "",
                     "packageFrame");
         } else {
             packageLabel = new RawHtml("<unnamed package>");
             packageLinkContent = getHyperLink(DocPaths.PACKAGE_FRAME,
-                    "", packageLabel, "", "packageFrame");
+                    packageLabel, "", "packageFrame");
         }
         Content li = HtmlTree.LI(packageLinkContent);
         return li;
@@ -148,7 +148,7 @@
      * @param body the Content object to which the all classes link should be added
      */
     protected void addAllClassesLink(Content body) {
-        Content linkContent = getHyperLink(DocPaths.ALLCLASSES_FRAME, "",
+        Content linkContent = getHyperLink(DocPaths.ALLCLASSES_FRAME,
                 allclassesLabel, "", "packageFrame");
         Content div = HtmlTree.DIV(HtmlStyle.indexHeader, linkContent);
         body.addContent(div);
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -178,7 +178,7 @@
             Content see = seeLabel;
             see.addContent(" ");
             Content descPara = HtmlTree.P(see);
-            Content descLink = getHyperLink("", "overview_description",
+            Content descLink = getHyperLink(DocLink.fragment("overview_description"),
                 descriptionLabel, "", "");
             descPara.addContent(descLink);
             div.addContent(descPara);
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageTreeWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -198,7 +198,7 @@
      * @return a content tree for the package link
      */
     protected Content getNavLinkPackage() {
-        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, "",
+        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
                 packageLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageUseWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -230,10 +230,10 @@
      */
     protected void addClassRow(ClassDoc usedClass, String packageName,
             Content contentTree) {
-        DocPath path = pathString(usedClass,
+        DocPath dp = pathString(usedClass,
                 DocPaths.CLASS_USE.resolve(DocPath.forName(usedClass)));
         Content td = HtmlTree.TD(HtmlStyle.colOne,
-                getHyperLink(path, packageName, new StringContent(usedClass.name())));
+                getHyperLink(dp.fragment(packageName), new StringContent(usedClass.name())));
         addIndexComment(usedClass, td);
         contentTree.addContent(td);
     }
@@ -286,7 +286,7 @@
      * @return a content tree for the package link
      */
     protected Content getNavLinkPackage() {
-        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY, "",
+        Content linkContent = getHyperLink(DocPaths.PACKAGE_SUMMARY,
                 packageLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
@@ -308,7 +308,7 @@
      * @return a content tree for the tree link
      */
     protected Content getNavLinkTree() {
-        Content linkContent = getHyperLink(DocPaths.PACKAGE_TREE, "",
+        Content linkContent = getHyperLink(DocPaths.PACKAGE_TREE,
                 treeLabel);
         Content li = HtmlTree.LI(linkContent);
         return li;
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageWriterImpl.java	Tue Oct 23 13:58:56 2012 -0700
@@ -112,7 +112,7 @@
             addSummaryComment(packageDoc, docSummaryDiv);
             div.addContent(docSummaryDiv);
             Content space = getSpace();
-            Content descLink = getHyperLink("", "package_description",
+            Content descLink = getHyperLink(DocLink.fragment("package_description"),
                     descriptionLabel, "", "");
             Content descPara = new HtmlTree(HtmlTag.P, seeLabel, space, descLink);
             div.addContent(descPara);
@@ -250,7 +250,7 @@
      * @return a content tree for the class use link
      */
     protected Content getNavLinkClassUse() {
-        Content useLink = getHyperLink(DocPaths.PACKAGE_USE, "",
+        Content useLink = getHyperLink(DocPaths.PACKAGE_USE,
                 useLabel, "", "");
         Content li = HtmlTree.LI(useLink);
         return li;
@@ -267,7 +267,7 @@
             li = HtmlTree.LI(prevpackageLabel);
         } else {
             DocPath path = DocPath.relativePath(packageDoc, prev);
-            li = HtmlTree.LI(getHyperLink(path.resolve(DocPaths.PACKAGE_SUMMARY), "",
+            li = HtmlTree.LI(getHyperLink(path.resolve(DocPaths.PACKAGE_SUMMARY),
                 prevpackageLabel, "", ""));
         }
         return li;
@@ -284,7 +284,7 @@
             li = HtmlTree.LI(nextpackageLabel);
         } else {
             DocPath path = DocPath.relativePath(packageDoc, next);
-            li = HtmlTree.LI(getHyperLink(path.resolve(DocPaths.PACKAGE_SUMMARY), "",
+            li = HtmlTree.LI(getHyperLink(path.resolve(DocPaths.PACKAGE_SUMMARY),
                 nextpackageLabel, "", ""));
         }
         return li;
@@ -297,7 +297,7 @@
      * @return a content tree for the tree link
      */
     protected Content getNavLinkTree() {
-        Content useLink = getHyperLink(DocPaths.PACKAGE_TREE, "",
+        Content useLink = getHyperLink(DocPaths.PACKAGE_TREE,
                 treeLabel, "", "");
         Content li = HtmlTree.LI(useLink);
         return li;
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SplitIndexWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/SplitIndexWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -158,7 +158,7 @@
             return HtmlTree.LI(prevletterLabel);
         }
         else {
-            Content prevLink = getHyperLink(DocPaths.indexN(prev), "",
+            Content prevLink = getHyperLink(DocPaths.indexN(prev),
                     prevletterLabel);
             return HtmlTree.LI(prevLink);
         }
@@ -175,7 +175,7 @@
             return HtmlTree.LI(nextletterLabel);
         }
         else {
-            Content nextLink = getHyperLink(DocPaths.indexN(next), "",
+            Content nextLink = getHyperLink(DocPaths.indexN(next),
                     nextletterLabel);
             return HtmlTree.LI(nextLink);
         }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TagletWriterImpl.java	Tue Oct 23 13:58:56 2012 -0700
@@ -172,19 +172,24 @@
                 htmlWriter instanceof ClassWriterImpl) {
             //Automatically add link to constant values page for constant fields.
             result = addSeeHeader(result);
-            result += htmlWriter.getHyperLinkString(htmlWriter.pathToRoot.resolve(
-                DocPaths.CONSTANT_VALUES),
-                ((ClassWriterImpl) htmlWriter).getClassDoc().qualifiedName()
-                + "." + ((FieldDoc) holder).name(),
-                htmlWriter.configuration.getText("doclet.Constants_Summary"), false);
+            DocPath constantsPath =
+                    htmlWriter.pathToRoot.resolve(DocPaths.CONSTANT_VALUES);
+            String whichConstant =
+                    ((ClassWriterImpl) htmlWriter).getClassDoc().qualifiedName() + "." + ((FieldDoc) holder).name();
+            DocLink link = constantsPath.fragment(whichConstant);
+            result += htmlWriter.getHyperLinkString(link,
+                    htmlWriter.configuration.getText("doclet.Constants_Summary"),
+                    false);
         }
         if (holder.isClass() && ((ClassDoc)holder).isSerializable()) {
             //Automatically add link to serialized form page for serializable classes.
             if ((SerializedFormBuilder.serialInclude(holder) &&
                       SerializedFormBuilder.serialInclude(((ClassDoc)holder).containingPackage()))) {
                 result = addSeeHeader(result);
-                result += htmlWriter.getHyperLinkString(htmlWriter.pathToRoot.resolve(DocPaths.SERIALIZED_FORM),
-                        ((ClassDoc)holder).qualifiedName(), htmlWriter.configuration.getText("doclet.Serialized_Form"), false);
+                DocPath serialPath = htmlWriter.pathToRoot.resolve(DocPaths.SERIALIZED_FORM);
+                DocLink link = serialPath.fragment(((ClassDoc)holder).qualifiedName());
+                result += htmlWriter.getHyperLinkString(link,
+                        htmlWriter.configuration.getText("doclet.Serialized_Form"), false);
             }
         }
         return result.equals("") ? null : new TagletOutputImpl(result + "</dd>");
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/TreeWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -146,7 +146,7 @@
                 }
                 DocPath link = pathString(packages[i], DocPaths.PACKAGE_TREE);
                 Content li = HtmlTree.LI(getHyperLink(
-                        link, "", new StringContent(packages[i].name())));
+                        link, new StringContent(packages[i].name())));
                 if (i < packages.length - 1) {
                     li.addContent(", ");
                 }
--- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlDocWriter.java	Tue Oct 23 13:58:56 2012 -0700
@@ -31,6 +31,7 @@
 import com.sun.javadoc.*;
 import com.sun.tools.doclets.formats.html.ConfigurationImpl;
 import com.sun.tools.doclets.internal.toolkit.*;
+import com.sun.tools.doclets.internal.toolkit.util.DocLink;
 import com.sun.tools.doclets.internal.toolkit.util.DocPath;
 import com.sun.tools.doclets.internal.toolkit.util.DocPaths;
 
@@ -80,9 +81,14 @@
      * @param strong       Boolean that sets label to strong.
      * @return String    Hyper Link.
      */
-    public String getHyperLinkString(DocPath link, String where,
+    public String getHyperLinkString(DocPath link,
                                String label, boolean strong) {
-        return getHyperLinkString(link, where, label, strong, "", "", "");
+        return getHyperLinkString(link, label, strong, "", "", "");
+    }
+
+    public String getHyperLinkString(DocLink link,
+                               String label, boolean strong) {
+        return getHyperLinkString(link, label, strong, "", "", "");
     }
 
     /**
@@ -96,10 +102,16 @@
      * @param stylename  String style of text defined in style sheet.
      * @return String    Hyper Link.
      */
-    public String getHyperLinkString(DocPath link, String where,
+    public String getHyperLinkString(DocPath link,
                                String label, boolean strong,
                                String stylename) {
-        return getHyperLinkString(link, where, label, strong, stylename, "", "");
+        return getHyperLinkString(link, label, strong, stylename, "", "");
+    }
+
+    public String getHyperLinkString(DocLink link,
+                               String label, boolean strong,
+                               String stylename) {
+        return getHyperLinkString(link, label, strong, stylename, "", "");
     }
 
     /**
@@ -112,7 +124,7 @@
      */
     public Content getHyperLink(String where,
                                Content label) {
-        return getHyperLink(DocPath.empty, where, label, "", "");
+        return getHyperLink(DocLink.fragment(where), label, "", "");
     }
 
     /**
@@ -124,9 +136,14 @@
      * @param label      Tag for the link.
      * @return a content tree for the hyper link
      */
-    public Content getHyperLink(DocPath link, String where,
+    public Content getHyperLink(DocPath link,
                                Content label) {
-        return getHyperLink(link, where, label, "", "");
+        return getHyperLink(link, label, "", "");
+    }
+
+    public Content getHyperLink(DocLink link,
+                               Content label) {
+        return getHyperLink(link, label, "", "");
     }
 
     /**
@@ -138,33 +155,27 @@
      * @param label      Tag for the link.
      * @param strong       Boolean that sets label to strong.
      * @param stylename  String style of text defined in style sheet.
-     * @param title      String that describes the link's content for accessibility.
+     * @param title      String that describes the links content for accessibility.
      * @param target     Target frame.
      * @return String    Hyper Link.
      */
-    public String getHyperLinkString(DocPath link, String where,
+    public String getHyperLinkString(DocPath link,
                                String label, boolean strong,
                                String stylename, String title, String target) {
-        return getHyperLinkString(link.getPath(), where, label, strong,
+        return getHyperLinkString(new DocLink(link), label, strong,
                 stylename, title, target);
     }
 
-    public String getHyperLinkString(String link, String where,
+    public String getHyperLinkString(DocLink link,
                                String label, boolean strong,
                                String stylename, String title, String target) {
         StringBuilder retlink = new StringBuilder();
-        retlink.append("<a href=\"");
-        retlink.append(link);
-        if (where != null && where.length() != 0) {
-            retlink.append("#");
-            retlink.append(where);
-        }
-        retlink.append("\"");
+        retlink.append("<a href=\"").append(link).append('"');
         if (title != null && title.length() != 0) {
-            retlink.append(" title=\"").append(title).append("\"");
+            retlink.append(" title=\"").append(title).append('"');
         }
         if (target != null && target.length() != 0) {
-            retlink.append(" target=\"").append(target).append("\"");
+            retlink.append(" target=\"").append(target).append('"');
         }
         retlink.append(">");
         if (stylename != null && stylename.length() != 0) {
@@ -197,17 +208,14 @@
      * @param target     Target frame.
      * @return a content tree for the hyper link.
      */
-    public Content getHyperLink(DocPath link, String where,
-            Content label, String title, String target) {
-        return getHyperLink(link.getPath(), where, label, title, target);
-    }
-    public Content getHyperLink(String link, String where,
+    public Content getHyperLink(DocPath link,
             Content label, String title, String target) {
-        if (link.startsWith("/")) Thread.dumpStack();
-        if (where != null && where.length() != 0) {
-            link += "#" + where;
-        }
-        HtmlTree anchor = HtmlTree.A(link, label);
+        return getHyperLink(new DocLink(link), label, title, target);
+    }
+
+    public Content getHyperLink(DocLink link,
+            Content label, String title, String target) {
+        HtmlTree anchor = HtmlTree.A(link.toString(), label);
         if (title != null && title.length() != 0) {
             anchor.addAttr(HtmlAttr.TITLE, title);
         }
@@ -218,17 +226,6 @@
     }
 
     /**
-     * Get a hyperlink to a file.
-     *
-     * @param link String name of the file
-     * @param label Label for the link
-     * @return a content for the hyperlink to the file
-     */
-    public Content getHyperLink(DocPath link, Content label) {
-        return getHyperLink(link, "", label);
-    }
-
-    /**
      * Get link string without positioning in the file.
      *
      * @param link       String name of the file.
@@ -236,7 +233,7 @@
      * @return Strign    Hyper link.
      */
     public String getHyperLinkString(DocPath link, String label) {
-        return getHyperLinkString(link, "", label, false);
+        return getHyperLinkString(link, label, false);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocLink.java	Tue Oct 23 13:58:56 2012 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 com.sun.tools.doclets.internal.toolkit.util;
+
+/**
+ * Abstraction for simple relative URIs, consisting of a path,
+ * an optional query, and an optional fragment. DocLink objects can
+ * be created by the constructors below or from a DocPath using the
+ * convenience methods, {@link DocPath#fragment fragment} and
+ * {@link DocPath#query query}.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ *
+ */
+public class DocLink {
+    final String path;
+    final String query;
+    final String fragment;
+
+    /** Create a DocLink representing the URI {@code #fragment}. */
+    public static DocLink fragment(String fragment) {
+        return new DocLink((String) null, (String) null, fragment);
+    }
+
+    /** Create a DocLink representing the URI {@code path}. */
+    public DocLink(DocPath path) {
+        this(path.getPath(), null, null);
+    }
+
+    /**
+     * Create a DocLink representing the URI {@code path?query#fragment}.
+     * query and fragment may be null.
+     */
+    public DocLink(DocPath path, String query, String fragment) {
+        this(path.getPath(), query, fragment);
+    }
+
+    /**
+     * Create a DocLink representing the URI {@code path?query#fragment}.
+     * Any of the component parts may be null.
+     */
+    public DocLink(String path, String query, String fragment) {
+        this.path = path;
+        this.query = query;
+        this.fragment = fragment;
+    }
+
+    /**
+     * Return the link in the form "path?query#fragment", omitting any empty
+     * components.
+     */
+    @Override
+    public String toString() {
+        // common fast path
+        if (path != null && isEmpty(query) && isEmpty(fragment))
+            return path;
+
+        StringBuilder sb = new StringBuilder();
+        if (path != null)
+            sb.append(path);
+        if (!isEmpty(query))
+            sb.append("?").append(query);
+        if (!isEmpty(fragment))
+            sb.append("#").append(fragment);
+        return sb.toString();
+    }
+
+    private static boolean isEmpty(String s) {
+        return (s == null) || s.isEmpty();
+    }
+}
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocPath.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/DocPath.java	Tue Oct 23 13:58:56 2012 -0700
@@ -32,6 +32,11 @@
 /**
  * Abstraction for immutable relative paths.
  * Paths always use '/' as a separator, and never begin or end with '/'.
+ *
+ *  <p><b>This is NOT part of any supported API.
+ *  If you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
  */
 public class DocPath {
     private final String path;
@@ -177,6 +182,14 @@
         return path.isEmpty();
     }
 
+    public DocLink fragment(String fragment) {
+        return new DocLink(path, null, fragment);
+    }
+
+    public DocLink query(String query) {
+        return new DocLink(path, query, null);
+    }
+
     /**
      * Return this path as a string.
      */
--- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Extern.java	Tue Oct 23 13:20:37 2012 -0700
+++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Extern.java	Tue Oct 23 13:58:56 2012 -0700
@@ -138,24 +138,25 @@
      *
      * @param pkgName The package name.
      * @param relativepath    The relative path.
-     * @param link    The link to convert.
+     * @param filename    The link to convert.
      * @return if external return converted link else return null
      */
-    public String getExternalLink(String pkgName,
-                                  DocPath relativepath, String link) {
+    public DocLink getExternalLink(String pkgName,
+                                  DocPath relativepath, String filename) {
+        return getExternalLink(pkgName, relativepath, filename, null);
+    }
+
+    public DocLink getExternalLink(String pkgName,
+                                  DocPath relativepath, String filename, String memberName) {
         Item fnd = findPackageItem(pkgName);
-        if (fnd != null) {
-            String externlink = fnd.path + link;
-            if (fnd.relative) {  // it's a relative path.
-                if (relativepath.isEmpty())
-                    return externlink;
-                else
-                    return relativepath.getPath() + "/" + externlink;
-            } else {
-                return externlink;
-            }
-        }
-        return null;
+        if (fnd == null)
+            return null;
+
+        DocPath p = fnd.relative ?
+                relativepath.resolve(fnd.path).resolve(filename) :
+                DocPath.create(fnd.path).resolve(filename);
+
+        return new DocLink(p, "is-external=true", memberName);
     }
 
     /**