Showing posts with label javadoc. Show all posts
Showing posts with label javadoc. Show all posts

Thursday, 5 October 2023

Creating an @plantuml Javadoc Custom Taglet

I love PlantUML, easily create UML diagrams using a description instead of having to draw them myself.

One thing I didn't like was the need to have to install the library GraphViz1 everywhere, where I wanted to use PlantUML.

But imagine my surprise when I found out, that I don't need to any more.

The java library Smetana2, which apparently functions as a drop in replacement for GraphViz should work exactly the same. And it's already integrated in PlantUML!

Can things get any better?

So, once more, let me integrate it into my javadoc build workflow of my sample Java Project using maven.

I had the idea to create a Java Doclet for generating my javadoc, but I quickly realised I should be making a PlantUML Taglet instead. It's already been done, see [3], but I wanted something a little different. But I did get some good ideas from that site.

I wanted to inline the imagedata in the src attribute of the image tag, that seems nicer than separate png files.

I also wanted to use the Smetana by default.

I managed it and uploaded it on the github4.

Maven integration

Adding the custom taglet to your pom.xml in the javadoc plugin should be enough. You do need to have my custom Taglet installed in your maven .m2/repository directory though.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <version>3.6.0</version>
  <configuration>
    <taglet>org.taglet.plantuml.PlantumlTaglet</taglet>
    <!-- <tagletpath>/path/to/taglet.jar</tagletpath> -->
    <tagletArtifact>
      <groupId>org.taglet.plantuml</groupId>
      <artifactId>plantumltaglet</artifactId>
      <version>1.0</version>
    </tagletArtifact>
  </configuration>
</plugin>

The following is sufficient to run javadoc and generate the diagrams:

mvn javadoc:javadoc

Eating your own dogfood

It also serves as a good example of eating your own dog food5.

That's right!

I added PlantUML diagrams to the javadocs of my new PlantUML Taglet, and generated the javadoc+diagrams using my PlantUML Taglet!

/**
 * Created PlantUML Diagrams based on a plantuml description.
 * @plantuml
 * PlantumlImageDataFactory : +getImageData(plantuml: String): String
 */
public class PlantumlImageDataFactory {

Worked like a charm!

It will look like this:

The image will be as raw data in the html source code, like so:

<section class="class-description" id="class-description">
<dl class="notes">
<dt>All Implemented Interfaces:</dt>
<dd><code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/jdk.javadoc/jdk/javadoc/doclet/Taglet.html" title="class or interface in jdk.javadoc.doclet" class="external-link">Taglet</a></code></dd>
</dl>
<hr>
<div class="type-signature"><span class="modifiers">public class </span><span class="element-name type-name-label">PlantumlTaglet</span>
<span class="extends-implements">extends <a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html" title="class or interface in java.lang" class="external-link">Object</a>
implements <a href="https://docs.oracle.com/en/java/javase/17/docs/api/jdk.javadoc/jdk/javadoc/doclet/Taglet.html" title="class or interface in jdk.javadoc.doclet" class="external-link">Taglet</a></span></div>
<div class="block">A Taglet made by me to convert appropriate Plantuml codes into generated diagrams. Uses layout smetana instead
 of GraphViz.</div>
<dl class="notes">
<dt>See Also:</dt>
<dd>
<ul class="tag-list">
<li><a href="https://mnlipp.github.io/jdrupes-taglets/plantuml-taglet/javadoc/index.html">PlantUML Taglet</a></li>
</ul>
</dd>
<p><img alt="umldiagram" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhMAAAC2CAIAAADsj5gHAAAAKnRFWHRjb3B5bGVmdABHZW5lcmF0ZWQgYnkgaHR0cHM6Ly9wbGFudHVtbC5jb212z..." /></p></dl>
</section>

References

[1] PlantUML - GraphViz-Dot
https://plantuml.com/graphviz-dot
[2] PlantUML - Porting GraphViz to Java
https://plantuml.com/smetana02
[3] PlantUML Taglet
https://mnlipp.github.io/jdrupes-taglets/plantuml-taglet/javadoc/index.html
[4] Github.com - PlantUML Taglet
https://github.com/maartenl/plantumltaglet
[5] Wikipedia - Eating your own dog food
https://en.wikipedia.org/wiki/Eating_your_own_dog_food

Thursday, 27 February 2020

JavaDoc that makes my head hurt

I found the following javadoc in our source code. It makes my head hurt.

/**
 * Marker interface that marks an executor as a refresh field definitions query executor,
 * i.e. a query executor that refreshes the field definitions.
 */
public interface RefreshFieldDefinitionsQueryExecutor {
}

It repeats the same thing at least three times, twice in the comments and once in the name of the marker interface.

And still I am no closer to understanding what it does.

Thursday, 18 January 2018

An error has occurred in JavaDocs report generation

Well, it turns out that this blog1 is an almost word-for-word mirror of an article2 about using Maven and Java 8 to generate the JavaDocs.

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 12.431 s
[INFO] Finished at: 2017-05-17T21:13:32+02:00
[INFO] Final Memory: 21M/157M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:2.9.1:javadoc (default-cli) on project mrbear: An error has occurred in JavaDocs report generation:
[ERROR] Exit code: 1 - /home/mrbear/beargame/src/main/java/awesomeness/vaadin/editor/Buttons.java:56: warning: no description for @return
[ERROR] * @return
[ERROR] ^

Turns out Malformed HTML is now a thing that bombs your javadoc generation. Add "-Xdoclint:none" somewhere to turn this off.

References

[1] Stephen Colebourne's blog - Turning off doclint in JDK 8 Javadoc
http://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html
[2] NLJUG Java Magazine
http://www.nljug.org/

Thursday, 21 April 2016

Constructors, Javadoc and Inheritance

I recently had the problem that I defined some very good javadoc documentation on a constructor in one of my generic classes that is inherited a lot.

The documentation, however, is never propagated to subclasses, because constructors are not inherited1.

It is too bad that I already have to duplicate Constructors in my subclasses, but now I have to duplicate the documentation as well?

Right now, the best solution I can think of is to add a "@see" link to the appropriate super constructor. Like so:

There is a feature request/bug2 defined to expand the {inheritedDoc} to also work on constructors. But it has not seen any love for a long time.

References

[1] StackOverflow - Why is inheritedDoc not defined on constructors?
http://stackoverflow.com/questions/14848999/why-is-inheriteddoc-not-defined-on-constructors
[2] JDK-4810216 : Allow {@inheritDoc name} for constructors
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4810216

Thursday, 17 March 2016

Humour in Javadoc

I found this little gem that made me chuckle from Gavin King.
/**
 * A copy of the EE5 standard InvocationContext API.
 * We do this because some poor souls are still using
 * J2EE. Pray for them.
 * 
 * @author Gavin King
 *
 */

public interface InvocationContext
{
   public Object getTarget();
   public Map getContextData();
   public Method getMethod();
   public Object[] getParameters();
   public Object proceed() throws Exception;
   public void setParameters(Object[] params);
}

Monday, 12 January 2015

Are Comments Necessary?

There are a lot of opinions on Comments in code.

In the words of Uncle Bob1:
“The proper use of comments is to compensate for our failure to express ourselves in code.”
Here are some things to remember:
  • Code is Leading.
  • If comments and code do not match up, the comments are wrong.
  • Code is always current, comments age.
There are two ways we can deal with unclear source code:
  1. add comments, if the source code is unclear
  2. refactor the code, if the source code is unclear, until the code is clear
The second option seems the best.

However, if the code is abstract, but the implementation refers to a (potentially complicated) knowledge domain, comments are a requirement.

However, sometimes the code should follow the knowledge domain. You try to implement the Knowledge Domain as faithfully as possible, to sort of map it one-on-one, if possible. If that succeeds, what you end up with is a Domain Specific Language (DSL).

Example

For example, in my job I work with valuation of houses. There are several characteristics that account for the value of a house.
  • location
  • quality
  • maintenance
  • appearance
  • purpose
  • facilities
Now, these individual items were stored in the record for a House.

Here is roughly my iterative software development written out:
  1. I added comments on each of these (on the getters and setters) to indicate that it was a value characteristic. (instead of, for example, an address, price, year of construction, etc.).
  2. I thought about it, and decided that this was a group of related data.
  3. I made a class ValueCharacteristics, that contained all these.
  4. I removed the comments.
Added bonus: once a value characteristic is added or removed, the different places where this will impact my code are much more clearly visible.

Conclusion

The steps you take can be generified as follows:
  1. If the code is unclear, try and add comments.
  2. Then try and think how you can change the code to better reflect the comments.
  3. Change the code.
  4. Remove the comments.
Comments can cause us to think about the code we produce.

Always keep in mind, if you have to add lots of comments to a piece of code, perhaps it is time to refactor instead.

I think that comments can still provide insight in "why" we do things, whereas the code only tells us "how" we do things.

References

[1] Clean Code - Chapter 4 - Comments
Robert C. Martin (Uncle Bob)

Friday, 19 September 2014

Maven and PlantUML

This blog explains about integrating PlantUML with Netbeans and Maven. For integrating PlantUML with Netbeans and Ant, see my previous blogpost here.

The blog at [2] explained to me how to add PlantUML to my Maven project, using the special plugin developed by jeluard1.

Just adding the following to the plugins did the trick:
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
    <groupId>com.github.jeluard</groupId>
    <artifactId>plantuml-maven-plugin</artifactId>
    <version>1.1</version>
    <configuration>
        <outputInSourceDirectory>false</outputInSourceDirectory>
        <outputDirectory>${basedir}/target/site/apidocs</outputDirectory>
        <sourceFiles>
            <directory>${basedir}/src/main/java/</directory>
            <includes>
                <include>**/*.java</include>
            </includes>
        </sourceFiles>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>net.sourceforge.plantuml</groupId>
            <artifactId>plantuml</artifactId>
            <version>8004</version>
        </dependency>
    </dependencies>
</plugin>

Netbeans and Maven

In Netbeans you can select Actions on your project to perform. There is a coupling between the action and the goals in Maven that are executed3.

These can be changed by going to your Netbeans Project Properties (right-click your project, select properties) - select "Actions" - select "Generate Javadoc".

Then add the plantuml Maven goal, com.github.jeluard:plantuml-maven-plugin:generate. You're likely to end up with the following:
generate-sources javadoc:javadoc com.github.jeluard:plantuml-maven-plugin:generate

References

[1] GitHub - jeluard/maven-plantuml-plugin
https://github.com/jeluard/maven-plantuml-plugin
[2] Smartics - Using PlantUML
http://www.smartics.de/archives/1313
[3] Netbeans - MavenBestPractices
http://wiki.netbeans.org/MavenBestPractices

Friday, 15 August 2014

Java Enum values() method

I remember there being a values() method that provides all possible values of an Enumerated Type in Java. I checked the javadoc1 and couldn't find it...

But it exists.

Which is weird.

Luckily, someone else had the same problem and asked it in [2].

I was intriged so I looked up the Language Spec3. Yes, the method is available in each and every Enum class, but it is 'especially' inserted by the compiler and not inherited from the superclass4.

Luckily in the javadoc1, values() and valueOf(String) methods are both mentioned in the description of the valueOf(Class<T> , String) method (nowadays).

References

[1] Javadoc - Enum
http://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html
[2] CodeRanch - Values method documented Enum
http://www.coderanch.com/t/559674/java/java/values-method-documented-Enum
[3] Oracle - The Java Language Specification (Java 8)
http://docs.oracle.com/javase/specs/jls/se8/jls8.pdf
[4] Oracle Java Tutorials - Enum Types
http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

Sunday, 16 February 2014

package.html vs. package-info.java

Found a good reference1 on why you should use a package-info.java class.

Notes:
  • can contain (package) annotations
  • package-info is not a legal identifier for a class2. So there's no chance of mistakes from the compiler.
  • “It is recommended that package-info.java, if it is present, take the place of package.html for javadoc and other similar documentation generation systems.”2
  • you're not messing up your source files with .html files, which was in fact the case with the old package.html.

References

[1] Javadoc: package.html or package-info.java
http://stackoverflow.com/questions/3644726/javadoc-package-html-or-package-info-java
[2] The Java™ Language Specification - Java SE 7
http://docs.oracle.com/javase/specs/

Saturday, 11 February 2012

PlantUML and NetBeans

If you're looking to integrate PlantUML with Netbeans with Maven, check out my blogpost here.

Introduction


One of the problems with software designers is that they do not enjoy writing Documentation. I do, but then again, I'm weird.

Now Documentation in the area of Java can be split up into two categories:
  • Javadoc comments, that reside in the Java source code, right where it matters
  • Specs, design documents, etc. which are made when the system is first designed and are then stored on a network drive or (if you're lucky) a version control system. They are never updated, become outdated, and forgotten but are sometimes used to provide new junior designers with a wrong idea of the architecture.
So, ideally, you'd wish to have all the specs on hand in the same fashion as your javadoc, with the hope that any change in the code by dilligent designers is also propagated in the javadoc.6

This is where I find PlantUML1 to be extremely handy.

Installing PlantUML in Netbeans


The following task addition lifted straight from the pages of PlantUML and added to build.xml in the netbeans project.
<!-- task definition -->
<taskdef name="plantuml"
  classname="net.sourceforge.plantuml.ant.PlantUmlTask"
  classpath="plantuml.jar" />


<!-- process ./src files -->
<target depends="javadoc-build" name="build-uml">
    <mkdir dir="${dist.javadoc.dir}/images"/>
    <!-- there is an issue where relative paths do not work -->
    <plantuml output="/home/mrbear/NetBeansProjects/YourProject/${dist.javadoc.dir}/images/" verbose="true">
        <fileset dir="./src">
            <include name="**/*.java" />
            <exclude name="**/*Test.java" />
        </fileset>
    </plantuml>
</target>
This won't work, as plantuml.jar cannot be found automatically. Once you've downloaded it you can let your project know where it is. A good explanation of this can be found at [3].

Running PlantUML and Javadoc


First of all, we add the uml syntax2 to the javadoc comments.
/**
 *
 * <p>Indicates the different sizes that are possible in the displaying
 * of pictures. BIG being un-scaled.</p>
 * <img src="../../images/ImageSize.png"/>
 * @author maartenl
 *
 * @startuml
 * "java.lang.Enum<ImageSize>" <|-- enum ImageSize
 * ImageSize : +ImageSize BIG
 * ImageSize : +ImageSize LARGE
 * ImageSize : +ImageSize MEDIUM
 * ImageSize : +ImageSize THUMB
 * ImageSize : +getHeight()
 * ImageSize : +getWidth()
 * @enduml
 */

public enum ImageSize
{

Build the "build-uml" target. It will automatically generate all the javadocs and start off generating uml diagrams. You can do this in the Files explorer in netbeans, right-click on build.xml on toplevel and select the appropriate run target. When the "build-uml" ant target is started in netbeans, the following output is shown:

main:
Starting PlantUML
Nb images generated: 1
BUILD SUCCESSFUL (total time: 0 seconds)

The webpage will look like the image below![5] Voilà, uml diagrams!

Issues

- Two files have the same name, so they both create the same named image file. And they get copied in the ant task, so only one of them remains!

The easiest solution is to add a filename after the "@startuml" command, to indicate the name of the image. This is especially important if you have two or more diagrams within the same Java file. I found it especially convenient when dealing with UML diagrams in package-info.java files.

A better solution would be to update the Ant task to take care of this automatically.

- I'm getting "taskdef class net.sourceforge.plantuml.ant.PlantUmlTask cannot be found using the classloader AntClassLoader[]"!

Make sure the plantuml.jar file is reachable in the classpath.

- Auto formatting in Netbeans of my Java source code throws my carefully created UML specs in the Javadoc into disarray!

Yes, while Eclipse has a /* @formatter:on */ editor annotation, I have been unable to find the same in Netbeans.

For now, the only solution I have found it to turn on 'explicit newlines' in formatting of the javadoc comments. You can do this by going in Netbeans to Tools->Options->Editor->Formatting->select Java->Category Comments and turn on "Preserve New Lines".

- The image shows errors, something like the image below.
Dot Executable: /usr/bin/dot
File does not exist
Cannot find Graphviz. You should try

@startuml
testdot
@enduml

or

java -jar plantuml.jar -testdot

It means you haven't installed the graphviz4 package that takes care of a lot of rendering.

root@localhost:~# apt-get install graphviz
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  libcgraph5 libgvpr1
Suggested packages:
  graphviz-doc
The following NEW packages will be installed:
  graphviz libcgraph5 libgvpr1
0 upgraded, 3 newly installed, 0 to remove and 197 not upgraded.
Need to get 553 kB of archives.
After this operation, 1,741 kB of additional disk space will be used.
Do you want to continue [Y/n]? y
Get:1 http://nl.archive.ubuntu.com/ubuntu/ natty/main libcgraph5 i386 2.26.3-5ubuntu1 [47.8 kB]
Get:2 http://nl.archive.ubuntu.com/ubuntu/ natty/main libgvpr1 i386 2.26.3-5ubuntu1 [198 kB]
Get:3 http://nl.archive.ubuntu.com/ubuntu/ natty/main graphviz i386 2.26.3-5ubuntu1 [307 kB]
Fetched 553 kB in 0s (563 kB/s) 
Selecting previously deselected package libcgraph5.
(Reading database ... 163396 files and directories currently installed.)
Unpacking libcgraph5 (from .../libcgraph5_2.26.3-5ubuntu1_i386.deb) ...
Selecting previously deselected package libgvpr1.
Unpacking libgvpr1 (from .../libgvpr1_2.26.3-5ubuntu1_i386.deb) ...
Selecting previously deselected package graphviz.
Unpacking graphviz (from .../graphviz_2.26.3-5ubuntu1_i386.deb) ...
Processing triggers for man-db ...
Setting up libcgraph5 (2.26.3-5ubuntu1) ...
Setting up libgvpr1 (2.26.3-5ubuntu1) ...
Setting up graphviz (2.26.3-5ubuntu1) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place
Thank the Heavens that I'm still running an old Ubuntu, that downloads the proper (read: old) version of GraphViz. PlantUML, I hear, has issues with the new and improved GraphViz 2.28. 1 2

Unfortunately, I was unable to use a relative path in the output attribute in the build.xml. I hope I can fix this later.

Update: changed ImageSizeEnum to ImageSize. Naming should not contain data type names, according to uncle Bob.

Second Update
: PlantUML according to this now works with the newest Graphviz version.

Third Update: Updated NetBeans javadoc formatting problem with a better solution.

References

[1] PlantUML
http://plantuml.sourceforge.net/
[2] Drawing UML with PlantUML - Language Reference Guide (Version 5737)
http://sourceforge.net/projects/plantuml/files/PlantUML%20Language%20Reference%20Guide.pdf/download
[3] NetbeansFAQ
http://wiki.netbeans.org/FaqAntJunitJar
[4] Graphviz
http://www.graphviz.org/
[5] Example
http://maartenl.github.com/YourPersonalPhotographOrganiser/javadoc/gallery/enums/ImageSize.html
[6] "To keep documentation maintained, it is crucial that it be incorporated in the source program, rather than kept as a separate document ... even high-level language syntax does not at all convey purpose." [DRY principle]
The Mythical Man-Month (Frederick P. Brooks, Jr.)