Tutorial

Code Styles for existing Code

Tutorial

Creating Code Styles for existing code

Code Styles are a unique concept of UML Lab to adapt both code generation and reverse engineering at the same time. To do so, Code Styles combine code templates with UML profiles in an easily usable way.

For example, a Code Style can implement specific requirements on how to generate a field's accessor methods like getter and setter. To do so, it redefines the relevant getter and setter templates, but leaves the rest of the template set unmodified. Therefore, subtle changes to the code generation do not require duplication of large template parts, but can be easily accomplished with low effort.

Likewise a Code Style improves abstraction when reverse engineering code. By defining templates to match specific code blocks, implementation details can be hidden from the model which would otherwise show up as additional attributes, operations, et cetera. This tutorial shows how to create your own custom Code Style.

Prerequisites

This tutorial assumes basic familiarity with UML Lab. If you have not taken the UML Lab Tour yet, this might be a good time to do so to get familiar with UML Lab's core functionality. You can start the tour by choosing Help > Cheat Sheets… and selecting UML Lab Tour from the cheat sheet list.

Contents

  1. Setting up the example
  2. Creating a Code Style Project
  3. Adapting to existing code
  4. Adding an additional template
  5. Wrapping it up

Setting up the example

In this section, we will set up the example project and investigate some unwanted implementation details in the model, which will be the starting point for our new Code Style.

First of all, import some sample code to work with. Select File > New > Example…, choose Code Style Example and click Finish.

The example code is similar to the Shop Example shown in the UML Lab Tour, but does not contain persistence annotations. Instead, the code reveals some implementation details which we don't want to see on the model level.

  • Reverse engineer the source code by right-clicking on the Code Style Example project and choosing File > New > UML Model and Class Diagram. Click on Finish to complete the wizard.
  • After the Reverse Engineering has finished, add the class Employee to the class diagram by double-clicking it in the presented dialog. Then use the fly-out buttons to add its associated classes. In the generated diagram, all classes reference the Logger class, which makes the diagram hard to read.
  • To clean up the diagram, you could just right-click the Logger class and select Hide Element. This will hide the Logger and replace the references with a log property in the referencing classes.

While this gets the diagram cleaned up easily, it would be better to increase the abstraction level of the model instead of manually hiding elements to get a better overview. We can achieve that by creating a new Code Style that captures the logging concept and abstracts from the logging implementation in the model.

Creating a Code Style Project

To create a custom Code Style, we first need a new Code Style project. The Code Style Project Wizard will guide us through the project creation and create a starting point for our customization.

Choose File > New > Other…, select UML Lab > Code Style Project and click Next.

First we need a name for our new project. Enter Logger in the project name field. Click Next to advance to the next page.

On the final wizard page, the name for our custom Code Style is already preconfigured with the project name Logger. If you chose something else for your project name, please change the Code Style name to Logger here. Next, we need to decide which existing Code Style to base our customization on. Since we don't want to get into advanced topics like JPA for now, just use the pre-selected standard Code Style. Now, we choose the code templates we would like to redefine for the target language. Don't worry, you can always add more templates to redefine later on. For now, let's start with recognizing the log property as an implementation detail of all classes annotated with our new Logger style. For that, we need to pick the appropriate templates to customize.

  • The target language already defaults to java, which is just fine.
  • The log field is a class member, which is located somewhere in the source code of a class. If you inspect the example classes, you will notice that its position indeed varies.
  • The template for this kind of code snippet can be found in the File.xpt file, which is used to generate class-specific parts. Expand that node in the tree.
  • Specific elements, which appear in the source code class but should not be represented in the model, are called additionalMember in UML Lab. Select the Fragment Single entry under Template additionalMember from the tree.
  • Click Finish to create the Code Style project and prepare the template file.

Adapting to existing code

Having created the Code Style project, we can now start adapting the new style to better match our existing code base.

UML Lab uses code templates to specify a mapping between model and source code. Those templates can be easily derived from existing source code. Unlike classic MDSD tools, UML Lab uses the same templates to reverse engineer your source code. This means that by teaching UML Lab how to generate implementation details from a more abstract model, the tool also learns how to reverse engineer such a clean model from our code.

In our example, we will now teach UML Lab, how to generate the omnipresent log fields as part of the class body with our new Logger Code Style. An explicit log property is not required in the model anymore. UML Lab recognizes this during the template-based reverse engineering and provides a more concise model.

The Code Style Wizard already opened the newly created File.xpt template file. It is located in the /templates/ directory of the Logger project. The part we are interested in is the section between«DEFINE additionalMember» and «ENDDEFINE» tags. Replace that part with the following lines and save the template file.

«IF Class.isInstance(parent)»
   private static final Logger log = 
                        Logger.getLogger("«getQualifiedName(".")»");
   «addImport("java.util.logging.Logger")»
«ENDIF»

UML Lab uses the Eclipse Xpand template language for its Code Styles. You can learn more about Xpand and its language elements from the Xpand Reference. The Xpand snippet above can be broken down into four simple elements:

  • The IF clause inside guillemets («…») is a control structure that conditionally writes its body code. This template should only apply to UML classes, i.e. the log field should not be generated for interfaces. Therefore, the condition checks if the classifier for which code is currently generated (parent) is indeed a UML class (Class.isInstance()).
  • Text outside guillemets is written to the output verbatim. Here, the log field declaration has been copied from the example's source code into the template.
  • The log declaration needs the full class name of the containing class as a parameter. We use the predefined utility method getQualifiedName(".") to generate its value from the model. This method call is again surrounded by guillemets, telling Xpand to evaluate it and output the result.
  • Finally, the code generator should add an import declaration to the Java source file. This is done with another utility, passing the qualified class name.

The finished template should look as follows:

With our new template and Code Style in place, let's see what UML Lab makes of our code now. Trigger a complete reparse of the model by right-clicking the model file in the project explorer and selecting UML Lab > Reparse all files.

UML Lab opens a dialog asking if the templates should be reloaded. Confirm by clicking on Yes.

UML Lab will then reverse engineer the whole project using all available templates - including the newly defined Code Style. This should only take a couple of seconds.

Once UML Lab has finished reparsing the project, take a closer look at the updated model. You will notice that the log properties have vanished from the model. Click on a class in the diagram and select CodeStyle from the Properties view. Any class with a log field matching the template above will be annotated with our new Logger style.

Adding an additional template

The class diagram still contains some undesirable details such as setter methods for various fields. By inspecting the source code, you can see that all these methods contain an additional log.log() statement. This implementation detail is not part of the default setter templates provided by UML Lab. So let's adapt the attribute setter template to fix this.

To redefine another template in an existing style project, select the project (Logger in our case) from the Package Explorer and choose Edit > Redefine Templates to bring up the wizard page we already know from above.

This time, we want to customize the template set for attributes. These templates can be found in the Attribute.xpt file. Expand that tree item as well as its single child, the Attribute template. You will see that there are three fragments available. Fragments are templates that generate code for a common UML element but to different locations in the output. In this case, the code generation for an attribute is split up into three fragments for the Declaration, Getter and Setter. Select the Setter and click Finish.

A new Attribute.xpt template file for the redefined template is created in the /templates/ folder of the Logger project. and automatically opened by the wizard.

Open the Attribute.xpt file and take a quick look. You will find the setter's method body in the «ELSE» block inside the curly braces. Let's go ahead and add our log statement now. Open one of the setter methods' source code by right-clicking it in the diagram and choosing Navigate to > Source from the context menu. The log statement is located at the start of the setter body. Just copy and paste it to the beginning of our template's setter body. We're almost done now. Note that the log statement makes use of the attribute name. We'll need to replace it with the correct name at runtime. Since our template is defined in the context of the current attribute (as denoted by the FOR Property part of the «DEFINE …» block above) we can just replace the name text with «name». Additionally, we need an import declaration for the Level class. Copy it from the finished example below.

At this point, the method body in your template should look as follows:

{
   log.log(Level.FINE, "change «name»");
   «addImport("java.util.logging.Level")»
   «"   " + thisName(parent)» = «value»;
}
  • The first line is copied from the source code and will be directly written to the output.
  • The attribute name is retrieved from the current attribute.
  • The Level type from the log statement needs to be imported.

The resulting template should look as follows:

Now, let's re-invoke the parser one more time. All remaining setter methods will now vanish from the model. Thanks to our new codestyle templates, the setters are recognized as simple implementation fragments of the attributes and are no longer needed in the model to generate the same code. Instead, the attributes matching our custom setter are now marked with the Logger style, denoting their special implementation.

Wrapping it up

We have seen how UML Lab's template collection can be extended to capture your own coding convention in Code Styles by selectively customizing some templates. This allows UML Lab to recognize your style and to abstract from implementation details while reverse-engineering your source.

Of course, you can also use your custom Code Styles for new elements. Just create a new class and choose the Logger style from the CodeStyle property page. The code for this class will now include our custom Logger field declaration. Similarly, attributes of this class will inherit its style by default, adding the custom log.log(…) code to their setters.

A sample solution of this tutorial is provided as an additional example project. So, if you want to review this tutorial, simply select File > New > Example… > Logger Code Style - stage 1 to import the example Code Style into the workspace.