Welcome to jMDA

To generate software automatically has been a strong ambition since the early days of software development.

jMDA is a new approach in this area. It streamlines proven, widely known and accepted open source technologies into a most comprehensible and easy to use set of Java libraries that are extremely powerful and flexible at the same time. The main purpose of jMDA is

  • to leverage a comprehensible and easy to use modelling environment,

  • to provide convenient and complete access to modelling information and

  • to make available easy to use software generator facilities.

The introduction will briefly explain the main drivers behind this project, the jMDA book provides more detailed information about the most important concepts and the open source software is available here.

A Guided Tour Through jMDA

<!--This file was converted to xhtml by LibreOffice - see http://cgit.freedesktop.org/libreoffice/core/tree/filter/source/xslt for the code.- no title specified

Guided Tour through jMDA

jMDA as it is today comes with two libraries. The first library jmda.core provides the means to read and access jMDA model information. The second one jmda.gen contains the generator framework that makes it amazingly easy to develop custom generators. This chapter will take you on a guided tour in which you will discover some of the things jMDA has to offer.

jMDA Models

We start our tour by creating a simple domain model using the Java type system:
class Person
{
  String firstName;
  String lastName;
  java.util.List<Contact> contacts;
}
class Contact
{
  java.util.List<ContactInfo> contactInfos;
  ContactInfo lastContactInfo;
}
class ContactInfo
{
  java.util.Date date;
  String note;
}
class EMail extends Contact
{
  String eMail;
}
class Address extends Contact
{
  String street;
  String zip;
  String city;
  String country;
}
Creating a domain model could hardly be easier. As you can see the model contains only a minimum amount of technical details such as data types and object relations. You can create this model using any simple text editor. If you use a modern Java IDE you get the full power and comfort of Java source code editing features right out of the box including syntax highlighting, code assistance, refactoring support and many more.
Above that here are tools that can create a visual UML style representation of such a model. The following UML class diagram has been created with an eclipse plugin called ObjectAid that is available for free:

Accessing model information

To create anything based on our model the first question that has to be answered is: how can we access the model information? The most straight forward way is to pick an element from the model and create a TypeElement instance for it. Once we have that type element we can easily access its details:
        TypeElement typeElement = ElementUtil.asTypeElement(Person.class);

        for (VariableElement field : getFields(typeElement))
        {
          out.println("" + field.asType() + " " + field.getSimpleName());
        }
This simple code fragment produces the following output:
        java.lang.String firstName
        java.lang.String lastName
        java.util.List<de.jmda.sample.person_contact.model.Contact> contacts
This is an extremely simple but working example of how to access model information. With jMDA you can not only access the structural details of a single model element. It is even possible to navigate the relations to other model elements. Now that we can access detailed information about a model we can proceed to the next major question:

jMDA Java Code Generators

How does jMDA support Java code generation? Let's assume we want to generate a simple Java Bean style class for the Person model element. We start by generating a Java class with a default generator:
        ClassGenerator classGenerator = new DefaultClassGenerator();

        out.println(classGenerator.generate().toString());
The default class generator produces a primitive but valid class declaration out of the box:
        class DEFAULT_TYPE_NAME
        {
        }
We add public visibility and a reasonable type name for the generated class by providing some configuration of the default class generator:
        ClassGenerator classGenerator = new DefaultClassGenerator();
       
        classGenerator.setVisibility(VisibilityModifier.PUBLIC);
        classGenerator.setClassName(typeElement.getSimpleName().toString());

        out.println(classGenerator.generate().toString());
Now the resulting output is:
        public class Person
        {
        }
The next task is to add field declarations to the generated class. We could easily solve this by modifying the loop shown above. However the output of the loop contains qualified type names everywhere. To overcome this unnecessary verbosity we use another generator namely DefaultInstanceFieldDeclarationGenerator. It can be configured in a similar style as the class generator.
        ClassGenerator classGenerator = new DefaultClassGenerator();
       
        classGenerator.setVisibility(VisibilityModifier.PUBLIC);
        classGenerator.setClassName(typeElement.getSimpleName().toString());

        for (VariableElement field : getFields(typeElement))
        {
          FieldDeclarationGenerator fieldGenerator =
              new DefaultInstanceFieldDeclarationGenerator();
   
          fieldGenerator.setVisibility(VisibilityModifier.PRIVATE);
          fieldGenerator.setTypeFrom(field);
          fieldGenerator.setName(field.getSimpleName().toString());

          fieldGenerator.setLineIndenter(LineIndenter.TAB_SINGLE);

          classGenerator.addFieldGenerator(fieldGenerator);
        }

        out.println(classGenerator.generate().toString());
Notice how generators for each field are being composed (added) into the surrounding class generator. This is a common pattern for many jMDA generators: Compound generators control the generation of contained generators. With some added pretty printing (see LineIndenter) the generated output now looks like this:
        public class Person
        {
          private String firstName;
          private String lastName;
          private List<Contact> contacts;
        }
The generator code shown so far is really simple and straight forward and it is a typical example for the convenient usage of jMDA generators. The following code fragment demonstrates how easy it is to extend the example so that the class generator also produces Java Bean style accessors:
        // getter
        MethodDeclarationGenerator methodGenerator =
            new DefaultInstanceMethodDeclarationGenerator();
   
        methodGenerator.setVisibility(VisibilityModifier.PUBLIC);
        methodGenerator.setTypeFrom(field);
        methodGenerator.setName(
            "get" + StringUtil.firstLetterToUpperCase(simpleFieldName));
        methodGenerator.setMethodBody("return " + simpleFieldName + ";");

        methodGenerator.setLineIndenter(LineIndenter.TAB_SINGLE);
        classGenerator.addMethodGenerator(methodGenerator);
   
        // setter
        methodGenerator = new DefaultInstanceMethodDeclarationGenerator();
   
        methodGenerator.setVisibility(VisibilityModifier.PUBLIC);
        methodGenerator.setName(
            "set" + StringUtil.firstLetterToUpperCase(simpleFieldName));
        methodGenerator.addParameterFrom(field, simpleFieldName);
        methodGenerator.setMethodBody(
            "this." + simpleFieldName + " = " + simpleFieldName + ";");

        methodGenerator.setLineIndenter(LineIndenter.TAB_SINGLE);

        classGenerator.addMethodGenerator(methodGenerator);
We finish this tutorial by presenting the complete Java bean output of our generator:
        package de.jmda.sample.tutorial.generated;

        import java.util.List;

        public class Person
        {
          private String firstName;
          private String lastName;
          private List<Contact> contacts;

          public String getFirstName()
          {
            return firstName;
          }

          public void setFirstName(String firstName)
          {
            this.firstName = firstName;
          }

          public String getLastName()
          {
            return lastName;
          }

          public void setLastName(String lastName)
          {
            this.lastName = lastName;
          }

          public List<Contact> getContacts()
          {
            return contacts;
          }

          public void setContacts(List<Contact> contacts)
          {
            this.contacts = contacts;
          }
        }
I hope this short trip through jMDA modelling and code generation has shown in a convincing way how easy it is to create meaningful models, access model information and generate valuable code with jMDA. It should be obvious that the demonstrated techniques can be easily adopted to create really interesting models and generate custom code for various purposes based on them. Model and code of the example discussed in this chapter are available for download here.

No comments:

Post a Comment