Java

Medea provides a template to generate Java classes from a UML class diagram. This is perhaps the most comprehensive template that handles most of the elements of a class diagram. It can serve as a blueprint for other, simplier templates that produce value objects, entity beans etc.

Model

Consider this fictional class diagram.

Javaclass diagram in MagicDraw 11.5

It contains all artifacts the template handles:

  • Packages
  • Classes
    • abstract
  • Interfaces
  • Enumerations
  • Associations
    • named
    • directed
    • bidirectional
  • Generalizations
    • classes
    • interfaces
  • Interface realizations
    • single
    • multiple
  • Attributes
    • standard datatypes
    • class instances
    • initial values
    • arrays
    • static
  • Operations
    • static
    • abstract
    • parameters
    • return values

Build

Since there's only one template in this target, it can be either applied directly or by ant target trans_java:

C:\projects\javaclass>ant trans_java
Buildfile: build.xml

trans_java:

trans:
     [echo] Java
     [java] /projects/javaclass/gen/data/geom/plain/Point.java
     [java] /projects/javaclass/gen/data/graph/Shape.java
     [java] /projects/javaclass/gen/data/graph/TextArea.java
     [java] /projects/javaclass/gen/data/graph/Drawable.java
     [java] /projects/javaclass/gen/data/graph/Refreshable.java
     [java] /projects/javaclass/gen/data/graph/Resizable.java
     [java] /projects/javaclass/gen/data/Alignment.java
     [java] Creates Java classes and interfaces for all classes.

BUILD SUCCESSFUL
Total time: 3 seconds

These files are produced from this example diagram:

Alignment.java

Point.java

Drawable.java

Refreshable.java

Resizable.java

Shape.java

TextArea.java

Template

Let's examine major elements of the template.

Java.xsl

  • The template uses classes function to select all classes from the model regardless of their stereotype (note 'void' parameter passed to the function).
  • The for-each statement iterates thru classes
  • We use functions to collect names, attributes, association ends etc. as well as construct the resulting filename (note how the parameter $purePackage is used)
  • Function results are saved in variables. We will use these variables throughout the template
    <xsl:for-each select="cr:classes('void', root(.))">
                    <xsl:variable name="className" select="cr:nameUpper(current())"/>
                    <xsl:variable name="ends" select="cr:ends(current(), root(.))"/>
                    <xsl:variable name="attrs" select="cr:attributes(current())"/>
                    <xsl:variable name="visibility" select="cr:visibility(current())"/>
                    <xsl:variable name="abstract" select="cr:abstract(current())"/>
                    <xsl:variable name="package" select="cr:classPackage($purePackage, current(), root(.))"/>
                    <xsl:variable name="fileName" select="cr:fileNameJava($purePackage, $className, current(), root(.))"/>
                    <xsl:variable name="extends">
                            <xsl:if test="cr:extends(current(), root(.)) != ''"> extends <xsl:value-of select="cr:extends(current(), root(.))"/></xsl:if>
                    </xsl:variable>         
                    <xsl:variable name="implements">
                            <xsl:choose>
                                    <xsl:when test="cr:implements(current(), root(.)) != ''"> implements  <xsl:value-of select="cr:implements(current(), root(.))"/></xsl:when>
                            </xsl:choose>
                    </xsl:variable>
    
  • This template code instructs to write to the resulting document, composes import statements, javadoc, class declaration and a default constructor (note how an empty HashSet is created when there's a many-to-one relationship)
    <xsl:result-document href="{$fileName}"><xsl:value-of select="$package"/>;
    java.util.*;
    <xsl:value-of select="cr:classImports($purePackage, 'void', root(.))"/>
    <xsl:value-of select="cr:classImports($purePackage, 'entity', root(.))"/>
    
    /** fileName=<xsl:value-of select="$fileName"/> xmi.id=<xsl:value-of select="@xmi.id"/>
    * <![CDATA[<!-- begin-user-doc -->
    * <!-- end-user-doc -->
    * @generated]]>
    */
    <xsl:value-of select="concat($visibility, ' ', $abstract)"/> class <xsl:value-of select="$className"/><xsl:value-of select="$extends"/><xsl:value-of select="$implements"/> {
            /**
            * <![CDATA[<!-- begin-user-doc -->
            * no argument constructor
            * <!-- end-user-doc -->
            * @generated]]>
            */
    <xsl:value-of select="$className"/>() {
                    <xsl:for-each select="$ends">
                            <xsl:if test="cr:multiUpper(current()) = -1">
                    <xsl:value-of select="cr:endFieldName(current(), root(.))"/>Set = new HashSet();
                    </xsl:if>
                    </xsl:for-each>
                    // begin-user-code
                    // end-user-code
            }
    
  • This template code iterates over class' attributes and creates their declarations, getters and setters
            <xsl:for-each select="$attrs">
            <xsl:variable name="name" select="cr:name(current())"/>
                    <xsl:variable name="nameUpper" select="cr:nameUpper(current())"/>
                    <xsl:variable name="dataType" select="cr:dataType(current(), root(.))"/>
                    <xsl:variable name="initialValue" select="cr:initialValue(current())"/>
            /** xmi.id=<xsl:value-of select="@xmi.id"/>
            * @unmodifiable
            */
    <xsl:value-of select="concat($dataType, ' ', $name)"/><xsl:if test="$initialValue != ''"> = <xsl:value-of select="$initialValue"/></xsl:if>;
            /** 
            * @unmodifiable
            */
    <xsl:value-of select="$dataType"/> get<xsl:value-of select="$nameUpper"/>() {
            <xsl:value-of select="$name"/>;
            }
            /** 
            * @unmodifiable
            */
    void set<xsl:value-of select="$nameUpper"/>(<xsl:value-of select="concat($dataType, ' ', $name)"/>) {
            .<xsl:value-of select="$name"/> = <xsl:value-of select="$name"/>;
            }
            </xsl:for-each>
    
  • These markups iterate thru associations of this entity and produce references in the Java class
    <!-- associations -->
            <xsl:for-each select="$ends">
                    <xsl:variable name="myEnd" select="current()"/>
                    <xsl:variable name="otherEnd" select="cr:otherEnd(current(), root(.))"/>
                    <xsl:variable name="myUpper" select="cr:multiUpper($myEnd)"/>
                    <xsl:variable name="otherUpper" select="cr:multiUpper($otherEnd)"/>
                    <xsl:variable name="myClassName" select="cr:endClassName($myEnd, root(.))"/>
                    <xsl:variable name="otherClassName" select="cr:endClassName($otherEnd, root(.))"/>
                    <xsl:variable name="myFieldName" select="cr:endFieldName($myEnd, root(.))"/>
                    <xsl:variable name="otherFieldName" select="cr:endFieldName($otherEnd, root(.))"/>
                    <xsl:variable name="myFieldNameUpper" select="cr:upper($myFieldName)"/>
                    <xsl:variable name="otherFieldNameUpper" select="cr:upper($otherFieldName)"/>
            /** xmi.id=<xsl:value-of select="@xmi.id"/>
            * myUpper=<xsl:value-of select="$myUpper"/> otherUpper=<xsl:value-of select="$otherUpper"/>
            * @unmodifiable
            */<xsl:choose>
                            <xsl:when test="$myUpper = -1 and $otherUpper = 1">
    Set <xsl:value-of select="$myFieldName"/>Set;
            /** 
            * @unmodifiable
            */
    Set get<xsl:value-of select="$myFieldNameUpper"/>Set() {
            <xsl:value-of select="$myFieldName"/>Set;
            }
            /** 
            * @unmodifiable
            */
    void set<xsl:value-of select="$myFieldNameUpper"/>Set(Set <xsl:value-of select="$myFieldName"/>Set) {
            .<xsl:value-of select="$myFieldName"/>Set = <xsl:value-of select="$myFieldName"/>Set;
            }
            /** 
            * @unmodifiable
            */
    void add<xsl:value-of select="$myFieldNameUpper"/>(<xsl:value-of select="concat($myClassName, ' ', $myFieldName)"/>) {
                    <xsl:value-of select="$myFieldName"/>Set.add(<xsl:value-of select="$myFieldName"/>);<!--
                    <xsl:if test="$otherEnd/@isNavigable = 'true'">
            (<xsl:value-of select="$myFieldName"/> != null)
                            <xsl:value-of select="concat($myFieldName, '.set', $otherFieldNameUpper, '(this')"/>);
                    </xsl:if>-->
            }
                            </xsl:when>
    
  • This code will produce operations:
            <!-- operations -->
            <xsl:for-each select="cr:operations(current())">
                    <xsl:variable name="visibility" select="cr:visibility(current())"/>
                    <xsl:variable name="returnType" select="cr:returnType(current(), root(.))"/>
                    <xsl:variable name="abstract" select="cr:abstract(current())"/>
                    <xsl:variable name="static" select="cr:static(current())"/>
                    <xsl:variable name="params" select="cr:parameters(current(), root(.))"/>
            /**
             * <![CDATA[<!-- begin-user-doc -->
             * <!-- end-user-doc -->
             * @generated]]>
             */
            <xsl:value-of select="concat($visibility, ' ', $abstract, ' ', $static, ' ', $returnType, ' ', @name)"/>(<xsl:for-each select="$params"><xsl:value-of select="concat(cr:dataType(current(), root(.)), ' ', @name)"/><xsl:if test="position() != last()">, </xsl:if></xsl:for-each>)<xsl:choose>
                    <xsl:when test="$abstract">;
                    </xsl:when>
                    <xsl:otherwise> {
                    // begin-user-code
                    <xsl:if test="$returnType != 'void'">
                    <xsl:value-of select="$returnType"/> ret = null;
                    return ret;</xsl:if>
                    // end-user-code
            }
            </xsl:otherwise></xsl:choose>
            </xsl:for-each>
    
  • This code will select interfaces from the model and write them into source files:
            <!-- interfaces -->
            
            <xsl:for-each select="cr:interfaces(root(.))">
                    <xsl:variable name="className" select="cr:nameUpper(current())"/>
                    <xsl:variable name="visibility" select="cr:visibility(current())"/>
                    <xsl:variable name="package" select="cr:classPackage($purePackage, current(), root(.))"/>
                    <xsl:variable name="fileName" select="cr:fileNameJava($purePackage, $className, current(), root(.))"/>
                    <xsl:variable name="extends">
                            <xsl:if test="cr:extends(current(), root(.)) != ''"> extends <xsl:value-of select="cr:extends(current(), root(.))"/></xsl:if>
                    </xsl:variable>         
                    
                    <xsl:result-document href="{$fileName}">
    package <xsl:value-of select="$package"/>;
    
    import java.util.*;
    <xsl:value-of select="cr:classImports($purePackage, 'void', root(.))"/>
    <xsl:value-of select="cr:classImports($purePackage, 'entity', root(.))"/>
    
    /** fileName=<xsl:value-of select="$fileName"/>
     * <![CDATA[<!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @generated]]>
     */
    <xsl:value-of select="$visibility"/> interface <xsl:value-of select="$className"/><xsl:value-of select="$extends"/> {
            <xsl:for-each select="cr:operations(current())">
                    <xsl:variable name="visibility" select="cr:visibility(current())"/>
                    <xsl:variable name="returnType" select="cr:returnType(current(), root(.))"/>
                    <xsl:variable name="params" select="cr:parameters(current(), root(.))"/>
            /**
             * @unmodifiable
             */
            <xsl:value-of select="concat($visibility, ' ', $returnType, ' ', @name)"/>(<xsl:for-each select="$params"><xsl:value-of select="concat(cr:dataType(current(), root(.)), ' ', @name)"/><xsl:if test="position() != last()">, </xsl:if></xsl:for-each>);
            </xsl:for-each>
            
    }
            </xsl:result-document>
            </xsl:for-each>
    
  • This code will select enumerations from the model and write them into source files. Enumeration literals become static members of the class.
            <!-- enumerations -->
            
            <xsl:for-each select="cr:enumerations(root(.))">
                    <xsl:variable name="className" select="cr:nameUpper(current())"/>
                    <xsl:variable name="attrs" select="cr:enumerationLiterals(current())"/>
                    <xsl:variable name="visibility" select="cr:visibility(current())"/>
                    <xsl:variable name="package" select="cr:classPackage($purePackage, current(), root(.))"/>
                    <xsl:variable name="fileName" select="cr:fileNameJava($purePackage, $className, current(), root(.))"/>
    
                    <xsl:result-document href="{$fileName}">
    package <xsl:value-of select="$package"/>;
    
    /** fileName=<xsl:value-of select="$fileName"/>
     * <![CDATA[<!-- begin-user-doc -->
     * <!-- end-user-doc -->
     * @generated]]>
     */
    <xsl:value-of select="$visibility"/> class <xsl:value-of select="$className"/> {
            private String label;
            
            /**
            * <![CDATA[<!-- begin-user-doc -->
            * private constructor for enum static members
            * <!-- end-user-doc -->'
            * @generated]]> 
            */
            private <xsl:value-of select="$className"/>(String label) {
                    this.label = label;     
            }
            
            <xsl:for-each select="$attrs">
            /**
             * @unmodified
             */
            public static final <xsl:value-of select="concat($className, ' ', @name)"/> = new <xsl:value-of select="$className"/>("<xsl:value-of select="@name"/>");
            </xsl:for-each>