Display class diagrams with PlantUML

When we are using object-oriented programming, it is nice to visually see the class hierarchy. In this article, I will show you how to use PlantUML to generate class diagram and an example of script for finding the class hierarchy of a project and generating its class diagram. I am doing that on Linux.

PlantUML

PlantUML is a tool to create diagrams. It uses a human-readable code to specify the diagrams which makes it useful for scripting.

For example to display a class diagram with ChildClass inheriting from MotherClass, we could use the following code snippet.

@startuml
MotherClass <|-- ChildClass
@enduml

PlantUML generates this image.

Class diagram from the previous code snippet.
Class diagram from the previous code snippet.

PlantUML can be used to generate other types of diagram like sequence diagrams, activity diagrams... Check out their website and documentation for more information.

Let me show you how to integrate PlantUML into a script to easily discover the class hierarchy used in hxWidgets.

Displaying hxWidgets library class diagram

hxWidgets is a port of wxWidgets in Haxe. hxWidgets was developed by the team behind HaxeUI.

If you do not understand anything of what I said: Haxe is an object-oriented programming language, the source code can be compiled into other languages (JavaScript, C++, PHP...) and so can be used to make web applications but also native software. wxWidgets is a C++ library for programming interfaces just like GTK and QT. hxWidgets is a port of wxWidgets in Haxe and can be used inside HaxeUI to make native interfaces (otherwise game engines are used) in Haxe.

Getting hxWidgets source code

Just clone the official repository.

git clone https://github.com/haxeui/hxWidgets

Finding the class definitions

In Haxe, classes are defined this way.

class ChildClass extends MotherClass implements Interface {
    // Class content
}

Let's use grep to find the class definitions.

The first thing we want to do is to be sure we search for the whole word class and not the string class. For that we will use the regular expression atoms \< which matches the beginning of a word and \> which matches the end of a word. If you are a Vim user and uses in normal mode *, it uses those atoms (see the bottom of your screen or check out the search history with :history search command). Here is an example.

$ cat file.txt
xxxxxxxxxxxxxxxxx
xxxxx class xxxxx
xxxxxxclassxxxxxx
xxxxxxxxxxxxxxxxx
$ grep --extended-regexp "class" file.txt
xxxxx class xxxxx
xxxxxxclassxxxxxx
$ grep --extended-regexp "\<class\>" file.txt
xxxxx class xxxxx

Searching for this pattern in the source repository gives us those results. I just show you some interesting parts.

$ grep --recursive \
    --no-filename \
    --extended-regexp \
    "\<class\>" hxWidgets/src/hx/widgets/

class OwnerDrawnPanel extends Panel {
class ClientDC extends WindowDC {

class ColourData {

class ArrayString { //extends WxArray<String> {

class MouseEvent extends Event implements MouseState {
class BookCtrlBase extends Control implements WithImages {

        return autoConvert(win); // lets auto convert the class so it can be used with casts
            list.push(autoConvert(win)); // lets auto convert the class so it can be used with casts
        return autoConvert(win); // lets auto convert the class so it can be used with casts

We still have too much information (see the highlighted lines). We should remove the commented section in the class definition and exclude the lines where the word class only appears in a comment.

Let's refine our regular expression using ^\<class\>[^\{]+\{ which means that we want lines starting with the word class and we match until the first { appears. We use the option --only-matching to only have the matching part. The command is now:

grep --recursive \
    --no-filename \
    --only-matching \
    --extended-regexp \
    "^\<class\>[^\{]+\{" hxWidgets/src/hx/widgets/

Converting the result into PlantUML code

To convert the result into PlantUML code, we create a small Python script def2plantuml.py. I could have used AWK or make a shell script using sed but the Python version was faster to write and cleaner to read.

def2plantuml.py
import sys
import re
"""
Converts a list of class definitions into a PlantUML class diagram.
"""
print("@startuml")
print("skinparam groupInheritance 2")
for line in sys.stdin:

    # Remove the newlines
    clean = line.strip()

    # Remove the trailing {
    clean = re.sub(r" {.*", "", clean)

    # Remove the word "class" at the beginning of the line
    clean = re.sub(r"^class ", "", clean)

    # We are interested only in the class hierarchy so
    # we remove the interface implementation definition.
    clean = re.sub(r" implements.*", "", clean)

    # If it extends a class, printing the link
    split = clean.split(" extends ")
    if len(split) == 1:
        print("class " + split[0])
    else:
        print(split[1] + " <|-- " + split[0])

print("@enduml")

Grouping everything together

We then create a shell script called create-class-diagram and use what we have done so far.

create-class-diagram
#!/bin/sh
# Generates the class diagram of hx.widgets package.

grep --recursive \
    --no-filename \
    --only-matching \
    --extended-regexp \
    "^\<class\>[^\{]+\{" hxWidgets/src/hx/widgets/ |
    sort |
    python3 def2plantuml.py |  # Convert the list into PlantUML file
    plantuml -pipe -tsvg > diagram.svg

# Using Inkscape 0.92.5, no "--pipe" option is present
inkscape --export-pdf="diagram.pdf" diagram.svg
rm diagram.svg

In this script we list the class definitions with our grep command and sort everything alphabetically. We send the result into our converter script. We then send the result to plantuml so it can export the result into an SVG file called diagram.svg.

We use Inkscape to create a PDF file so we can easily search for a class name. If you use a version above 0.92.5 maybe you have a --pipe option and you do not need to create diagram.svg. We save the PDF into diagram.pdf and here is the result.

The generated class diagram.
The generated class diagram for hxWidgets.

It may not be the prettiest diagram but at least it does the job.