the class2uml project pages

Tutorial

This page explains the usage of class2uml on a short and comprehensible "real life" example: the java.lang.Boolean class from SUN's JDK 1.4.

Note: Boolean is a JAVA wrapper class for the primitive type boolean, such as Integer for int, Float for float etc.

Table of contents

  1. Code of java.lang.Boolean
  2. Analysing Boolean with class2uml
  3. Understanding the results
  4. Conclusion

1. Code of java.lang.Boolean

In order to obtain a more compact representation, the source file has been reformatted as well as stripped of its copyright statement and comments. Please note that this piece of code is Copyright 2002 Sun Microsystems, Inc!

package java.lang;

public final class Boolean implements java.io.Serializable {

    public static final Boolean TRUE = new Boolean(true);
    public static final Boolean FALSE = new Boolean(false);
    public static final Class	TYPE = Class.getPrimitiveClass("boolean");
    private boolean value;
    private static final long serialVersionUID = -3665804199014368530L;


    public Boolean(boolean value) { this.value = value; }
    public Boolean(String s) { this(toBoolean(s)); }

    public boolean booleanValue() { return value; }

    public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
    public static Boolean valueOf(String s) { return toBoolean(s) ? TRUE : FALSE; }

    public static String toString(boolean b) { return b ? "true" : "false"; }
    public String toString() { return value ? "true" : "false"; }

    public int hashCode() { return value ? 1231 : 1237; }

    public boolean equals(Object obj) {
	if (obj instanceof Boolean)
	    return value == ((Boolean)obj).booleanValue();

	return false;
    }

    public static boolean getBoolean(String name) {
        boolean result = false;
        try {
            result = toBoolean(System.getProperty(name));
        }
	catch (IllegalArgumentException e) {}
        catch (NullPointerException e) {}
        return result;
    }

    private static boolean toBoolean(String name) { 
	return ((name != null) && name.equalsIgnoreCase("true"));
    }
}		  

2. Analysing Boolean with class2uml

At this point we presume a successful installation with BCEL available on your system. Now, there are two possibilities how you can follow this chapter - one using Dia, with Dot and Dia present, one using XMI and ArgoUML. If you are using a different Software Engineering tool, a conversion of the ArgoUML-flavoured XMI file might prove necessary.

2.1. class2uml for Dia

We analyse java.lang.Boolean by executing

java class2uml.ClassDiagram -ns -nx -o boolean.dia java.lang.Boolean .

The options will suppress Swing diagram drawing and XMI export and output the resulting Dia diagram data into "boolean.dia"; see the download page for a description of the class2uml command line arguments.

After the program has terminated, we can load the result into Dia (the option -n makes the program start faster, skipping the usual splash screen):

dia -n boolean.dia .

2.2. class2uml for XMI

We analyse java.lang.Boolean by executing

java class2uml.ClassDiagram -ns -nd -x boolean.xmi java.lang.Boolean .

The options will suppress Swing diagram drawing and Dia export and output the resulting XMI diagram data into "boolean.xmi"; see the download page for a description of the class2uml command line arguments.

Then import "boolean.xmi" into your Software Engineering tool. As stated before, conversion might be necessary if you are not using ArgoUML.

3. Understanding the results

Now let us try to understand the diagram we produced.

Note:
In addition to the mere diagram output, the call to class2uml created a subdirectory "CLASS2UML_ANALYSIS" where the program stored some compact, textual summaries of its underlying analyses as well as a .dot file representing the propagation graph for java.lang.Boolean. If you are interested in viewing it later on, you can use

dotty CLASS2UML_ANALYSIS/java.lang.Boolean.prop.dot .
Class diagram for Boolean

This should be the diagram you just obtained (click onto the image to view the full sized diagram). Note that this is the Dia output you see; if you followed this tutorial using ArgoUML or another XMI compatible tool, you will have to manually arrange the classes onto your diagram area, but then, you should obtain very much the same result.

As you can see in the picture, class2uml maps the classes it analyses to UML class boxes. Classes that are encountered, but not resolved due to recursion depth restriction or other reasons are marked with the stereotype <<reference>>. (In case you use the XMI export facility, you will not obtain stereotypes - due to technical reasons, these are replaced by tagged values, but then, everything else still holds for those.)

Generalisations

Generalisations are straightforward and follow the inheritance structure in the code. Thus, java.lang.Boolean is a child of java.lang.Object, such as all classes that are defined without an explicit inheritance statement.
The same holds for the interface java.io.Serializable.

Associations

Let C be the class we analyse, such as java.lang.Boolean. Fields based on an object type (that is SomeClass f; or SomeClass f[];) are mapped to associations from C to SomeClass. The far-end cardinality (how many SomeClass objects can be referenced during the lifetime of a C object?) is one of the analysis goals in the project, whereas the near-end cardinality is not analysed, thus always 0..*.

In the example, the self-associations TRUE and FALSE are analysed as 1..1, which means that during the lifetime of a Boolean, each of those fields bears exactly one reference to a Boolean.
Inspecting the code, we can confirm this: the static initialisations are the only write accesses to these fields (which, by the way, is not astonishing, since TRUE and FALSE are declared as final).

Finally, the association TYPE can be judged no better than 0..1; - a fact due to TYPE being initialised from a method result.

Note:
This example with its three final object type fields has the rather seldom property that none of its association cardinalities can be influenced from the outside of the current class.
Suppose they were NOT declared final - then, being public, they could be assigned to from classes other than the here analysed Boolean! However, class2uml would consider this by adding a warning prototype <<+>> (standing for "public") to their associations.

Other possible warning prototypes are <<#>> (protected access), <<~>> (package access), <<I>> (inner class access) and <<E>> (object array fields where the array reference may escape the own class, allowing array writing from the outside). Combinations of warnings are possible, too. Again, for XMI the stereotypes are replaced by tagged values, but everything else holds.

Dependencies

In UML terms, a dependency is characterised as a weak relationship between classes. Often, its idea is expressed as "C1 depends on C2, if changes in C2 may require also changing C1".
Following this idea, class2uml considers every reference to a class which is NOT an association nor a generalisation as a dependency. In order to avoid duplication of information, dependencies are not created if the class in question already occurrs as of one of the formerly introduced "stronger" relationships.

Thus, java.lang.System and java.lang.String are added. The first for being accessed statically (in getBoolean(...)), the latter for occurring as a method parameter and a return type in several contexts. Of course one occurrence would already be sufficient to create a dependency.
Finally, the two exceptions that are caught in getBoolean(...) lead to creating two more dependencies.

Query property

In UML, methods which do not alter the system state may be marked with the property "query".
We interprete the system state as the state of all objects, and the state of an object as the state of its fields. Thus, altering the system state would mean accessing at least one field. Note that we do NOT include local variables - which are more of a computational tool than an actual part of an object.

One of the analyses implemented in this project attempts to identify methods possessing the query property. Denoted by Dia with "const" instead of the more common "{query}", we can see that it has been identified in no fewer than 6 methods of java.lang.Boolean, which is a rather unusual success and is due to the simplicity of the java.lang.Boolean code.

One can easily verify that the 6 methods in question in fact do not perform any writing operation on any field of any object.

Compositions

UML specifies a refinement of the association notion called "composition". Compositions are associations where one side of the association "owns" the other, in such a way that those other side objects are not accessible to any other object but the one on the this-side. An interesting property which allows e.g. cascading deletion, as an owned object become useless without its owner.

A practical example would be an implementation of a Line class with

Line() { Point p_start = new Point(); Point p_end = new Point(); }
If additionally, we can guarantee that p_start and p_end do not escape the Line class and the this pointer does not escape the Point class, we would call p_start and p_end compositions.

In our Boolean example, none of the three associations has been identified as a composition - which is correct:
TRUE and FALSE because of escaping in the valueOf method and TYPE for not being new-initialised (but rather by a static method access).

4. Conclusion

This concludes our mini-tutorial on class2uml. It is evident that such a simple example cannot point out all of the difficulties that may be encountered during the construction of a class diagram, nor can it illustrate very well the underlying analyses.

And yet, it may hopefully prove helpful as a first step towards understanding this tool and the diagrams it produces.


Martin Keschenau
Last modified: Fri Dec 3 10:36:23 CET 2004