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
- Code of
java.lang.Boolean
- Analysing
Boolean with class2uml
- Understanding the results
- 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 .
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.