Mapping UML Associations into Java Code
Gonzalo Génova, Carlos
Ruiz del Castillo and Juan Llorens,
Science Department, Carlos III University of Madrid, Spain
|
 |
REFEREED
ARTICLE

PDF Version |
Abstract
Object-oriented programming languages do not contain syntax or semantics
to express associations directly. Therefore, UML associations have
to be implemented by an adequate combination of classes, attributes
and methods. This paper presents some principles for the implementation
of UML binary associations in Java, paying special attention to multiplicity,
navigability and visibility. Our analysis has encountered some paradoxes
in the specification of visibility for bidirectional associations.
These principles have been used to write a series of code patterns
that we use in combination with a tool that generates code for associations,
which are read from a model stored in XMI format.
1 INTRODUCTION
One of the key building blocks in the Unified Modeling Language [UML]
is the concept of association. An "association" in UML is
defined as a kind of relationship between classes1, which represents
the semantic relationship between two or more classes that involves
connections (links) among their instances [UML, p. 2-20]2.
As it has
been denounced long ago [Rumbaugh 87], object-oriented programming
languages express classification and generalization well, but do not
contain syntax or semantics to express associations directly. Therefore,
associations have to be implemented by an adequate combination of classes,
attributes and methods [Rumbaugh 96a] [Noble 96] [Noble 97] [Ambler 01].
The simplest idea is to provide an attribute to store the links of
the association, and accessor and mutator methods to manipulate the
links. Other approaches emphasize the use of Java interfaces to implement
associations with some practical advantages [Harrison 00].
CASE tools
often provide some kind of code generation starting from design models3,
but limited to skeletal code involving only generalizations and classes,
with attribute and method signatures, but no associations
at all4. The programmer has to
manually write the code to manage the associations in a controlled
way, so that all constraints and invariants
are kept for correctness of the implementation. This is usually a repetitive
task that could be automated to a certain extent. Besides, the number
of things that the programmer should bear in mind when writing the
code for the associations is so large, that he or she continuously
risks forgetting some vital detail. This is specially true when dealing
with multiple (with multiplicity higher than 1) or bidirectional (two-way
navigable) associations. Moreover, the final written code is frequently
scattered over the code of the participating classes, making it more
difficult to maintain.
The aim of this work is two fold. First, write
a series of code patterns that will help programmers in mapping UML
associations into a target
object oriented programming language. In this work, the language has
been chosen to be Java, although the principles we have followed may
be applied to other close languages like C++ or the .NET framework.
Second aim, construct a tool that generates code for associations using
these patterns, the associations being read from a model stored in
XMI format5. A third aim will be to enable reverse engineering, that
is, obtaining the associations between classes by analyzing the code
that implements them. Our tool does not presently accomplish this task,
although it is a very simple and straightforward procedure if the code
has been written with our patterns. A complete description of the patterns
and the tool is outside the scope of this paper, but can be found elsewhere
[Ruiz 02].
Associations in UML can have a great variety of features.
The present work is limited to the analysis and implementation of multiplicity,
navigability and visibility in binary associations. It excludes, therefore,
more complex kinds of associations such as reflexive associations,
whole/part associations (aggregations and compositions), qualified
associations, association-classes, and n-ary associations. It excludes,
too, features such as ordering, changeability, etc.
The three following
sections of this article are devoted to studying the features of multiplicity,
navigability and visibility of associations,
with a detailed analysis of the possible problems and proposed solutions.
Then, Section 5 contains the description of a uniform interface for
all kinds of associations from the point of view of the participating
classes, such as it is implemented by our patterns and tool. Finally,
Section 6 describes briefly how our tool works.
2 THE PROBLEM OF MULTIPLICITY
The multiplicity of a binary association,
placed on an association end (the target end), specifies the number
of target instances that
may be associated with a single source instance across the given association,
in other words, how many objects of one class (the target class) may
be associated with a given single object from the other class (the
source class) [RM, p. 348] [UML, p. 2-23]6.
The
classical example in Figure 1 illustrates binary multiplicity. Each
instance of Person may work for none or one instance of Company (0..1), while each company may be linked to one or more persons (1..*).
For those readers less familiarized with UML notation, the symbol (*)
stands for "many" (unbounded number), and the ranges (1..1)
and (0..*) may be abbreviated respectively as (1) and (*).

Figure 1. A classical example of binary association with the expression
of multiplicities
The potential multiplicities in UML extend to any subset of nonnegative
integers [RM, p. 346], not only a single interval as (2..*), or a comma-separated
list of integer intervals as (1..3, 7..10, 15, 19..*): specifications
of multiplicity like {prime numbers} or {squares of positive integers}
are also valid, although there is no standard notation for them. Nevertheless,
in UML as in other modeling techniques, the most usual multiplicities
are (0..1), (1..1), (0..*) and (1..*). We are going to restrict our
analysis to multiplicities that can be expressed as a single integer
interval in the form of (min..max) notation.
The multiplicity
constraint is a kind of invariant, that is, a condition that must be
satisfied by the system. A possible practice when programming
is: do not check always the invariant, but only at the request of the
programmer, after completing a set of operations that are supposed
to leave system in a valid state (a transaction). This practice is
more efficient in run-time, and gives the programmer more freedom and
responsibility in writing the code, with the corresponding risk that
he or she forgets putting the necessary checks and carelessly leaves
the system in a wrong state. On the other side, we think that checking
multiplicity constraints is not very time consuming (inefficient),
especially when compared with the time required to manage collections
or synchronize bidirectional associations (see Section 3). Therefore,
we think that it is worth doing as much as we can for the programmer,
so that our first target will be to analyze the possibility of performing
automatic checks for multiplicity constraints.
Optional and mandatory
associations
The value of minimum multiplicity can be any positive integer,
although the most common values are 0 or 1. When the value is 0 we
say the association
is optional for the class on the opposite end (class Person in
Figure 1), when the value is 1 or greater we say it is mandatory (class Company).
Optional associations pose no special problems for the implementation,
but mandatory associations do. From a conceptual point of view, an
object participating in a mandatory association needs to be linked
at any moment with one object (or more) on the other side
of the association, otherwise the system is in a wrong state. In the
example given in Figure
1, an instance of Company needs always an
instance of Person. Therefore,
in the same moment you create the instance of Company,
you have to link it to an instance of Person.
This
can happen in three different ways:
- An instance of Company is created by an instance of Person and linked to its creator.
- An instance of Company is created with an instance of Person supplied as a parameter.
- An instance of Company is created and it issues the creation
of an instance of Person.
The third case poses additional problems. The creation
of a Person will probably require additional
data, such as name, address, etc.,
and it does not seem very sensible to supply them in the creation of
a Company. This problem becomes much worse
if Person has other mandatory
associations, for example one with the Country where
he or she lives: if this were the case, the creation of a Company would
require supplying data for creating a Person,
for creating a Country, etc.
The most obvious
solution is to allow only the first and second forms of instantiation.
But then suppose the association is mandatory in
both ends. Which instance is to be created first? We have not a satisfactory
choice, since we will put the system in a wrong state until both creations
are finished. We could think of an atomic creation of both
instances, but this is valid only for the simplest case in which only
two classes
are involved. Should we define atomic creators for two, three, any
number of classes? Similar problems arise when dealing with object
deletion.
Imagine now that we are not creating or deleting instances,
but changing links between instances. If you want to change the instance
of Company that is linked with a given instance of Person, simply delete the link
with the old Company and add a new link with the new Company. This
works as far as the old Company is linked to other instances of Person;
you can even delete the link and add no new one, since the association
is optional for Person. If you had only one Person linked to a given
Company, you should supply a new Person to the Company before deleting
the link with the old Person, but this is only the specified behavior
(the association is mandatory for Company) and you cannot complain
about it.
Nevertheless, we find new problems here. If the association
with Company were mandatory for Person too (that is, 1..1 multiplicity
instead of
the current 0..1), the instance of Person could not delete the old
link with a Company and then add the new one, nor it could do it in
the reverse order, "first add then delete", because it would
go through a wrong system state. An atomic change of links would be
valid only for the simplest cases, but not for more complex ones such
as the following, rather twisted case (see Figure 2): consider classes
A and B, which are associated with multiplicity 1..1 on both ends,
and the corresponding instances a1, a2, b1 and b2. In the initial state,
we have the links a1-b1 and a2-b2. In the final state, we want to have
the links a1-b2 and a2-b1. Even if we can change atomically a1-b1 to
a1-b2 without violating the multiplicity constraints on a1, this would
leave b1 without any links and b2 with two links until the final state
is reached. We should have to perform the whole change atomically by
means of an atomic switch implemented in a single operation.

Figure 2. Multiplicity constraints can make very difficult changing
links between instances without entering a wrong system state:
a) class
diagram; b) initial state; c) intermediate wrong state; d) final desired
state
Obviously, we cannot define a new operation to avoid any conceivable
wrong state involving several instances. In consequence, we think that
mandatory associations pose unsolvable problems regarding the creation
and deletion of instances and links: we cannot achieve with a few primitive
operations that a mandatory association is obeyed at any time,
and we cannot isolate, inside atomic operations, the times when the
constraint
is not obeyed. Therefore, we have to relax the implications of mandatory
associations for the implementation, as other methods do [Harrison
00]. Our proposal is as follows: do not check the minimum multiplicity
constraint when modifying the links of the association (mutator
methods, or setters), but only when accessing them (accessor
methods, or getters). The programmer will be responsible for using
the primitives in a consistent
way so that a valid system state is reached as soon as possible.
For
example, you will be allowed to create a Company without linking it
to any Person, and you will be allowed to delete all the links of
a Company with instances of Person; but before accessing, for other
purposes, the links of that particular instance of Company towards
any instances of Person, you will have to restore them to a valid state,
otherwise you will get an invalid multiplicity exception,
which shall be defined in the code that implements the associations
according to
our proposal.
Single and multiple associations
The value of maximum multiplicity
in an association end can be any integer greater or equal than 1, although
the most common values are
1 or *. When the value is 1 we say the association is single for
the class on the opposite end (class Person in
Figure 1), when the value is 2 or greater we say it is multiple (class Company).
Single associations are easier to implement than multiple associations:
to store the only
possible instance of a single association we usually employ an attribute
having the corresponding target class as type, but to store the many
potential links of a multiple association we must use some kind of
collection of objects, such as the Java predefined Vector, HashSet,
etc. In the general case we cannot use an array of objects, because
it gets a fixed size when it is instantiated. Since collections in
Java can have any number of elements, the maximum multiplicity constraint
cannot be stated in the declaration of the collection in the Java code,
but it must be checked elsewhere during run-time.
We need two kinds
of mutators, add and remove,
which will accept as a parameter either single objects or entire
collections. Because of
the problems with minimum multiplicity explained above, the remover
sometimes will leave the source instance in a wrong state; we can't
avoid this situation. The adder, instead, leaves us a wider choice.
If we try to add some links above the maximum multiplicity constraint,
we can choose between rejecting the addition or performing it; in
the latter case we violate temporarily the constraint until a call
to the
remover restores the source instance to a safe state; the wrong state
would only be detected by accessor methods, as we settled in the
case of minimum multiplicity. However, this is true only for multiple
associations
implemented with a collection; in single associations implemented
by means of an attribute we simply cannot violate the maximum multiplicity
constraint: we are forced to reject the addition.
If we choose to reject
the addition, instead, besides having an asymmetric behavior between
remover and adder, we can find precedence problems
when invoking the adder and the remover in succession. Consider class Game associated
with class Player with
multiplicity 2..4 (see Figure 3), and suppose an instance g1 of Game is
linked to two instances p1, p2 of Player.
We want to replace these two players by four new different players q1, q2, q3, q4.
If we issue "first remove then add",
we get finally what we want; if we issue "first add then remove",
the addition is rejected and the remotion leaves the instance of Game in
a wrong state.

Figure 3. Precedence problems found when invoking the
adder and the remover in succession:
a) class diagram of Game-Player association;
b) initial state with players p1, p2;
c) final desired state after
removing players p1, p2 and then adding players q1, q2, q3, q4;
d)
final wrong state after unsuccessfully trying to add players q1, q2, q3, q4 and then removing players p1, p2
In the end, we have preferred
to reject the addition if it violates the maximum allowed,
and ask the users of mutator methods to use them
always in the right order, first remove then add, so that we can
get an analogous behavior for single and multiple associations. Therefore,
the remover does not check the minimum multiplicity constraint (possibly
leaving empty a mandatory association), the adder does check the
maximum
multiplicity constraint, and the getter raises an exception if either
constraint is not fulfilled.
Accessor methods of multiple associations
have another peculiarity, when compared with the accessors of single
associations: they return
a collection of objects, not a single object, therefore the returned
type is that of the collection, not that of the target class. In
our implementation, the returned type is the Java interface Collection,
which is implemented by all standard collections. Internally, we
use
a HashSet collection, which ensures that
there are no duplicate links in an association, as the UML requires
[UML, p. 2-19]7.
Finally, the standard
collections in Java are specified to contain instances of the standard
class Object, which is a superclass of
every class in Java. You cannot specialize these collections to
store objects
pertaining only to a particular class8.
This means that, if we use a HashSet inside Company to
store the links to instances of Person,
we must ensure on our own that no one puts a link to an instance
of another class such as Dog or Report (this
could happen if a collection
of objects is passed as a parameter to the add method).
Therefore, the mutator methods must perform a run-time type checking
by means
of explicit casting. If the type-check fails, then the
link is not set to that object, and a class cast exception,
which is predefined in Java, is raised.
3 THE PROBLEM OF NAVIGABILITY
The directionality, or navigability,
of a binary association, graphically expressed as an open arrow at
the end of the association line
that connects two classes, specifies the ability of an instance
of the
source class to access the instances of the target class by
means of the association
instances (links) that connect them9.
If the association can be traversed in both directions, then
it is bidirectional (two-way),
otherwise
it is unidirectional (one-way).
A navigable association
end, which is referenced by its rolename, defines a pseudoattribute
of the source class, so that the
source instance
can use the rolename in expressions in the same way as it
uses its own attributes [RM, p. 354]. An instance can communicate
(by sending
messages) with the connected instances of the opposite navigable
end, and it can use references to them as arguments or reply
values in communications
[UML, p. 2-114]. Similarly, if the association end is navigable,
the source instance can query and update the links that connect
it to the
target instances.
The examples in Figure 4 illustrate navigability.
The association Key-Door is unidirectional,
meaning that a Key can
access
the Door it can open,
but an instance of Door does
not know the set of instances of Key that
can open it: the Door cannot
traverse the connections (links)
against
the navigability of the association. On the other side,
the association
Man-Woman is bidirectional, meaning
that connected instances of these classes know each other.

Figure
4. Examples of a) unidirectional and b) bidirectional
associations
The arrowheads can be shown or omitted in
a bidirectional association [UML, p. 3-73]. Unfortunately, this leads
to an ambiguity in the graphical
notation, because we cannot distinguish between bidirectional associations
and associations with unspecified navigability. Or, worse, unspecified
associations are assumed to be bidirectional without further analysis
[Génova 01].
Unidirectional associations
A single unidirectional association is
very similar to a single valued attribute in the source class, of the
type of the target class: an
embedded reference, pointer, or whatever you want to call it. The equivalence,
however, is not complete. Whereas the attribute value is "owned" by
the class instance and has no identity, an external referenced
object has identity and can be shared by instances of
other classes that have a reference to the same object [Rumbaugh 96b]
(see Figure 5). Anyhow,
the equivalence is satisfactory enough to serve as a basis for the
implementation of this kind of associations. In fact, in Java there
is no difference at all: except for the case of primitive values, attributes
in Java are objects with identity, and if they are public you cannot
avoid them to be referenced and shared by other objects.

Figure 5.
Partial equivalence between a) attribute and b) single unidirectional
association
A multiple unidirectional association is a bit more complicated,
although the implementation can be based on the same principles, since
it can
be assimilated to a multivalued attribute10.
To manage the collection of objects on the navigable end, however,
we need an additional object
of a standard collection class, which is a HashSet in
our implementation (see Figure 6).

Figure 6. Multiple unidirectional
association: a) analysis diagram
and b) design diagram.
A new object must be inserted to manage
the collection of target objects.
The standard collections in Java,
such
as HashSet,
are defined for the standard class Object,
which is a superclass of every class; therefore, mutator methods must
ensure
that the objects
contained in the collection parameter are of the
appropriate type before adding them to the collection attribute.
Therefore, the type of the attribute used to implement the association
inside the source class is not any more the target class itself, but
the HashSet class or another convenient collection
class. The methods to manage the association will have to accomplish
some additional tasks.
Mutators can add or remove not only single objects of the
class target, but also entire collections; thus, the type of the parameter
will be
either the target class of the association or the intermediate collection
class. In this case, mutator methods must ensure that the objects contained
in the collection parameter are of the appropriate type before adding
them to the collection attribute. Accessors, as we have already
explained (see Section 2), do not return a single object, but a collection
of
objects, even when the collection is made up of only one element. The
returned collection object is not identically the same one that is
stored inside the source class, but a clone (a new object with a collection
of references to the same target elements), because the original collection
object must remain completely encapsulated inside the source object
(represented by the composition in Figure 6).
As the diagrams in Figures
5 and 6 show, in our opinion the multiplicity constraint in a design
model can be specified only for a navigable
association end11. Indeed,
the multiplicity is a constraint that must be evaluated within the
context of the class that owns the association
end; if that class knows the constraint, then it knows the association
end, that is, the end is navigable. You cannot restrict the number
of objects connected to a given instance unless this instance has some
knowledge of the connected objects, that is, unless you make the association
end navigable. Therefore, the need for a multiplicity constraint
other than 0..* (that is, unrestricted) is an indication that
the association end must be navigable. In consequence, unidirectional
associations with multiplicity constraints on the nonnavigable association
end must
be rejected in code generation.
Bidirectional associations
The partial equivalence between attributes
and unidirectional associations is not any more found among bidirectional
associations. Instead, an
instance of a bidirectional association is more like a tuple of elements
[UML, p. 2-19]. Combining the multiplicities in both association ends, we
can have three cases: single-single, single-multiple, and multiple-multiple.

Figure
7. Single-single bidirectional association: a) analysis diagram
and b) design diagram. The implementation of the association's
mutators
must ensure that the husband of the wife of a given man is that man
himself, and vice versa

Figure 8. Sequence diagram illustrating the
synchronization of a bidirectional association. The update of the attribute
Woman.husband to "John" (last
operation) takes place only after the update of the attribute Man.wife to "Mary" has
been correctly accomplished. If the woman were already married, then
she would not request the man to update the marriage association on
his side; if the update on the man's side fails (because
he is already married), then the woman does not update her side. To
achieve this behavior, the add method returns
a convenient result that is checked by the client object
An easy way to implement a single-single bidirectional association
is by means of two synchronized single unidirectional associations
(see Figure 7). The synchronization of the two halves must be preserved
by the mutator methods on each side: every time an update is requested
on one side, the other side must be informed to perform the corresponding
update; the update is accomplished only if both sides agree that they
can perform it while keeping maximum multiplicity constraints12 (see
Figure 8).
A single-multiple bidirectional association can be implemented
in a similar way, combining a single unidirectional association and
a multiple
unidirectional association. And, finally, a multiple-multiple bidirectional
association is achieved by means of two multiple unidirectional associations
(see Figure 9).

Figure 9. Multiple-multiple bidirectional association:
a) analysis diagram and b) design diagram
Synchronization becomes
progressively a more and more complex issue when one or both association
ends are multiple. Consider the example
given in Figure 9. Suppose you want to add an author to a particular
Book instance; you do this by issuing the add method
on the Book instance,
and passing a Person instance as a parameter.
If the Book can have
more authors without violating its maximum multiplicity (which is 3),
then it requests the author to add the Book itself
to the collection of publications the Person has;
this can fail if the maximum multiplicity constraint for the number
of publications (in this case, 10) is violated.
If the request to the author succeeds, then the Book updates
its side.
Now, you can try adding a collection of authors to a Book,
too. As one can expect, the Book requests
each one of the authors to add the Book itself
as a publication; if only one of the authors fails to add the Book,
then the whole operation must be undone, since an update must be atomic:
all or none.
Similar considerations apply to the remove mutator,
bearing in mind that the remove method is
performed even if the minimum multiplicity constraint is not kept,
therefore it can leave the source instance
or any of the affected target instances in an invalid state.
In UML,
an association is defined as a "set of tuples" [UML,
p. 2-19], meaning that you cannot have twice the same tuple in the
collection of links of an association13 .
This is automatically safeguarded if we follow the implementation scheme
explained above. Anyhow, it
suggests also a different kind of implementation that could have some
advantages. Instead of synchronizing two unidirectional associations
to get a bidirectional one, we can directly store the collection of
bidirectional links (see Figure 10).

Figure 10. An alternative scheme
for implementing bidirectional associations by means of a collection
of "reified" tuples
Within this alternative scheme the links
are "reified" and
become objects on their own [Rumbaugh 87]. To manage the collection
of links, or tuples, we need an object, which will be the only instance
of a class (in application of the "Singleton" design pattern
[Gamma 94]) representing the association itself. The main advantage
of this approach is that it avoids the dispersion of the information
about the association instances (links), so that updates are effected
in only one place, without synchronization problems. It is easily extended
to implement association-classes and associations of higher degree
(ternary associations, etc.). However, these advantages have a high
cost, as we can appreciate by comparing Figures 9 and 10.
First, note
that the original multiplicity constraints are not
expressed in this scheme: the multiplicity of roles Person.pbAssociation and Book.pbAssociation must
be obviously 1..1, since there is only one
instance of the object that manages the association considered as a
collection of links; besides, a link is the connection of two instances,
therefore a link has exactly one "leg" on each side [Génova
02] [Génova 03b], that is, multiplicities must be 1..1 on the
roles author and publication;
finally, the role tuple has multiplicity
0..* regardless of the multiplicity of the original association, even
if it was single-single, because it stores all the links that may exist
between any instances on each side. In consequence, multiplicity constraints
become more difficult to keep, since the control cannot consist simply
in "counting links".
Second disadvantage, the uniqueness of
each tuple, required by the "set
of tuples" constraint, is not automatically safeguarded. Suppose
we implement the collection of tuples by means of a HashSet of objects,
each object storing two references, author and publication. As each
tuple object has its own identity, two different tuples referencing
the same two targets would be considered as different objects, therefore
the HashSet collection would not check the uniqueness of each tuple
for us14.
Considering all these factors, in our implementation we have
discarded the "reified tuples" approach in favor of the previous "synchronized
cross-references" scheme.
4 THE PROBLEM OF VISIBILITY
So far we have dealt only with the Java
implementation of two features of UML associations: multiplicity and
navigability (directionality),
but we are interested also in the implementation of visibility. According
to the Standard [UML, p. 2-23], the visibility of an association end "specifies
the visibility of the association end from the viewpoint of the classifier
on the other end". The Standard assimilates the visibility of
an association end to the visibility of an attribute, and gives the
same four possibilities:
- public - Other classifiers may navigate the association
and use the rolename in expressions, similar to the use of a public
attribute.
- protected - Descendants of the source classifier may navigate
the association and use the rolename in expressions, similar to the
use of a protected
attribute.
- private - Only the source classifier may navigate the association
and use the rolename in expressions, similar to the use of a private
attribute.
- package - Classifiers in the same package (or a nested
subpackage, to any level) as the association declaration may navigate
the association
and use the rolename in expressions15.
In Java we find the same four
kinds of visibility for attributes and methods (not a chance, of course),
known as access control levels [Gosling
96] [Arnold 00], although their semantics is not exactly the same as
in UML16. Package visibility is
the default for unspecified access control, usually known as friendly.
Since we have implemented UML associations by means of Java attributes
and methods, it seems that we should not
find special problems with the implementation of visibility17;
on the contrary, it should be rather easy.
This is true for unidirectional
associations: if we declare the Java
attributes and methods with the same access control as the UML association
end we want to implement, we automatically get the desired behavior.
But the story runs differently for bidirectional associations. In principle,
it seems sensible to declare private one or both ends of a binary association.
We can think of an association with two private ends as a "secret" relationship
that is not known outside the participating classes, such as a Bank-Client association,
for example. Similarly, an association with one public and one private
association ends would be only partially known from
the outside. But there are problems. Consider the bidirectional association Lecturer-Subject with
public and private visibilities (see Figure 11).

Figure 11. A bidirectional
association with public and private association ends
The public association
end, lecturer, can be used by any other class
in the model with visibility to the Subject class,
that is, the collection of lecturers that teach on a given subject
can be queried and updated
directly by any class in the model that sees the subject. Instead,
the private association end, subject, meaning
the collection of subjects on which a given lecturer teaches, is known
only to the lecturer itself,
just as a private attribute. The Lecturer class
could declare other public methods that internally refer to the subject rolename,
thus providing indirect access to the private association
end, but direct
access is restricted to the owner class itself. This is no more
than the idea of declaring something private.
Now, we have got a paradox
here about the bidirectionality of the association.
The association end with the private rolename subject is
known only to its owner, that is, the Lecturer class.
We repeat: only to its owner. That means that the Subject class
does not know the subject association
end! The Subject class knows that it is associated
with the Lecturer class, but it
does not know that the Lecturer class is
associated with it in return. Is this really a bidirectional association?
In
our implementation, based on synchronized cross-references as explained
above, this paradox manifests itself in the impossibility to reciprocally
update the association ends. Remember that, when an instance of Subject tries
to add an instance (newLecturer) of the Lecturer class
to its collection of lecturers (lecturer.add(newLecturer)),
it first has to invoke the add method on
the reciprocal side (lecturer.subject.add(self))18
; but now this is impossible due to the private visibility of the subject association
end. The same happens with the remove method.
On the contrary, if an instance of Lecturer tries
to update the association, it can issue the update method on the opposite
side, because it is public,
and it can update its own private side, thus the whole operation succeeds.
At first sight, then, it seemed that the association could be managed
via the class that owns the public association end (in this case, the Subject class),
but this has turned to be false: in fact, only the class that owns
the private association end (Lecturer) can
manage the association, and direct access from outside the two participating
classes
is impossible. However, as it has been explained above, the Lecturer class
could declare public methods to provide indirect access to the private
association end from the outside.
Even worse, if both association ends
were private, as in the Bank-Client example,
the association would become inaccessible from both sides19.
The approach based on "reified tuples" does not solve the
problem either, since it involves auxiliary classes that cannot provide "private" access
to the main classes, excluding all other classes.
Summing up, a public-private
bidirectional association can be managed only from the class that owns
the private end, and other classes, including
the class on the other end of the association, can have only indirect
access if this class provides the adequate public methods. A private-private
bidirectional association, on the contrary, cannot be managed at all.
Similar considerations can be made for package and protected visibility,
which behave in this case respectively like public and private visibility.
In consequence, bidirectional associations with visibility other than
public or package in both ends must be rejected in code generation.
We think this result is not only a bias of our particular implementation,
but a real semantic difficulty of the definition of visibility in bidirectional
associations. Visibility in UML is not specified for associations but
for association ends, and it is assimilated to the visibility of attributes
[UML, p. 2-23]. We need in UML a definition of visibility that fits
better with the concept of bidirectional association.
5 A UNIFORM
INTERFACE
The code required to implement a UML association consists
basically of an adequate combination of Java attributes and methods,
but this
combination depends on the multiplicity, navigability and visibility
of the association. With respect to multiplicity, to store
the only possible instance of a single association we can employ an
attribute
of the corresponding target class, but to store the many potential
links of a multiple association we need some kind of collection of
objects: we have chosen a HashSet collection,
since it ensures that there are no duplicate objects in the collection.
With respect to navigability,
a unidirectional association is implemented only in the source class,
whereas a bidirectional association is implemented in both classes,
with code that ensures the synchronization of both ends. The visibility of
the association ends maps directly onto the visibility of the required
methods; the attributes, instead, will remain always private, to keep
a controlled access through the interface methods.
We have designed
a uniform interface for all kinds of associations, that is, an interface
that is as independent as possible of the multiplicity,
navigability and visibility of the association ends. The interface
comprises accessor and mutator methods, as well as other auxiliary
methods to learn the state and definition of the association. Our intention
is that the client code can use the interface of the association without
knowing a priori, when possible, what kind of association it is; this
will make the client code much more stable with regard to changes in
the design (for example, a unidirectional association that becomes
bidirectional).
In fact, the implementation of unidirectional and bidirectional
associations is different, because only bidirectional associations
have to be synchronized,
but both kinds present exactly the same interface on each end. On the
contrary, single and multiple associations have not only different
implementations, but a slightly different interface, because single
associations do not manage collections of objects as parameters or
return values. We could treat single associations as a particular case
of multiple associations and provide no special implementation or interface
for them, but we consider that they are used so frequently that the
benefits in efficiency are proportionate to the losses in interface
uniformity.
In the following paragraphs, "%Target" means the
name of the target class in the association, which will have to be
substituted
by its real name when the code is generated for each concrete association
in the design model. The source class of a unidirectional association
presents an interface to query and update the opposite association
end; the target class does not present an interface, because it is
not aware of the association. In contrast, the two sides of a bidirectional
association present an interface; in this case the terms "source" and "target" become
relative to the class that is seeing the opposite association end.
Accessor
methods
We have two accessor methods, test and get, with the following
signatures:

The test method checks whether a given
instance of the target class (the query_link parameter)
is linked with the instance of the source class that receives the method
invocation. The second version of
this method is defined only when the association end is multiple; in this
case the method checks whether all the instances contained
in the collection parameter are linked to the source instance20.
The
get method returns the target instances that are linked with the
source instance. The first version is for a single association
end
and it returns a unique value, the type of which is the %Target class,
whereas the second version is for a multiple association end, so
that it returns a value of type Collection. According to the justification
given above when dealing with the problems of multiplicity, mutator
methods warrant that maximum multiplicity is not violated, but regarding
minimum multiplicity, it can happen that the number of linked instances
is smaller than the minimum required by the design, in which case
the
invalid multiplicity exception is raised21.
Mutator methods
We have also two mutator methods, remove and add, with the following
signatures:

The remove method deletes
target instances from the opposite association end, and returns a
convenient error code. It can remove all
instances (first parameterless version), one instance (second version),
or a collection of instances (third version, available only when the opposite
association end is multiple). In the third version, if any
instance in the collection parameter is not of type %Target,
then no link is removed, following the "none or all" semantics,
and a
class cast exception is raised. On the contrary, if any instance
in the
collection (or the single instance, in the second version of the method)
is simply
not linked to the source instance, then the operation proceeds
without considering it an error. In a bidirectional association, the
method invokes a reciprocal remove on each
one of the instances to be
deleted.
The remove method can leave the
source instance or some of the target instances in an invalid
state regarding the minimum multiplicity
constraints, in which case an error code is returned, but no exception
is
raised. If a subsequent get method were invoked,
the invalid
multiplicity exception would be raised.
The add method
appends a new target instance or a collection of target instances to
the opposite association end, and
returns a
boolean value to indicate whether the operation was performed or
not. The second
version of this method is defined only when the association
end is multiple; if any instance in the collection parameter
is not
of type
%Target, then no link is added, following the "none
or all" semantics,
and a class cast exception is raised. On the contrary, if
any instance in the collection (or the single instance, in
the first version
of the method) is already linked to the source instance,
then the operation
proceeds without considering it an error (and, of course,
without adding a duplicate). In a bidirectional association,
the method
invokes a
reciprocal add on each one of the instances to be appended.
The add method checks whether the source instance, or any
of the target
instances,
would be left in an invalid state regarding the maximum multiplicity
constraints, in which case the operation is cancelled, no
link is added, and a False value is returned22.
If you want
to substitute some target instances by other target instances,
you must invoke first the remove method
and then
the add method;
otherwise the result could be different from expected (see
Section 2). Beware
that this is valid even for single associations:
there is no implicit remove of
the old instance when you add a new instance
(this is done
this way in order to get the most similar behavior between
single and multiple associations).
Auxiliary methods to learn
the state of the association
We have two auxiliary methods
to know the state of the association from the point of view of a
particular source instance:

The isValid method determines whether
the source instance sees the right number of target instances on
the opposite side of
the association, according to the multiplicity constraints specified in the
design
model. The tool generates code only for the simplest case, where the
multiplicity constraint consists of a single MIN..MAX interval.
Anyway, the programmer
can modify manually the code to implement a more complex
constraint, and the changes will affect the execution of accessor and mutator
methods,
since they check the multiplicity constraints by means of
this
method. This method is useful too when the automatic check of multiplicity
constraints is disabled and the programmer assumes the responsibility
for checking them manually at specific points in the source
code.
The numberOfLinks method returns the number
of target instances linked to the source instance.
Auxiliary methods to
learn the definition of the association
We have five auxiliary methods
to know the definition of the association from one side of the association,
that
can be useful
for the client
code:

The isBidirectional method determines
whether the reciprocal association end is navigable too. The isMandatory method
determines whether the minimum multiplicity is greater than zero.
The isMultiple method
determines whether the maximum multiplicity is greater than one.
The
getMIN method
returns the value of the minimum multiplicity constraint.
The getMAX method returns the value of the maximum
multiplicity constraint. A special value is returned when this is many ('*').
The interface also
defines the constant value int MANY (actually –1).
6
THE CODE GENERATION TOOL
In this section we are going
to present briefly the tool we have developed: JUMLA (Java
code generator for Unified
Modeling
Language
Associations).
This tool reads a UML model, stored in XMI format,
and generates Java code to manage the UML associations contained
in the
input model, according
to the technique described in this paper. The tool
generates code for associations only: it ignores every other UML
artifact that is
not
directly related to associations, such as generalization
between classes, class attributes and methods, etc.
The tool presents
the classes and
associations found in the model, and the user can select
which associations he or she wants to generated code
for.
The tool creates output Java files for the involved
classes and inserts into them the code for the associations,
with convenient labels to
mark the start and the end of the generated code.
If the class file already exists, the code is inserted
at
the
end of the
class
file,
respecting any other class code that the programmer
may have written manually (on the contrary, if the
programmer
changes
the association
code and then re-generates it, the manual changes
are lost).
Figures 12 shows a sample model and Figure 13 shows
how it is presented in the main window of the JUMLA
tool.
The left
pane
of the tool shows
the classes contained in the model, in a tree structure
corresponding to the package structure of the model.
The right pane shows
the associations contained in the model. For each
association, the
following information
is presented: source and target classes; rolename
(optional), multiplicity, navigability and visibility
of source
and target association ends;
association name (optional). The user can select
with check boxes the associations he or she wants
to generated
code
for.

Figure 12. A sample model with some classes
and associations between the classes

Figure 13. A snapshot of the
JUMLA tool. The interface of the current version of the tool is
in Spanish (Archivo = File,
Edición =
Edit, Ayuda = Help). The tool behaves according to five
predefined options which can be
disabled by the user to get more flexibility in the generation of code
or in dealing with the input model. Table 1 summarizes them.
| Tool Option |
Default |
| Check minimum and maximum multiplicity constraints
in get method |
Yes |
| Check maximum multiplicity constraint in add method |
Yes |
| Check type of objects in Collection parameters
in add and remove methods |
Yes |
| Reject unidirectional associations with multiplicity
constraint on source end |
Yes |
| Reject bidirectional associations with one private
or protected end |
Yes |
Table 1. Summary of tool options
The first two options refer to the automatic checking of multiplicity
constraints in mutator and accessor methods by means of the isValid auxiliary
method. According to the justification given in Section 2, the predefined
behavior is: get methods raise an invalid
multiplicity exception, defined in the code that implements the
association, if multiplicity constraints are not satisfied; add methods
reject the addition of new links if these constraints are not satisfied,
but they
raise no exception; and remove methods don’t
do any checking. Changing the default value of these two options allows
the generation
of a simplified code that omits these checks, so that the user assumes
the responsibility of controlling multiplicity.
The third tool option
refers to the automatic type checking in mutator
methods (add and remove)
for multiple associations, which deal with
Collection parameters, by means of run-time
explicit casting. According to the justification given in Section 2,
if the type-check fails, then
the links are not updated, and the Java predefined class cast exception is
raised. Changing the default value of this third option allows the
generation of a simplified code that does not check the type of objects
received in a Collection parameter, and does
not raise this exception.
The last two options refer to the checking
of the input model´s
correctness. In the predefined behavior, unidirectional associations
with multiplicity constraints on the nonnavigable association end are
rejected (see Section 3), and bidirectional associations with visibility
other than public or package in both ends are also rejected (see Section
4). Changing the default value of the fourth option allows the generation
of code without checking the multiplicity on the nonnavigable end,
instead of rejecting the association. Changing the default value of
the fifth option allows the generation of code, instead of rejecting
the association, when one of the ends is protected or private and the
other end is public or package, warning the user that he or she must
provide an indirect access via other methods. When both ends are protected or private, the association is allways rejected, since the generated
code could not work properly.
7 CONCLUSIONS
In this work we have developed a concrete way of mapping
UML associations into Java code: we have written specific code patterns,
and we have
constructed a tool that reads a UML design model stored in XMI format
and generates the necessary Java files. We have paid special attention
to three main features of associations: multiplicity, navigability
and visibility. Our analysis has encountered difficulties that may
reveal some weaknesses of the UML Specification [UML].
Regarding multiplicity,
we have shown that it is impossible in practice with a few primitive
operations to keep the minimum multiplicity constraint
at any moment on a mandatory association end; our proposal is to check
this constraint only when accessing the links, but not when modifying
them. The programmer will be responsible for using the primitives in
a consistent way so that a valid system state is reached as soon as
possible. On the contrary, it is possible to ensure the fulfillment
of the maximum multiplicity constraint during run-time, and so we enforce
it in our implementation. Single association ends are easily stored
in attributes having the related target class as type, but multiple
association ends require the use of collections to store the corresponding
set of links; as collections in Java are based on the standard Object class, it is necessary to perform run-time type-checking by means of
explicit casting when using collections as parameters in the mutator
methods.
Regarding navigability, unidirectional associations are easier
to implement by means of attributes than bidirectional associations,
because of
the difficulties in synchronizing both associations ends. An update
to a bidirectional association must be performed atomically on both
ends to keep them consistent; this is achieved in the source object
by issuing a reciprocal update on the target object. We have considered
the pros and cons of an alternative implementation, based on the storage
of “reified tuples”, and finally we have discarded it in
favor of our “synchronized cross-references” scheme. A
side consequence of our analysis is that the multiplicity constraint
in a design model can be specified only for a navigable association
end.
Regarding visibility, in the case of unidirectional associations
it can be implemented rather easily by simply mapping the visibility
of
the association end onto the visibility of the corresponding accessor
and mutator methods, because UML and Java visibility levels have the
same semantics. However, bidirectional associations with one or two
private (or protected) ends behave paradoxically, because the reciprocal
update becomes impossible. Besides, we consider that package visibility
is ill-defined for associations in the UML Specification, and we have
suggested a new definition.
The generated code for each association
is easily localized inside the involved Java classes. Each association
end presents a uniform
programmer's interface. The interface is exactly the same for unidirectional
and bidirectional association ends, but there are slight differences
for single and multiple association ends.
Our approach is rather check-exhaustive
with regard to invariants. We think that it is worth doing for the
programmer as much as we can,
so that our tool will insert code to perform run-time multiplicity
and type checking and, of course, to issue reciprocal updates on bidirectional
associations. However, different tool options will allow the user to
override the automatic multiplicity and type checks when generating
code, in favor of efficiency. Besides, we have argued that unidirectional
associations should not have a multiplicity constraint on the source
end in a design model, and bidirectional associations should not have
both ends with private (or protected) visibility; therefore, the tool
will reject the generation of code for these associations. Again, the
user will be able to disable this model-correctness checking and issue
the code generation at his/her own risk.
This work can be continued
on several lines. First, implementation of other association end properties,
such as ordering, changeability,
interface specifier, xored associations, and so on. Second, specific
implementation of particular kinds of binary associations, such as
reflexive associations, aggregations and compositions. Third, implementation
of more complex associations: qualified associations, associations
classes, and n-ary associations. Fourth, expand the tool to perform
reverse engineering, that is, obtaining the associations between classes
by analyzing the code that implements them. Our tool does not presently
accomplish this task, although it is a very simple and straightforward
procedure if the code has been written with our patterns. Finally,
adapt the tool and the patterns so that they follow the new Java Metadata
Interface (JMI) Specification [JMI].
8 ACKNOWLEDGEMENTS
The authors wish
to give thanks to Perdita Stevens, since this paper was written mainly
while the first author was visiting
the Laboratory for Foundations of Computer Science (LFCS), part of
the Division of Informatics of the University of Edinburgh, invited
by her in February-April 2002; a preliminar version of this work was
presented at the LFCS Lab Lunch on April 23rd 2002. This research stay
was accomplished with funding by the Fundación Universidad Carlos
III, Madrid, Spain. Thanks also to José Miguel Fuentes, Víctor
Quintana, David Fernández and Vicente Palacios for their valuable
suggestions to improve the paper.
Footnotes
1Actually classifiers. Classifier is a superclass of Class in the
UML metamodel.
2The current submission of communityUML
to the OMG for the development of UML
2.0 [cUML] proposes a change in terminology: "association" instead
of "link" and "association type" instead of "association".
We support this change, but in this paper we are going to follow the current
official terminology in UML.
3We distinguish here between analysis and design models.
An analysis model is an abstraction of the problem (the real world
as it is before the proposed system is built) whereas a design model
is an abstraction of the solution (the proposed system's internal
construction) [Kaindl 99], therefore code generation has sense only
for a design
model.
4Some tools are an exception to this rule [Fujaba] [Rhapsody].
5XML Metadata
Interchange [XMI], an XML-based format designed to store and interchange
UML models between different tools.
6Other notations invert the placement of multiplicity values, following
the near-end convention instead of the far-end convention, which is
the one used in UML. It has been well established that the semantics
of both conventions are equivalent for binary associations, but differ
substantially when they are applied to associations of higher degree
[Song 95] [McAllister 98] [Castellani 00]
[Génova 02] [Génova 03b].
7In other places we have given conclusive arguments against the no-duplicates
restriction in UML associations [Génova 03b], but here we have
respected the current specification of UML.
8That is, you cannot specialize
them to modify their storage structure, but you can modify their
behavior so that they store in effect only the required objects,
precisely by means of the run-time type checking method we describe.
9An alternate definition: the possibility for a source object to designate
a target object through an association instance (link), in order to
manipulate or access it in an interaction with message interchanges.
The Standard does not give a clear definition of navigability, as we
have shown in previous works where we have tried to clarify this topic
[Génova 01] [Génova 03a] [Génova 03b]. In this paper,
we take navigability and directionality as synonyms.
10UML allows multiplicity in attributes, thus multivalued attributes
[UML, p. 2-50].
11This principle does not apply to analysis models, which usually do
not deal with navigability [Fowler 97] [Stevens 00]. Obviously, code
generation only has sense when starting from design models.
12ThisWe have already justified in Section 2 that mutators must be allowed
to violate the minimum multiplicity constraint.
13The convenience of this constraint, inherited from Entity-Relationship
modeling, is disputed by many authors [Genilloud 99] [Stevens 02] [Génova 03b].
14This is not anyway an unsolvable difficulty. For two “equal” tuples
to be recognized and their uniqueness to be warranted, you must redefine
the equals and hashCode methods, inherited from Object and employed
by HashSet with this purpose [Eckel 00].
15This last kind of visibility,
appended in version 1.4 of the Standard, is ambiguously defined, since
an association could be declared between classifiers from two
different packages. Which package does the association declaration belong to,
then? We suggest this wording instead (additions in italics): "Classifiers
in the same package (or a nested subpackage, to any level) as the source
classifiermay navigate the association and use the rolename in expressions, similar
to
the use of an attribute with package visibility.
16The protected access control
means in Java the union of protected and package visibilities in UML, that
is, the protected element is visible for descendants
as well as for other elements in the same package [Arnold 00] [Eckel 00] [Gosling 96].
17Except that protected will have the Java meaning, not the UML meaning.
The Standard acknowledges that all forms of nonpublic visibility are
language-dependent [UML, p. 3-42].
18An object refers to itself in UML
by means of the self keyword, equivalent to
Java’s this.
19A reflexive association (an
association between instances of the same class) is an exception to
this rule, since private association ends are visible inside
the class, that is, for both sides of the association.
20The parameter type is defined as Collection to get more generality.
Collection is an abstraction (technically, an interface) realized by
library classes such as ArrayList, HashSet and TreeSet.
21In fact, the check is performed
by the isValid method, which can
be more elaborated than simply verifying that the number of linked
instances is not smaller than the minimum required; the programmer
can modify manually the code of isValid to
implement a more complex constraint.
22As in the previous case, the check is performed by the isValid method,
which can achieve a more general behavior.
REFERENCES
[Amble01] Scott W. Ambler. “An Overview of Object
Relationships”, “Unidirectional
Object Relationships”, “Implementing One-to-Many Object
Relationships”, “Implementing Many-to-Many Object Relationships”.
A series of tips to be found at IBM Developer Works, http://www-106.ibm.com/developerworks/.
[Arnol00]
Ken Arnold, James Gosling, David Holmes. The Java Programming Language.
Addison-Wesley, 3rd ed., 1998.
[Caste00] Xabier Castellani, Henri
Habrias, Philippe Perrin. "A
Synthesis on the Definitions and Notations of Cardinalities of Relationships",
Journal of Object Oriented Programming, 13(6):32-35 (2000)
[cUML] Financial
Systems Architects (New York, U.S.A.). 3C-Clear Clean Concise. Submission
to OMG. Available at http://www.community-ml.org/.
[Eckel00] Bruce
Eckel. Thinking in Java, 2nd ed. Prentice-Hall, 2000.
[Fowle97] Martin
Fowler, Kendall Scott. UML Distilled: Applying the Standard Object
Modeling Language. Addison-Wesley, 1997.
[Fujab] The Fujaba CASE Tool,
University of Paderborn, http://www.fujaba.de/.
[Gamma94] Erich Gamma,
Richard Helm, Ralph Johnson, John Vlissides. Design Patterns. Elements
of Reusable Object-Oriented Software. Addison-Wesley,
1994.
[Genil99] Guy Genilloud. "Informal UML 1.3 - Remarks, Questions,
and some Answers". UML Semantics FAQ Workshop (held at ECOOP'99),
Lisbon, Portugal, June 12th 1999.
[Génov01] Gonzalo Génova. "Semantics
of Navigability in UML Associations". Technical Report UC3M-TR-CS-2001-06,
Computer Science Department, Carlos III University of Madrid, November
2001,
pp. 233-251.
[Génov02] Gonzalo Génova, Juan Llorens, Paloma
Martínez. “The
Meaning of Multiplicity of N-ary Associations in UML”, Software
and Systems Modeling, 1(2): 86-97, 2002. A preliminary version in:
Gonzalo Génova, Juan Llorens, Paloma Martínez. “Semantics
of the Minimum Multiplicity in Ternary Associations in UML”. The
4th International Conference on the Unified Modeling Language-UML'2001,
October 1-5 2001, Toronto, Ontario, Canada. Published in Lecture Notes
in Computer Science 2185, Springer 2001, pp. 329-341.
[Génov03a]
Gonzalo Génova, Juan Llorens, Vicente Palacios. "Sending
Messages in UML", in Journal of Object Technology, vol.2, no.1,
Jan-Feb 2003, pp. 99-115, http://www.jot.fm/issues/issue_2003_01/article3.
[Génov03b]
Gonzalo Génova. Entrelazamiento de los aspectos
estático y dinámico en las asociaciones UML. PhD Thesis,
Carlos III University of Madrid, 2003.
[Gosli96] James Gosling, Bill
Joy, Guy Steele. The Java Language Specification. Addison-Wesley, 1996.
[Harri00]
William Harrison, Charles Barton, Mukund Raghavachari. "Mapping
UML Designs to Java". The 15th Annual ACM Conference on Object-Oriented
Programming, Systems, Languages, and Applications-OOPSLA’2000 October 15-19 2000, Minneapolis, Minnesota, United States. ACM
SIGPLAN Notices,
35(10): 178-187. ACM Press, New York, NY, USA.
[JMI] Java Community
Process. Java Metadata Interface (JMI) Specification, Version 1.0,
June 2002. Available at http://www.jcp.org/.
[Kaind99] Hermann Kaindl. “Difficulties
in the Transition from OO Analysis to Design”. IEEE Software,
16(5):94-102 (1999).
[McAll98] Andrew McAllister. "Modeling N-Ary
Data Relationships in CASE Environments", Proceedings of the
7th International Workshop on Computer Aided Software Engineering, pp.
132-140, Toronto, Canada
(1995). A more recent version in: "Complete Rules for N-Ary Relationship
Cardinality Constraints", Data & Knowledge Engineering, 27(3):255-288
(1998).
[Noble96] James Noble. “Some Patterns for Relationships”.
In Proceedings of Technology of Object-Oriented Languages and Systems
(TOOLS Pacific 21), Melbourne, 1996. Prentice-Hall.
[Noble97] James
Noble. “Basic Relationship Patterns”. In
Proceedings of the European Conference on Pattern Languages of
Program Design (EuroPLOP'97). Irsee, Germany, 1997.
[Rhaps] The Rhapsody
CASE Tool, ILogix, http://www.ilogix.com/.
[RM] James Rumbaugh, Ivar
Jacobson, Grady Booch. The Unified Modeling Language Reference
Manual.
Addison-Wesley, 1998.
[Ruiz02] Carlos Ruiz del Castillo. Implementación
en Java de asociaciones binarias UML. Universidad Carlos III de Madrid,
Proyecto
Fin de Carrera, Ingeniería Informática (Segundo Ciclo),
julio 2002. Tutor: Gonzalo Génova.
[Rumba87] James Rumbaugh. "Relations
as Semantic Constructs in an Object-Oriented Language", In Proceedings
of the ACM Conference on Object-Oriented Programming: Systems, Languages
and Applications,
pp. 466-481, Orlando, Florida, 1987.
[Rumba96a] James Rumbaugh. "Models
for Design: Generating Code for Associations". Journal of
Object Oriented Programming, 8(9):13-17, February 1996.
[Rumba96b] James
Rumbaugh. "A Search for Values: Attributes and
Associations". Journal of Object Oriented Programming, 9(3):6-8,
June 1996.
[Song95] Il-Yeol Song, Mary Evans, E.K. Park. "A Comparative
Analysis of Entity-Relationship Diagrams", Journal of Computer
and Software Engineering, 3(4):427-459 (1995).
[Steve00] Perdita Stevens,
Rob Pooley. Using UML: Software Engineering with Objects and Components.
Addison-Wesley, 2000.
[Steve02] Perdita Stevens. “On the Interpretation
of Binary Associations in the Unified Modelling Language”, Journal
on Software and Systems Modeling, 1(1):68-79 (2002). A preliminar version
in: Perdita Stevens. "On
Associations in the Unified Modeling Language". The Fourth
International Conference on the Unified Modeling Language, UML'2001, October 1-5,
2001, Toronto, Ontario, Canada. Published in Lecture Notes in Computer
Science 2185, Springer 2001, pp. 361-375.
[UML] Object Management Group.
Unified Modeling Language (UML) Specification, Version 1.4, September
2001 (Version 1.3, June 1999). Available at
http://www.omg.org/.
[XMI] Object Management Group. XML Metadata Interchange
(XMI) Specification, Version 1.2, January 2002. Available at http://www.omg.org/.
About the authors
 |
 |
Gonzalo Génova received in 2003
his PhD in Computer Science at the Carlos III University of Madrid,
Spain, where he is currently a Teaching Assistant of Software Engineering
and Advanced Software Design. His main research subject is modeling
and modeling languages in software engineering. He can be reached
at ggenova@inf.uc3m.es.
|

|
|
Carlos Ruiz del Castillo received in
2002 his MS degree in Computer Science at the Carlos III University
of Madrid. He is currently working for a news agency in the development
of .NET applications. |
 |
|
Juan Llorens is Associate Professor
of the Computer Science Department at the Carlos III University
of Madrid, Spain, where he is the leader of the IE (Information
Engineering) research group. He is also a Visiting Professor at
Aland’s Institute of Technology - ATL, Mariehamn, Finland.
His current research involves the integration of Knowledge technologies
and Software Engineering techniques towards Software and Information
Reuse. He can be reached at llorens@inf.uc3m.es. |
Cite this article as follows: Gonzalo Génova, Carlos Ruiz del
Castillo and Juan Llorens: “Mapping UML Associations into Java
Code”, in Journal of Object Technology, vol. 2, no. 5, September-October
2003, pp. 135-162. http://www.jot.fm/issues/issue_2003_09/article4
|