4.1. Pojo Classes

About the author

Sandra L Sandra is the best. Toevoegen: iets over Sandra en over wat maakt dat ze plezier heeft in haar werk.

In this first blog, we will start with the creation of Java POJO classes which represent data from a database. We will create a so-called code instruction, which in combination with a data model will form the basis of generating code. We will also explain how functions can be used to apply a consistent naming of classes, fields, and methods for example. Finally, we will be adding methods to our classes.

4.1.1. Data model

The data model which we will use in this article looks like this:

../_images/M13_DataModel.png

Fig. 4.1 Data model

Listing 4.1 Model object
1
2
<!--I need to be here.
    But I am not yet -->

Let’s start with creating a very simple class for the entity Book:

Listing 4.2 class Book
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package org.blog1.pojo;

public class Book {

private String name;
private String description;
private Author author;

// Getters and setters

}

There are quite some similarities between the data model and the entity for Book. We take advantage of these similarities to create ‘code instructions’, which will contain the blueprint for, in our case, Java classes. As all POJO classes have a similar structure, it is very convenient to use these code instructions to create more classes.

4.1.2. Code instruction

For our POJO classes we can define the following code instruction using XML:

Listing 4.3 Code instruction
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<java_package
    xmlns="https://metafactory.io/xsd/v1/java-codeinstruction"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://metafactory.io/xsd/v1/java-codeinstruction
                              https://metafactory.io/xsd/v1/java-codeinstruction.xsd"
    name="org.blog1.pojo"
    package="domain_model">

    <class name="${object.name}"
           visibility="public"
           foreach="object">

        <field name="${attribute.name}"
               visibility="private"
               foreach="attribute">
            <datatype>${attribute.type}</datatype>
        </field>

        <field name="${reference.name}"
               visibility="private"
               foreach="reference">
            <datatype>${reference.type}</datatype>
        </field>
    </class>
</java_package>

This is a good example of using Metaprogramming to describe POJO’s. Let’s first have a look at how a class is defined (from line 9 on):

name=”${object.name}”

This property describes the access modifier, in this case, of the class.

visibility=”public”

This property describes the access modifier, in this case, of the class.

foreach=”object”

The property defines in this case that we want to generate a class for every object defined in our data model.

This really emphasizes the advantages of a tool like MetaFactory’s Code Composer. Instead of having to write similar POJO classes for every entity by hand, you can now generate classes like these for all objects in the data model. You only need to define the desired objects.

Next we have two different types of fields defined in our code instruction: one based on the attributes and one based on the references in our data model. Our model object Book (see Model object) for example contains two attributes: name and description. For each of these attributes we want to generate a field with a private access modifier. The name of the field will now be based on the name of the attribute in our data model (i.e. description). The child element datatype in our code instruction describes the type of the Java field, based on the type of the attribute in the data model (i.e. String). The second type of field is based on the references and follows the same logic as for the attributes.

Now we can use this code instruction to generate, with one mouse click, both the Book and Author classes by means of the Code Composer.

The Author class should look like this:

Listing 4.4 class Author
1
2
3
4
5
6
7
8
9
package org.blog1.pojo;

public class Author {

private String firstName;
private String lastName;
private Book book;

}

The fields firstName and lastName are based on the 2 attributes of the Author model object and the field book is created based on the reference of Author to Book in the Author object.

4.1.3. Functions

Naming is an important aspect of Metaprogramming. In Listing 4.3 (line 9) we used the name of the model object for naming our Java POJO class. In this case that might be sufficient, but there are plenty of other situations where you might want to apply more advanced naming conventions. In MetaFactory we therefore have something called “code instruction functions”. These functions can be used in code instructions to describe all kinds of properties. Let’s have a look again at the names of the POJO classes and try to replace those with a function:

Listing 4.5 Function to create a class name
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(...)

<function name="createPojoClassName">
    <!-- Function must be called with 1 argument: 1. Name of model object -->

    <definition>${arg1}</definition>

</function>

(...)

Applying this function to our code instruction, it will look like this:

Listing 4.6 Code instruction
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<java_package
    xmlns="https://metafactory.io/xsd/v1/java-codeinstruction"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://metafactory.io/xsd/v1/java-codeinstruction
                              https://metafactory.io/xsd/v1/java-codeinstruction.xsd"
    name="org.blog1.pojo"
    package="domain_model">

    <class name=="${createPojoClassName(${object.name})}"
           visibility="public"
           foreach="object">

        <field name="${attribute.name}"
               visibility="private"
               foreach="attribute">
            <datatype>${attribute.type}</datatype>
        </field>

        <field name="${reference.name}"
               visibility="private"
               foreach="reference">
            <datatype>${createPojoClassName(${reference.type})}
            </datatype>
        </field>
    </class>
</java_package>

We have first used this function to determine the class name and currently it will have the same result as in Listing 4.1. One major advantage of this solution is that if we want to change the names of our POJO classes, for example to BookEntity and AuthorEntity, we only have to adjust this one function and give the Code Composer a kick again.

All classes created based on this code instruction will be updated with this new naming convention. Even better, also the type of our reference fields will automatically be adjusted. This is just a very simple example, but hopefully you recognize how convenient these functions are. They will result in consistent naming and are less error prone than changing all names manually.

4.1.4. Methods

Our Java POJOs can use some getter and setter methods for access to the private fields. You need only a small adjustment to the code instruction to generate getters and setters:

Listing 4.7 Introducing Getters and Setters
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<java_package
    xmlns="https://metafactory.io/xsd/v1/java-codeinstruction"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="https://metafactory.io/xsd/v1/java-codeinstruction
                              https://metafactory.io/xsd/v1/java-codeinstruction.xsd"
    name="org.blog1.pojo"
    package="domain_model">

    <class name=="${createPojoClassName(${object.name})}"
           visibility="public"
           foreach="object">

        <field name="${attribute.name}"
               visibility="private"
               access="RW"
               foreach="attribute">
            <datatype>${attribute.type}</datatype>
        </field>

        <field name="${reference.name}"
               visibility="private"
               access="RW"
               foreach="reference">
            <datatype>${createPojoClassName(${reference.type})}
            </datatype>
        </field>
    </class>
</java_package>

By adding the access property with value r (read), w (write), or rw, we can indicate whether we want getter and/or setter methods to be generated. To really complete the POJO classes we can also add implementations for equals and hashCode methods.

Let’s further expand the code instruction and add these methods:

Listing 4.8 equals and hashCode methods
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<method name=”equals”
        visibility=”public”>
    <annotation>@Override</annotation>

    <parameter name=”return”>
        <apicommentline>Return true if object is the same as the argument object,
                        otherwise return false</apicommentline>
        <datatype>boolean</datatype>
    </parameter>

    <parameter name=”other”>
        <apicommentline>The reference object with which to compare</apicommentline>
        <datatype>Object</datatype>
    </parameter>

    <body>${fmsnippet.java.pojo.method.equals}</body>
</method>

<method name=”hashCode”
        visibility=”public”>
    <annotation>@Override</annotation>

    <parameter name=”return”>
        <apicommentline>A hash code value for this object</apicommentline>
        <datatype>integer</datatype>
    </parameter>

    <body>${fmsnippet.java.pojo.method.hash_code}</body>
</method>

Lines 16 and 28 tell the Code Composer to call Freemarker snippets for the generation of the methods’ body.

The Code Composer will then generate these 2 classes:

Listing 4.9 class Book
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
package org.blog1.pojo;

import java.util.Objects;

public class Book {

        private String name;

        private String description;

        private Author author;

        /**
        * equals – Fields used as business key: 1) name 2) description.
        *
        * @param other The reference object with which to compare
        * @return boolean Return true if object is the same as the argument
          object, otherwise return false
        */
        @Override
        Public Boolean equals(final Object other) {
                if (this == other) {
                        return true;
                }

                if (!(other instanceof Book)) {
                        return false;
                }

                final Book otherBook = (Book) other;

                boolean result;
                result = Objects.equals(getName(), otherBook.getName());
                result = result && Objects.equals(getDescription(),
                        otherBook.getDescription());

                return result;
        }

        /**
        * hashCode – Fields used as business key: 1) name 2) description.
        *
        * @return integer A hash code value for this object
        */
        @Override
        Public int hashCode() {
                Return Objects.hash(getName(), getDescription());
        }

        /**
        * Getter for property name.
        *
        * @return Value of property name
        */
        public String getName() {
                return this.name;
        }

        /**
        * Setter for property name.
        *
        * @param name New value of property name
        */
        public void setName(final String name) {
                this.name = name;
        }

        /**
        * Getter for property description.
        *
        * @return Value of property description
        */
        public String getDescription() {
                return this.description;
        }

        /**
        * Setter for property description.
        *
        * @param name New value of property description
        */
        public void setDescription(final String description) {
                this.description = description;
        }

        /**
        * Getter for property author.
        *
        * @return Value of property author
        */
        public Author getAuthor() {
                return this.author;
        }

        /**
        * Setter for property author.
        *
        * @param author New value of property author
        */
        public void setAuthor(final Author author) {
                this.author = author;
        }
}
Listing 4.10 class Author
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
package org.blog1.pojo;

import java.util.Objects;

public class Author {

        private String firstName;

        private String lastName;

        private Book book;

        /**
        * equals – Fields used as business key: 1) firstName 2) lastName.
        *
        * @param other The reference object with which to compare
        * @return boolean Return true if object is the same as the argument
          object, otherwise return false
        */
        @Override
        Public Boolean equals(final Object other) {
                if (this == other) {
                        return true;
                }

                if (!(other instanceof Author)) {
                        return false;
                }

                final Author otherAuthor = (Author) other;

                boolean result;
                result = Objects.equals(getFirstName(), otherAuthor.getFirstName());
                result = result && Objects.equals(getLastName(), otherAuthor.getLastName());

                return result;
        }

        /**
        * hashCode – Fields used as business key: 1) firstName 2) lastName.
        *
        * @return integer A hash code value for this object
        */
        @Override
        Public int hashCode() {
                Return Objects.hash(getFirstName(), getLastName());
        }

        /**
        * Getter for property firstName.
        *
        * @return Value of property firstName
        */
        public String getFirstName() {
                return this.firstName;
        }

        /**
        * Setter for property firstName.
        *
        * @param firstName New value of property firstName
        */
        public void setFirstName(final String firstname) {
                this.firstName = firstName;
        }

        /**
        * Getter for property lastName.
        *
        * @return Value of property lastName
        */
        public String getLastName() {
                return this.lastName;
        }

        /**
        * Setter for property lastName.
        *
        * @param lastName New value of property lastName
        */
        public void setLastName(final String lastName) {
                this.lastName = lastName;
        }

        /**
        * Getter for property book.
        *
        * @return Value of property book
        */
        public Book getBook() {
                return this.book;
        }

        /**
        * Setter for property book.
        *
        * @param book New value of property book
        */
        public void setBook(final Book book) {
                this.book = book;
        }

}

In the next blog of this series, we’ll explain how you can use the Freemarker template engine in various ways.