correctly render javadoc method links to external html javadoc documents that use dashes instead of parentheses and commas

Viewed 247

HTML javadoc documents that were generated with javadoc tool from Java version 10 and newer use parentheses ( ) and commas , in method links/labels, for example: https://docs.oracle.com/javase/10/docs/api/java/lang/Object.html#wait(long,int).
Older versions however replace these characters with a dash -, for example: https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#wait-long-int-.
(kudos to this answer for explaining that format depends on javadoc version)

Now, when building a project with Java version 10+, how can I make maven-javadoc-plugin render proper links to methods from projects that had their HTML javadoc documents generated with older versions? (i.e. when one of the <link> tag in pom.xml in maven-javadoc-plugin's configuration section points to a set of HTML javadoc documents that use dashes instead of parentheses and commas).
By default, parentheses and commas are used, which results in links leading to the top of the given class's page instead of the desired method section.

Using an older javadoc tool to generate HTML for the project that uses Java 10+ is not a solution as in such case links to methods from standard libraries at docs.oracle.com (or to any other external projects built with java 10+) would be broken. A definitive solution must be applicable to a specific <link> section only.

2 Answers

According to RFC 3986 both variants are valid.

For instance, URL fragments for methods with parameters for Java <=9 look like:

https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#equals-java.lang.Object-

and for Java 10–17 they look like:

https://docs.oracle.com/javase/10/docs/api/java/lang/Object.html#equals(java.lang.Object)

If you {@link ...} to the Javadoc of a library that used a different tool to create its Javadoc than you do (or used a different version of the same tool) you're out of luck for the moment.

If we really do not find an according option at the Javadoc tool(s) (and I think we won't because why should external links be handled differently than internal ones) the first that comes into my mind is the Maven Resources Plugin. It has the feature of resource filtering (which is bad naming, since in fact it's string interpolation) and perhaps this could be used to replace the characters accordingly.

If that doesn't work there are other options, like running an external program, e.g. sed, during a build. Let me think a while and try some things. I'm confident that I can come up with a working solution. However, please be patient. It's 4:30 a.m. here now and I think I need some hours of sleep soon. If someone comes up with a solution in the meantime, the better (though I don't think so but who knows... :)

Approach #1 – --release option

There's javadoc's --release option:

The following core javadoc options are equivalent to corresponding javac options. See Standard Options for the detailed descriptions of using these options:

  • ...
  • --release

javac's --release:

[Well, that's funny...well, no, it's embarassing: The deep links to --release and its Note: ... dont' work in the end because centiseconds after jumping to them apparently a JS (AJAX?) comes into play and the page finally lands at its top. I want Sun Microsystems back!]

--release release

Compiles against the public, supported and documented API for a specific VM version. Supported release targets are 6, 7, 8, 9, 10, and 11.

If this javadoc --release solves your problem we dont' have to think further for a handmade solution.

Update: The --release/<release> option doesn't solve the problem. It's just to specify the link target version as in https://docs.oracle.com/javase/<version>/docs/api/.... The docs above aren't too helpful in this regard and the maven-javadoc-plugin doc isn't either: "<release> Provide source compatibility with specified release". At least it's documented here now. ;)

Approach #2 – Maven resource filtering

Maven's resource filtering doesn't help either since in Javadoc comments method references for methods with just one parameter can look like:

/**
 * <p>Link to {@link Logger#info}</p>
 * <p>Link to {@link Object#equals}</p>
 */

and for string interpolation we would need ${...} (or the not well-known and unusual @...@) definitions.

It would work (in theory) with the explicit form:

/**
 * <p>"${(}" and "${)}" replaced by '-', if the additional '{' and '}' don't conflict with Javadoc comment's tags – but it seems they do</p>
 * <p>Link to {@link Logger#info${(}String${)}}</p>
 * <p>Link to {@link Object#equals${(}Object${)}}</p>
 *
 * <p> "@(@" and "@)@" replaced by '-'</p>, if the additional '@'s don't conflict with Javadoc comment's tags – but it seems they do</p>
 * <p>Link to {@link Logger#info@(@String@)@}</p>
 * <p>Link to {@link Object#equals@(@Object@)@}</p>
 */

I don't know (yet) whether these "reserved characters" can be escaped and if yes, how this could be done. I found How do you escape curly braces in javadoc inline tags, such as the {@code} tag but nothing from there works with {@link ...} (yet).

UPDATE

Approach #3 – Maven XML Plugin's xml:transform

Doesn't work since the Javadoc HTMLs contain non-X(HT)ML-conformant unclosed <meta ... >s and <link ... >s.

Approach #4 a) – Groovy script via the GMavenPlus Plugin

Using FileVisitor, XPath – if that works with the non-X(HT)ML-conformant HTML – or whatever works then.

XPath doesn't work: [Fatal Error] :18:3: The element type "link" must be terminated by the matching end-tag "</link>".

Approach #4 b) – Revive one of maven-javascript-plugin or Maven Javascript Plugin, ...

... add a goal javascript:execute and use a JS script with its CSS selectors and DOM manipulation.

After much searching, I’m inclined to believe that it’s easier to just use Ant inside your pom.xml to change parentheses to hyphens, than to try to look for a dedicated plugin:

<plugin>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <phase>prepare-package</phase>
      <configuration>
        <target>
          <replaceregexp
              match='(&lt;a href="[^"]*grpc[^"]*)[(]([^)"]*)[)]("[^&gt;]* class="external-link")'
              replace="\1-\2-\3"
              flags="g">
            <fileset dir="${project.reporting.outputDirectory}/apidocs"
                     includes="**/*.html"/>
          </replaceregexp>
        </target>
      </configuration>
      <goals>
        <goal>run</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Unfortunately, I don’t have a way to test it.

Related