3.3. QuickStart

This guide will help you to get started with a demonstration project in 15 minutes.

Now let’s create our first example.

3.3.1. Create your first example

Creating an application with a large amount of entities quickly results in tedious work. Entity classes contain fields, zero or more overloaded constructors and a set of getters and setters. All these entities need separate controllers, repositories and so on. Now to automate this process we will start by creating entity interfaces as well as the implementation classes.

The following example shows how to produce java pojo classes and interfaces by a code instruction and a model.

For a very first simple impression of how the Code Composer works, you may however want to read the T01 Hello World example first.

First we define a model:

Listing 3.4 model.xml
<?xml version="1.0" encoding="UTF-8"?>
<model xmlns="https://metafactory.io/xsd/v1/model"
  <package name="domain_model">
        <object name="Person">
          <field name="firstName" type="String" length="50" notnull="true"></field>
          <field name="lastName" type="String" length="50" notnull="true"></field>
          <reference name="homeAddress" type="Address" notnull="true" multiplicity="1..1"></reference>
          <reference name="workAddress" type="Address" notnull="false" multiplicity="0..1"></reference>
          <reference name="phone" type="Phone" notnull="false" multiplicity="0..n"></reference>
        <object name="Address">
          <field name="streetName" type="String" length="100" notnull="true"></field>
          <field name="zipCode" type="String" length="10" notnull="false"></field>
          <field name="city" type="String" length="50" notnull="true"></field>
          <field name="country" type="String" length="50" notnull="false"></field>
        <object name="Phone">
          <field name="number" type="String" length="30" notnull="true"></field>
          <field name="description" type="String" length="100" notnull="true"></field>
          <reference name="person" type="Person" notnull="true" multiplicity="1..1"></reference>

Various attribute values such as ‘type’, ‘length’ and ‘notnull’ are included in the above snippet. However you should know that these values by itself do nothing unless they are explicitly dealt with by the code instruction. The Code Composer is designed not to use any default or hidden implementations, thereby providing transparency and control to the programmer.

Note that the <reference> element contains an attribute called ‘multiplicity’. This attribute tells the code instruction how many references of the given type the object can contain. For example ‘0..n’ means that the object may contain either zero or any other number of this reference type. The code instruction can for example use this attribute as a condition for creating the output code.

Now let’s look at the code instruction that creates interfaces and implementations for this model data.

Listing 3.5 codeinstruction.xml
 1<?xml version="1.0" encoding="UTF-8"?>
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns="https://metafactory.io/xsd/v1/codeinstruction"
 5        xsi:schemaLocation="https://metafactory.io/xsd/v1/codeinstruction
 6                                https://metafactory.io/xsd/v1/codeinstruction.xsd
 7                                https://metafactory.io/xsd/v1/java-codeinstruction
 8                                https://metafactory.io/xsd/v1/java-codeinstruction.xsd
 9                                https://metafactory.io/xsd/v1/typescript-codeinstruction
10                                https://metafactory.io/xsd/v1/typescript-codeinstruction.xsd"
11        xmlns:typescript="https://metafactory.io/xsd/v1/typescript-codeinstruction"
12        xmlns:java="https://metafactory.io/xsd/v1/java-codeinstruction">
14        <properties>
15                <java.output.directory>java</java.output.directory>
16        </properties>
17        <java_package name="com.firstbase.ba.example6a.pojo" package="domain_model"
18                      path="${pattern.property.java.output.directory}">
19                <interface name="I${object.name}" foreach="object">
20                        <field name="id" access="rw">
21                                <datatype>long</datatype>
22                                <apicommentline>primary key</apicommentline>
23                        </field>
24                        <field name="${attribute.name}" access="rw" foreach="attribute">
25                                <datatype>${attribute.type}</datatype>
26                                <apicommentline>${attribute.name} property</apicommentline>
27                        </field>
28                        <field name="${reference.name}" foreach="reference" access="rw"
29                               condition="${reference.multiplicity}=0..1 OR ${reference.multiplicity}=1..1">
30                                <datatype>I${reference.type}</datatype>
31                                <apicommentline>Reference to I${reference.type} object</apicommentline>
32                        </field>
33                        <field name="${reference.name}Set" foreach="reference" access="rw"
34                               condition="${reference.multiplicity}=0..n OR ${reference.multiplicity}=1..n">
35                                <import>java.util.Set</import>
36                                <datatype><![CDATA[Set<I${reference.type}>]]>
37                                </datatype>
38                                <apicommentline>Set of I${reference.type} objects</apicommentline>
39                        </field>
40                        <method name="add${firstUpper(${reference.name})}" foreach="reference"
41                                condition="${reference.multiplicity}=0..n OR ${reference.multiplicity}=1..n">
42                                <apicommentline>Utility method to add a object of type I${reference.type} to ${reference.name}Set</apicommentline>
43                                <parameter name="${firstLower(${reference.name})}">
44                                        <datatype> I${reference.type}</datatype>
45                                        <apicommentline> object to add to ${reference.name}Set</apicommentline>
46                                </parameter>
47                        </method>
48                        <method name="delete${firstUpper(${reference.name})}" foreach="reference"
49                                condition="${reference.multiplicity}=0..n OR ${reference.multiplicity}=1..n">
50                                <parameter name="${firstLower(${reference.name})}">
51                                        <datatype> I${reference.type}</datatype>
52                                </parameter>
53                        </method>
54                </interface>
55                <class name="${object.name}Impl" foreach="object">
56                        <implements>I${object.name}</implements>
57                        <field name="id" access="rw">
58                                <datatype>long</datatype>
59                                <apicommentline>primary key</apicommentline>
60                        </field>
61                        <field name="${attribute.name}" foreach="attribute" access="rw">
62                                <datatype>${attribute.type}</datatype>
63                        </field>
64                        <field name="${reference.name}" foreach="reference" access="rw"
65                               condition="${reference.multiplicity}=0..1 OR ${reference.multiplicity}=1..1">
66                                <datatype> I${reference.type}</datatype>
67                        </field>
68                        <field name="${reference.name}Set" foreach="reference" access="rw"
69                               condition="${reference.multiplicity}=0..n OR ${reference.multiplicity}=1..n">
70                                <import>java.util.Set</import>
71                                <import>java.util.HashSet</import>
72                                <datatype><![CDATA[Set<I${reference.type}>]]></datatype>
73                                <body><![CDATA[new HashSet<I${reference.type}>()]]></body>
74                        </field>
75                        <method name="add${firstUpper(${reference.name})}" foreach="reference"
76                                condition="${reference.multiplicity}=0..n OR ${reference.multiplicity}=1..n">
77                                <parameter name="${firstLower(${reference.name})}">
78                                        <datatype> I${reference.type}</datatype>
79                                </parameter>
80                                <body> ${firstLower(${reference.name})}.${getSetterName(${reference.type},${object.name})}(this);
81                                       ${reference.name}Set.add(${firstLower(${reference.name})});</body>
82                        </method>
83                        <method name="delete${firstUpper(${reference.name})}" foreach="reference"
84                                condition="${reference.multiplicity}=0..n OR ${reference.multiplicity}=1..n">
85                                <parameter name="${firstLower(${reference.name})}">
86                                        <datatype> I${reference.type}</datatype>
87                                </parameter>
88                                <body> ${firstLower(${reference.name})}.${getSetterName(${reference.type},${object.name})}(null);
89                                       ${reference.name}Set.remove(${firstLower(${reference.name})});</body>
90                        </method>
91                </class>
92        </java_package>

A few explanations regarding this code instruction:

  • The <java_package> element tells the name of the java package that the produced class will be in.

    This element also has a ‘package’ attribute which refers to the group of objects that is defined in model.xml.

  • Model objects are dynamically accessed using MetaFactory’s expression language.

    Expressions such as ${object.name} are known at the time of execution because a code instruction is always executed within the context of the part of the domain model that the Code Composer is iterating over, such as a package, object or property. Read more about expressions here.

  • <![CDATA ]> tags (see line 36) are required sometimes to escape the XML reserved symbols, such as ‘<‘

  • The attribute ‘access=”rw” (of the <field> element) tells the Code Composer to generate getters and setters for this field.

  • The <method> element creates Java methods.

Now that you have updated the code of our newly created project it is time to let the Code Composer run and generate all the code (menu Transform -> Run). You can find the generated code at <java.output.directory> see Listing 3.5 line 15.

Light S Add some new data entities of your own to the model and see how that works out in the output.

Good job, you’ve just created your first code with the Code Composer.

3.3.2. Evaluation

While XML code instructions help you enforce structure and consistency both in your code instructions and in the resulting Java classes, using this technique only does come with limitations in flexibility.

Snippets are the power tool in the Code Composer that overcome these limitations and provide you with the templating freedom of using Freemarker or Velocity. You can either evaluate a snippet into true or false as a condition to operate your xml code instruction on or write complete method bodies and even classes with it.

Do you value the structured approach and out of the box functionality of xml more, or the templating freedom of snippets? Mind that a very basic XML code instruction is required as a container for your snippet, but other than that you are free in how you use snippets in your code instructions.

Glasses S More information about the possibilities of snippets can be found at Code Instructions Snippets.

Glasses S For more about calling snippets from your code instruction check out SDA example using snippets.