Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven javadoc - how to include centralized resources

I'm trying to include centralized resources (e.g. image files, js files) into my Maven generated javadoc. Such centralized resources would come from a dependency. (in my case I would like to always include certain resources, Javascript files, that allows to do nice syntax highlighting of example code inside Javadoc, and also to use a special stylesheet)

There's substantial information on how to do this if you include your resources locally with your project. That's not what I want as I need to do this for every project in my company. So the configuration needs to go into the company-wide POM file from which all projects in our company inherit.

Note that for stylesheet this is pretty easy to do as the Maven plugin allows for this file to come from a dependency. I'm looking for something similar, except for 'resources'. Basically it would seem silly that I would have to copy things like our company logo into every project. That's what I would like to avoid.

If this is not directly supported by the Maven Javadoc Plugin (I cannot figure out if it is) then I'm guessing an alternative approach might be to use the Maven Dependency Plugin to copy my centralized javadoc resources into the project. However that approach has at least two drawbacks:

  1. Such dependency is not a real dependency of the project and shouldn't be stated as such. It is a dependency of the maven-javadoc-plugin, not of the project itself.

  2. I would need to figure out a way so that the copying of the dependency into the project only happens when javadoc generation is requested.

Please help.

like image 997
peterh Avatar asked May 28 '15 13:05

peterh


1 Answers

I've completely overlooked the resourcesArtifacts config parameter on the Maven Javadoc plugin. This is the key to getting this to work.

I'll explain this in two steps:

  1. A Maven project to hold your centralized Javadoc assets (customized stylesheet (if you want), logos, javascript libs, etc.)

  2. What to put into your company-wide pom in order to have all Javadocs in your company look the same.

Javadoc customization project

This 'project' will hold your custom Javadoc assets. It is a Maven project, but it doesn't contain any Java source code. Just create a standard Maven project. Create a src/main/resources directory. Everything you put into this directory will eventually be put into the root of every Javadoc bundle you create. If you put a file name of say stylesheet.css in there it will effectively overwrite the standard Javadoc stylesheet.

I my src/main/resources directory I have:

  1. A stylesheet.css file. This file is our company version of Javadoc stylesheet. It is a bit different from the standard stylesheet in that it fixes some JDK8 deficiencies (JDK8 javadoc readability sucks) but also changes some colors to be inline with company branding and so on.

  2. A subdir, syntaxhighlighter into which I put relevant files from SyntaxHighlighter. In my case those files are shCore.js, shBrushJava.js, shCore.css and shThemeDefault.css since I only care about syntax highlighting for Java language and since I want to use the default theme for SyntaxHighlighter.

My project's Maven coordinates are

<groupId>com.acme.javadoc</groupId>
<artifactId>customization</artifactId>

but feel free to name it anyway you like.

Remember: this is just a standard Maven project so you can put it under source control and so on.

Now build (and possibly release) this project.

Changes to company-wide POM

The recipe below assumes you have some kind of company-wide POM which allows you to make Maven customizations for many projects in one place. If you don't have such a central parent POM then you'll have to do the below in each and every project instead.

<profiles>
    <profile>
        <activation>
            <jdk>1.8</jdk>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-javadoc-plugin</artifactId>
                    <version>2.10.3</version>
                    <configuration>
                        <resourcesArtifacts>
                            <resourceArtifact>
                                <groupId>com.acme.javadoc</groupId>
                                <artifactId>customization</artifactId>
                                <version>1.0-SNAPSHOT</version>
                            </resourceArtifact>
                        </resourcesArtifacts>
                        <!-- Add SyntaxHighlighter feature.
                              This gets added to the top of every Javadoc html file -->
                        <top><![CDATA[
                            <script src="{@docRoot}/syntaxhighlighter/shCore.js" type="text/javascript"></script>
                            <script src="{@docRoot}/syntaxhighlighter/shBrushJava.js" type="text/javascript"></script>
                            <link href="{@docRoot}/syntaxhighlighter/shCore.css" rel="stylesheet" type="text/css" title="Style">
                            <link href="{@docRoot}/syntaxhighlighter/shThemeDefault.css" rel="stylesheet" type="text/css" title="Style">
                            ]]>
                        </top>                            
                        <!-- Activate and customize SyntaxHighlighter feature 
                             This gets added to the bottom of every Javadoc html file -->
                        <footer><![CDATA[
                            <script type="text/javascript">
                               SyntaxHighlighter.defaults["auto-links"] = false;
                               SyntaxHighlighter.defaults["tab-size"] = 2;
                               SyntaxHighlighter.all();
                            </script>
                        ]]></footer>                            
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>    

What will happen is this: Everytime a project which inherits from the company-wide POM creates a Javadoc package it will do so with the maven-javadoc-plugin settings above. As you notice the whole thing is put into a profile and only activated if the Maven build is running under JDK8. If you don't want this condition you can change it so the profile is always activated rather than being conditionally activated.

The resourceArtifact points to our project with our Javadoc assets. This artifact (which is a jar) gets unpacked into the generated Javadoc bundle's root dir. It wasn't clear to me from the documentation that there's an unpack going on, but there is indeed. The stuff from the resourceArtifact jar gets copied blindly into the bundle so be careful with your naming. It will overwrite anything of a similar name. In the case of our stylesheet.css file this is actually what we want so that's good. In any case you just need to be careful about what you put into your Javadoc customization project.

What we have achieved

  1. Javadoc resources (stylesheet, logo, JS files) can be under source control.
  2. Javadoc resources can be centralized.
  3. Added the ability to do syntax highlighting when writing Java code snippets in Javadoc comments.
  4. The created Javadoc bundle is self-contained. Doesn't depend on any external resources.

How to do syntax highlighting in Javadoc

With the above all your Javadocs automatically now inherit the ability to do syntax highlighting. All you have to do is add class="bruch:java" to your <pre> tags. Here's an example:

/**
 * Howdy devs. Normally you would use create a
 * class something like this:
 * 
 * 
 * <pre class="brush:java">
 * public class MyClass1 {
 *   
 *   public static String getVar(String x1, int x2) {
 *      if ( 3 &lt; 10 ) {
 *         return "x"; 
 *      } else {
 *         return "y";
 *      }
 *   }
 * } 
 * </pre>
 * 
 * That's all, folks.
 * 
 * @since 1.3
 */

Note how I had to escape the < sign. The standard trick that many of us are using to avoid having to do this, embedding {@code} inside <pre> tags, doesn't work with SyntaxHighlighter. Eeew.

And this is what it will look like in the Javadoc:

enter image description here

Tada !

You can expand on the recipe to add more customization, e.g. always put a company logo in the Javadoc footer, etc.

Performance of this solution

Every time you do a Javadoc build you'll notice this additional step in your Maven output:

enter image description here

It will probably steal a second or two of your build time - if not less. And only when building Javadoc artifacts of course.

UPDATE RELATED TO JDK 8u121

As of JDK 8u121 the Javadoc tool (javadoc) will no longer by default allow you to include Javascript resources in your build. See Release Notes for more information. The Maven Javadoc Plugin implicitly uses the javadoc tool and is therefore affected as well. There's a new command line parameter to javadoc that needs to be added in order to make it work : --allow-script-in-comments.

In other words if you are using JDK 8u121 or later then your company-wide POM should add this command line parameter:

<profiles>
    <profile>
        <activation>
            <jdk>1.8</jdk>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-javadoc-plugin</artifactId>
                    <version>2.10.3</version>
                    <configuration>
                        ...
                        ...
                        <!-- Required as of JDK 8u121 -->
                        <additionalparam>--allow-script-in-comments</additionalparam>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>    

That bad thing about what Oracle has done is that the build is now dependent on JDK minor version number. If you happen to use the above on JDK prior to 8u121 it will exit with error because the --allow-script-in-comments is unknown.

like image 63
peterh Avatar answered Sep 16 '22 22:09

peterh