Contents
1 INTRODUCTION
1-x Prerequisites
2 USAGE
2-1 ClassDesigner Components as Java source modules
2-2 Binding UML Classes to source modules
2-3 Specifying source directories for Component packages
2-4 Selecting Components for code generation
2-5 Executing the code generator
3 UML MODEL ELEMENTS TO JAVA SOURCE CODE
3-1 UML concepts vs. Java concepts
3-2 ClassDesigner properties
3-3 Classes and Interfaces
3-4 Attributes as Java fields
3-5 Operations as Java methods
3-6 Associations as references to Java objects
3-7 Inner classes and Java Bean properties
3-8 Components
4 PRESERVATION OF OLD CODE BY THE CODE GENERATOR
4-1 Signatures and field declarations of classes
4-2 Method declarations of classes
5 SOURCE CODE TEMPLATES
5-1 Purpose of templates
5-2 Coverage of default templates
5-3 Variables available for templates
5-4 Editing template files
APPENDIX: ERROR MESSAGES AND WARNINGS
1 INTRODUCTION
1-x Prerequisites
In order to make good use of this document, the reader should be
reasonably familiar with the major features of:
Java 1.1
- keywords and syntax
- classes, interfaces, methods and fields
- inheritance, scope and access control
Unified Modeling Language (UML)
- syntax and semantics of Class, Interface, Operation, Attribute,
Association and AssociationEnd
ClassDesigner
- creating and editing models, packages, diagrams, Components,
Classes, Interfaces, Operations, Attributes and Associations.
- setting properties in UML model elements
The document also briefly discusses Java exceptions, inner classes and
Java Beans, but knowledge on these concepts is required only if the
corresponding features in the code generator are exploited.
2 USAGE
2-1 ClassDesigner Components as Java source modules
As an object-oriented modeling language, UML describes systems
as collections of Classes, each of which has given Attributes,
behavior (Operations related to the Attributes), and Associations to
other Classes of the system. In an UML model describing a Java
implementation, obviously, each Class represents a Java class,
each Attribute a Java field, etc. In addition to Classes, UML also
supports Interface model elements - equivalent to Java interfaces.
For convenience, we address both a Class and an Interface as
a "Class" here.
For code generation purposes, each UML Class must be bound to a
source module in the case tool. ClassDesigner uses separate objects
for specifying a binding between a Class and the corresponding source
module. These objects are called Components. A Class is bound to a
Component, and the Component describes the name and other properties
of the source module to be generated. Although ClassDesigner supports
separate Components for specification ("header") and implementation
("code") of a Class, since Java classes don't have header files, the
"specification component" setting of a Class is ignored by the Java code
generator.
2-2 Binding UML Classes to source modules
The designer should introduce one or more Component diagrams to
each package of an UML model under development in order to be able to
generate code for them. Refer to the documentation of ClassDesigner
for details on how to create new models, packages and diagrams.
An UML Class is bound to a Java source module by following three easy
steps:
1. Open a suitable Component diagram and create a new implementation
Component in it.
2. Name the Component according to the name of the source module to be
generated (without the .java extension).
3. Open the corresponding UML Class, select its "Components" dialog
and alter the "implementation" setting to point to the newly created
Component.
More than one Class may occupy a single source module. In such a case,
several Classes have their "implementation" setting pointing to the
same Component. The designer can't decide the order in which the
Java classes appear in the generated source module, however. Also, changing
the order by hand after code generation is not very practical, because
activating the code generator for the module for the next time will
again reorder the classes.
2-3 Specifying source directories for Component packages
The location of the source modules generated from an UML model is
specified on package level in ClassDesigner. That is, each package of
an UML model has a "source directory" setting which can be set to
refer any available directory. The directory must be created
beforehand. All components in a package behave as source modules
residing in the source directory selected for that package.
The "source directory" setting of a package is accessed in
ClassDesigner by selecting the package in the model diagram, and then
choosing "Object" from the main menu, followed by selections
"Properties..." then "Source Directory".
The starting point of relative path names is ClassDesigner's working
directory instead of e.g. the directory where the UML model files are
stored.
2-4 Selecting Components for code generation
The user may freely select objects in ClassDesigner from the model
diagram (any number of packages or even the entire model) and from all
diagrams contained by the packages of the model. Selecting a package
covers all Components in the package, and selecting a Class also
selects the corresponding "implementation" Component (if any). When
the code generator is activated, source code will be gererated for all
selected Components.
2-5 Executing the code generator
The Java code generator is executed for the selected UML model
components by choosing "Actions" from the main menu, and then
selecting "Execute script". In the appearing dialog, one should open
the file "Java.tcl" which is in the directory "Jacob3/codegen" of the
Jacob v3 project. This will start the code generation.
One should not open any other Tcl scripts in the code generator
directory, because they require initialization by the main script
"Java.tcl" in order to work properly.
After executing the code generator, one may want to read the output
on ClassDesigner's console to review the results of code generation,
including issued warnings and error messages.
3 UML MODEL ELEMENTS TO JAVA SOURCE CODE
When generating code for an UML model element, the code generator
inspects many of the settings available for each element in order to
generate Java classes that are equivalent to Classes in the UML model.
The designer is offered a reasonable amount of flexibility in
controlling various aspects of the classes to be generated. The
following discusses how the settings for Classes, Attributes,
Operations and Associations in ClassDesigner affect the corresponding
generated Java classes.
3-1 UML concepts vs. Java concepts
UML Java
+ public (*)
- private (*)
# protected (*)
$ static (*)
Attribute field
Class class
Interface interface
Operation method
(*) For the usage of '+', '-', '#' and '$' to control the visibility
and class scope of Attributes and Operations, please refer to the
documentation of the case tool. "Package" visibility of Java is
indicated by leaving visibility unspecified.
3-2 ClassDesigner properties
Although many of the settings in ClassDesigner's dialog boxes for
model elements have semantics that are usable in Java code generation,
most of them are ignored by the code generator. Instead, the code
generator supports various properties that can be used to e.g. define
a class to be {abstract} or {final}. Properties are very much like
#define settings in C. The existence of a property in a model element
and the value (if any) assigned to the property affect the behavior of
the code generator on the model element. The braces enclosing defined
properties which show up in class diagrams are included by ClassDesigner.
The reasons for using properties, instead of model element settings
with similar semantics, include:
- properties of classes can be viewed on the class diagrams of
ClassDesigner with one glance whereas model element settings cannot
- some aspects of Java require the use of properties anyway; the
user's memory load is probably smaller if all settings can be done
with properties
- supporting both properties and model element settings could lead to
mixed practice and somewhat confusing class diagrams.
Summary of supported properties:
Property setting Applies to Effect in Java
{abstract} C, O Declare "abstract"
{beanprop=none} A Generate field as Bean property
{beanprop=bound} A Generate field as bound Bean prop.
{beanprop=constrained} A Generate field as constr. Bean prop.
{beanprop=abstract} A Generate field as abstract Bean prop.
{exceptions=[ExcList]} O Declare "throws [ExcList]"
{final} C, I, O, A Declare "final"
{native} O Generate native method prototype
{static} C, I Declare "static"
{synchronized} O Declare "synchronized"
{transient} A Declare "transient"
{visibility=public} C, I Declare "public" visibility (*)
{visibility=protected} C, I Declare "protected" visibility (*)
{visibility=private} C, I Declare "private" visibility (*)
{volatile} A Declare "volatile"
C = Class
I = Interface
O = Operation
A = Attribute
(*) If the {visibility} property is not defined, the code generator
defaults to ClassDesigner's Visibility setting
The semantics of each property when applied to different model
elements is described in better detail in (3-3)-(3-7).
3-3 Classes and Interfaces
Interfaces are Classes that have the identity "Interface" instead of
the identity "Class" of normal Classes. Otherwise, Interfaces in the
UML model are identical to Classes, ie. an Interface has exactly the
same settings in the case tool as any other Class. The code generator,
however, uses slightly different approach in generating code for
Interfaces. For example, all Operations of an Interface are by
default treated as abstract Java methods, and all Attributes are
treated as static final Java fields unless they have the property
{beanprop=abstract}.
General settings
Name: The name of the generated Java class.
Description: Generated as a leading Javadoc comment for the Java class
declaration.
Stereotype: Ignored.
Detail settings
Parameters: Ignored.
Arguments: Ignored.
Root: Ignored.
Leaf: Ignored. Use property {final}.
Abstract: Ignored. Use property {abstract}.
Visibility: Generate either public, protected or private Java class or
interface. If unspecified, use package visibility.
This setting is overridden by the {visibility} property.
Primitive: Ignored.
Relationships settings
These settings should be edited by drawing Associations between
Classes with a graphical toolkit in an UML class diagram. Deleting
obsolete Associations may be sometimes easier to do from within the
Relationships settings of the involved classes.
Components settings
Specification: Ignored.
Implementation: Specifies the Component which defines the Java source
module for the Class.
Properties settings
{abstract}:
Generate an abstract Java class. Makes no difference with
Interfaces. If a Class has {abstract} Operations, the Class must
have this property. A Class may not be both {abstract} and
{final}.
{final}:
Generate a final Java class. Interfaces cannot be {final}. A Class
may not be both {abstract} and {final}.
{static}:
Generate a nested top-level Java class or interface.
{visibility=public|protected|private}:
Generate either public, protected or private Java class or interface.
If omitted, use ClassDesigner's Visibility setting.
3-4 Attributes as Java fields
Attribute settings describe how to generate each field in the Java
class.
General settings
Declaration: The name of the Java field to be generated, as well as
its visibility, scope (static or non-static) and initial
value. See the documentation of ClassDesigner for details.
Description: Generated as a leading Javadoc comment for the Java
field declaration.
Implement as: Ignored.
Access: Ignored.
Properties settings
{beanprop=none|bound|constrained|abstract}:
Generate the Java field as a Bean property. See (3-7) for details.
{final}:
Generate a final Java field. Attributes of an Interface are
{static} {final} by default unless they also have the property
{beanprop=abstract}.
{transient}:
Generate a transient Java field.
{volatile}:
Generate a volatile Java field.
3-5 Operations as Java methods
Operation settings define how to generate each method in a Java class.
General settings
Declaration: The name of the Java method to be generated, as well as
its visibility and scope (static or non-static). See the
documentation of ClassDesigner for details.
Description: Generated as a leading Javadoc comment for the Java
method declaration.
Polymorphic: Ignored. Use property {final}.
Abstract: Ignored. Use property {abstract}.
Query: Ignored.
Implement as: Ignored.
Properties settings
{abstract}:
Generate an abstract Java method. A non-interface Class
containing an {abstract} Operation must also have this
property. Operations of an Interface have the {abstract} property
by default. An Operation may not be both {abstract} and {final}.
{exceptions=[ExcList]}:
Generate a Java method with a throws clause. For example, the
property {exception=myException1, myException2} generates a method
declaration with the throws clause
"throws myException1, myException2".
{final}:
Generate a final Java method. An Operation may not be both
{abstract} and {final}.
{native}:
Generate the method as a native method prototype.
{synchronized}:
Generate a synchronized Java method.
3-6 Associations as references to Java objects
In Java terms, an association between two Classes in an UML model
means that either one or both of the corresponding Java classes have
a variable or an array that references one or more instances of the
other class, and possibly methods for manipulating these references
(such as getter and setter methods).
Code generation for Associations is a complicated issue affected
by several settings each of which can produce a large variety of
association implementations. Thus, understanding the principles of
code generation for Associations requires some intuition from the user
on how UML Associations map to Java code. The basic approach
of the code generator is to use two kinds of association variables,
simple fields and arrays, and five different manipulation methods:
init, add, set, get, and update. Choosing the right association variable
and selecting a suitable set of manipulator implementations at each
AssociationEnd produces the correct implementation for the whole
Association.
"Init" is a private method which should be called from the constructor
of the generated class. Obviously, "init" is responsible for initializing
the association variable. The code generator does not modify
constructors of classes, so the user should always remember to initialize
all of the association variables of each class by entering appropriate
calls to "init" methods into their constructors.
"Add" is a method used for adding new elements to an association variable
array.
"Set" is a method used for changing the value of an existing association
variable and elements in association variable arrays.
"Get" is a getter for the association variable.
"Update" is a special method which is only generated for Associations
navigable in both directions. The purpose of "update" is to ensure that
adding and setting association variables in one AssociationEnd keeps
the other End up-to-date with these changes. The user's code should not
explicitly call "add" and "set" methods for an association variable
which also has an "update" method.
The existence, signature and implementation of association variable
manipulators can vary a lot depending on the Association Specification.
Association Specification
Name: Only affects the generated comment lines which indicate
the beginning and end of the association code in a source
module.
Description: Generated as a leading Javadoc comment for the association
Java code.
(The following settings are unique to both AssociationEnds.)
End name: If the AssociationEnd is navigable, its end name will
be generated as the name for an association variable on
the other End.
Qualifier: If the AssociationEnd has a Qualifier, the list of
Attributes for that Qualifier are passed on to the
AssociationEnd source code templates; see (5) for
more information. The default templates ignore
Qualifier attributes, however.
Multiplicity: If the AssociationEnd is navigable, its multiplicity
will affect the type and, for arrays, index bounds of
the association variable on the other End.
Each multiplicity setting maps to a multiplicity type.
There are four multiplicity types (*):
Type Effect
One generate a non-array association variable
which must be initialized to a non-null
value and never be set to null thereafter
ZeroOrOne generate a non-array association variable
which may optionally be null
Bounded generate an association variable array
whose minimum and maximum number of
elements are limited to fixed values
Unbounded generate an association variable array
whose minimum number of elements is fixed
but which may grow unlimitedly
(*) Note: ClassDesigner also supports multiplicity types
"Zero" and "ExactNumberGreaterThanOne" but
the former is basically useless and thus not
supported, and the latter is treated as
Bounded multiplicity with the upper bound equal
to the lower bound.
The multiplicity type of an AssociationEnd also affects
both the signature (arguments) and implementation of the
manipulation methods for the generated association variable.
Multiplicity types are resolved as follows:
Multiplicity Multiplicity type
1 One
0..1 ZeroOrOne
m (m >= 0) Bounded
m..n (m >= 0, n >= m) Bounded
m..* (m >= 0) Unbounded
Multiplicities other than those listed above are invalid.
Visibility: Sets the visibility of the manipulation methods for the
association variable on the other End. The "init" method,
however, is private regardless of this setting.
Access: Prevents manipulator methods from being generated for
the association variable on the other End:
Setting Excluded methods
readonly add, set, update
writeonly get
writeread -
The exclusive effects of this setting are cumulative
with those of the Changeable setting.
Aggregation: Ignored at the moment.
Changeable: Prevents manipulator methods from being generated for
the association variable on the other End:
Setting Excluded methods
none -
addOnly set
fixed add, set, update
The exclusive effects of this setting are cumulative
with those of the Access setting.
Class scope: Checking this box generates the association variable
on the other End and its manipulators as static Java members.
Ordered: Ignored at the moment.
Navigable: If an AssociationEnd is navigable, an association variable
with the name of that AssociationEnd is generated
on the other End (along with manipulation methods
for the variable). If both Ends of an Association are
navigable, an extra manipulation method "update"
is generated for both AssociationEnds.
Gen. operations: Leaving this box unchecked disables code generation for
the whole AssociationEnd.
Implement as: Generate association code according to the source code
template named after this field, as opposed to the
default template which is resolved from other
settings of the Association Specification. A set of source
code templates with the given postfix must be located in the
"template/assocend" subdirectory of the code generator. For
more information on source code templates, see (5).
3-7 Inner classes and Java Bean properties
The code generator is able to recognize Java inner classes and Java
Bean properties in an UML model and generate appropriate code for
them.
Inner classes
Although UML doesn't support inner classes yet, the code generator
recognizes a special kind of Association which declares an
AssociationEnd as an inner class of the other AssociationEnd, and
generates code for the Java inner class inside the code of the container
class.
To declare a Class as an inner class of another Class:
1. Include the two Classes in the same UML diagram in ClassDesigner
and draw an Association between them.
2. Open the dialog box of the new Association and enter the word
"innerclass" into the "implement as" box of the AssociationEnd you
want to generate as a Java inner class.
3. For clarity, it is suggested that you also define the container
Class' AssociationEnd as a composition. (Semantically, an inner
class can be thought as a composite of the container Class.)
Regardless of what implementation component has been specified for the
inner class, its code will now be generated into the declaration of
the container class.
Java Bean properties
Using Java Bean properties involves writing methods like getters,
setters and notifiers (as described in the design pattern section of
the Java Beans documentation). The code generator is able to recogize
different types of Bean properties and automatically generate the
methods for the related design patterns. This helps the user to avoid
doing uncreative work and ensures that the rules of the design patterns
are followed to the letter.
Not surprisingly, support for Java Bean properties has been
implemented by using ClassDesigner properties.
To enter a Bean property into a Class:
1. Create a new Attribute into the Class and give that Attribute the
property {beanprop}.
2. Enter a value for the property according to what kind of a Bean
property you want to create:
{beanprop=none} or {beanprop}: normal Bean property
{beanprop=bound}: bound Bean property
{beanprop=constrained}: constrained Bean property
{beanprop=abstract}: abstract Bean property
The next time you generate code for the Class, the field declaration
for the new Bean property will appear in the source module, followed by
the methods of the property's design patterns.
The code generator knows that the getter method for a Bean property of
the type boolean is called "is" and not "get".
Indexed Bean properties are not yet supported.
4-8 Components as Java source modules
Components are object representations of Java source modules,
describing one or more Java classes or interfaces.
General settings
Name: The name of the generated source module without the .java
extension which is added automatically.
Description: Generated as a leading Javadoc comment at the beginning
of a source module.
Relationships settings
These settings should be edited by drawing Associations between
components with a graphical toolkit in a component diagram. Deleting
obsolete Associations may be sometimes easier to do from within the
Relationships settings of the involved components.
Declarations settings
The text in this area follows the leading Javadoc comment in the
source module. In Java code generation, it is typically used for
listing the import statements of the source module. (The package
statement is generated automatically using the name
of the UML package.)
Properties settings
Ignored.
4 PRESERVATION OF OLD CODE BY THE CODE GENERATOR
The following describes how the code generator preserves method bodies
with the help of special "code section" markers and the cases where
code generator does not preserve old code.
4-1 Signatures and field declarations of classes
Signatures and field declarations for classes are always re-generated
from the UML model.
Fields added to a class by hand after the last code generation and
left out of the UML model are NOT preserved by the code generator! It
is very advisable to always introduce new variables to a class by
adding them to the UML model and then generating fresh code for the
class.
Naturally, the statement above does not apply to local variables
within method implementations.
4-2 Method declarations of classes
The code generator does not preserve hand-written code when generating
code into source modules that have been imported from another
project and created a ClassDesigner component for.
ClassDesigner uses special markers to define, in bodies of methods,
code sections which are preserved "as is" in code generation. The
markers are included in the generated classes automatically by the
generator and should not be edited or deleted by the user.
The marker indicating the beginning of a code section ("//+ ...")
should always immediately follow the signature of a method, and the
ending indicator ("//- ...") should immediately precede the closing
brace of the method body:
public int myMethod(int a, myClass cl) {
//+ myClass::myMethod(int, myClass)
/*
* insert your code between the code section markers;
* code outside the markers is not preserved in code generation
*/
//- myClass::myMethod(int, myClass)
}
Code sections may NOT be nested or otherwise overlap.
If the signature of a method remains the same between two subsequent
code generation sessions, the newly generated method will continue to
have the body it had before the last session.
If the signature of a method changes, the code for that method
is not included in the code section of the newly generated method
declaration (with new code section markers). Instead, the code
generator appends the old code section to the end of the source
module, after a comment labeled "UNUSED CODE". The preserved code can
be re-copied into the body of the new method declaration by hand, but
the old code section markers must not be copied along with the
code. The user is free to delete obsolete code located in the
"UNUSED CODE" block; the code generator never removes anything
from this block.
5 SOURCE CODE TEMPLATES
5-1 Purpose of templates
The output format of the generated source module is largely controlled
by separate template files which define, on ASCII character level,
how to write a Java field declaration, how to write a Java implementation
for a particular Java association etc.
The directories for template files are located in the "template" subdirectory
of the code generator. The user is free to adjust the templates to suit her
personal taste.
Besides modifying the existing templates, the user can also add new templates
to template directories. Self-tailored templates are made to override the
default templates in code generation by entering their name
(without the .java extension) to the "implement as" setting of
an UML model element in ClassDesigner.
5-2 Coverage of default templates
The features that can be configured by editing source code templates and
the corresponding template directories are:
- Java class signature and Java interface signature ("class" and "interfac")
- Java field declaration ("attrib")
- Java method signature ("operat")
- design patterns for different Java Beans properties ("beanprop" and "class")
- association variables and their manipulators "init", "add", "set", "get",
and "update" ("assocend")
5-3 Variables available for templates
The following Tcl string variables can be used in template files:
Variable Description
${name} name of the source code element (class, field, etc.)
${Name} as above, but with the first letter in uppercase
${abstract} "abstract " if element has the {abstract} property, else ""
${beanprop} value of the {beanprop} property
${exceptions} value of the {exceptions} property
${final} "final " if element has the {final} property, "" otherwise
${hasbody} 1 if an Operation has a non-empty body, 0 otherwise
${increment} symbolic name for a constant which has the value ${multincr}
${initialvalue} initialization string for an Attribute: " = "
${isOrdered} 1 if an AssociationEnd is ordered, 0 otherwise
${lowerbound} symbolic name for a constant which has the value ${multmin}
${multincr} size of the increment used in expanding association
variable arrays
${multmax} upper multiplicity bound for an AssociationEnd
${multmin} lower multiplicity bound for an AssociationEnd
${native} "native " if element has the {native} property
${parameters} argument list of an Operation ("arg1, arg2, ...")
${qattr} list of Attrbute names for a Qualifier of an AssociationEnd
${static} "static " if element has the {static} property or
if an AssociationEnd has "class scope" setting checked
${superclass} name of the superclass of a Class
${interfaces} list of interfaces a Class or Interface implements
${synchronized} "synchronized " if an Operation has the {synchronized} prop.
${transient} "transient " if an Attribute has the {transient} property
${type} type of an Attribute or the return value of an Operation
${Type} reflected "object" type of an Attribute (for example,
"Byte" is the object type for Attributes of type "byte")
${upperbound} symbolic name for a constant which has the value ${multmax}
${visibility} value of the {visibility} property, followed by a space
${volatile} "volatile " if an Attribute has the {volatile} property
5-4 Editing template files
The contents of each Tcl file are treated as evaluated Tcl strings.
("Evaluated" means that variables within the string are substituted with
their corresponding values.)
Since brackets ('[' and ']') have a special purpose in Tcl, they should
be escaped ("\[", "\]") in template files when used in e.g. Java array
indexing. Besides variables, Tcl expressions (for example, condition
testing) can also be embedded in templates using '[' and ']'. Please
see Tcl's documentation on substitution rules for more information.
APPENDIX: ERROR MESSAGES AND WARNINGS
The following lists the messages which result from the integrity checks
of the code generator and gives general hints for correcting errors.
*** ERROR *** C: multiple superclasses
Open the Relationships dialog for Class C and check whether an obsolete
superclass is haunting the Class.
*** ERROR *** C: non-abstract class with an abstract method ( O )
Either give Class C the {abstract} property or remove
the {abstract} property from Operation O.
*** WARNING *** C: abstract class with no abstract methods
Just a notification.
*** ERROR *** I: interface extending a class ( C )
Ensure that Interface I only has superclass relationships with other
Interfaces.
*** ERROR *** O: method declared both abstract and final
Remove either the property {abstract} or the property {final} from
Operation O.
*** ERROR *** A: uninitialized final field
Either remove the property {final} from Attribute A or initialize A
in its Declaration setting.