Tutorial: Spring Roo and JPA: Prof. Dr. Joachim Hering Ulm University of Applied Sciences Germany

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

Tutorial:

Spring Roo and JPA


Prof. Dr. Joachim Hering
Ulm University of Applied Sciences
Germany

Page 1 of 16
In this tutorial you will get some hands-on experience with the Spring Tool Suite (STS) and
Spring Roo to rapidly develop a database-based (Web-)Application by following a step-by-
step guide.
Note that in this tutorial a Linux-based operating system is assumed. However, on other
platforms (e.g., Windows), this tutorial should work as well - different file paths may have
to be used, though (e.g., "C:\" instead of "home").

Spring Tool Suite and Spring Roo installation


As a pre-requisite, the development environment required for the following tutorial needs
to be installed on your PC.
A brief description about how how this is done is given inthe following.

Pre-Requisite: Java SE
Please ensure that the JDK 1.7 has been installed on your machine. The current version of
Spring Roo requires JDK 1.6 or JDK 1.7 to be installed.

Installing the Spring Tool Suite


• Download the corresponding archive file from "http://spring.io/tools/sts/all" and
unpack it to your home directory (or "C:\" on Windows)
• In your home directory, create a folder "springWS".
(On Windows, you may create the following folder: "C:\springWS")

Installing Spring Roo


• Start the Spring Tool Suite (STS) by executing "~/sts-bundle/sts-3.6.3.SR1/STS".
(Note that "~" means your home directory)
• As "Workspace", enter the folder "springWS" you have just created, check the box
"Use this as the default and do not ask again" and click on "OK"
• Open STS dashboard via "Help->Dashboard"
• Click on the Extensions tab at the bottom of the Dashboard and search for "Spring
Roo" (via the "Find:" text box)
• From the search results list, select the following
• Spring Roo (current production release)
• Spring IDE - Roo Extension
• Click on the "Install" button at the bottom right corner of the Dashboard and follow
the instructions to install those two extensions
• Restart the Spring Tool Suite for the changes to take effect
• You may then close the Dashboard

Page 2 of 16
Domain Object Model
In this tutorial, you will develop the Web Application "MyJobOffers" allowing to maintain
and view job offers. The corresponding Domain Object Model is shown in the following
figure.

Create the Roo Project in STS


Start the Spring Tool Suite (STS)

Close the "Welcome" page, "Dashboard" page and "Tool tips", if displayed.

Within STS, we will mainly work with the Roo Shell. If it is not shown, you may open it via
"Window->Show View->Other...", expand the folder "Spring", and select "Roo Shell". After
clicking "OK", you should see the Roo Shell in a tab at the bottom of STS. If you see the
Roo Shell at a different place, you may drag the corresponding tab to the bottom of STS.

Page 3 of 16
A new Roo project may now be created by clicking on the "Create new Roo Project" button
( ) on the right upper side of the Roo Shell.

In the "New Roo Project" dialog, enter the following data:


• Project name: MyJobOffers
• Top level package name: com.springroo.myjoboffers
Leave the rest unchanged and click "Next" and then "Finish".

Wait until a Roo Shell prompt is shown in the Roo Shell.

Observe in the "Package Explorer" of STS, that a new project "MyJobOffers" has been
created.

In the following, we will mainly be using the Roo Shell to enter Roo commands.
A few notes about the Roo Shell in STS (please feel free to try them out):
• Entering "help" provides you with some further information on the Roo Shell
• Entering "help RooCommand" will provide you with information on a specific Roo
command. E. g., "help jpa setup"
• Entering "hint" will provide you with a generic step-by-step guidance
NOTE: If time left after the tutorial, you may experiment with that, in this tutorial,
however, you will already be provided with a specific step-by-step guidance.
• While entering Roo commands, you may at any time press CTRL+SPACE. Roo will
then provide you with a list of possible Roo commands/options.
E.g., pressing CTRL+SPACE in the empty Roo Shell will present you with a list of
all possible Roo commands to choose from.

Some notes on the Java Persistence API (JPA)


In Roo, JPA will be used to access the underlying relational database.
JPA was created to provide a standard API for object-oriented database mapping. A
number of object-oriented database mapping frameworks, like for instance Hibernate,
provide an implementation of the JPA.
This way, developers write their persistence code against a single API without having to
bother with the underlying implementation.
In brief, in JPA, Domain Objects are represented as JPA entities which are mapped to
corresponding database tables (via persistence annotations). Track of changes to the
underlying relational data is kept by a persistence context which may be accessed via the
EntityManager API.
In this tutorial, JPA 2.0 is used. More details on JPA can be found at
https://jcp.org/en/jsr/detail?id=317.

Page 4 of 16
Setting up the Java Persistence API (JPA) in Roo
In Roo, JPA is set up by entering the following Roo command:
roo1> jpa setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE

Note that for this tutorial, we are using the HYPERSONIC IN MEMORY database which
relieves us from the need to have a separate database engine installed.
In real world (Web-)Applications, another database engine should be used. The "jpa setup"
command does of course allow to set up jpa for other database engines like for instance
Oracle, MySQL, MSSQL, ...
Since JPA is a standard API, the "jpa setup" command may be re-run at any time with
different options (e.g., for the database or for the JPA provider) without affecting any of the
existing Java code.

After entering this command, Roo automatically modifies your project such that JPA may
be used in the following.

Please feel free at any time of the tutorial to explore the current structure of your project
via the "Package Explorer".

Creating the Domain Object Model using the Roo Shell


Now, we will create the Domain Object Model (i.e., the corresponding JPA entities) shown
above via the Roo Shell.
The Domain Object Model basically consists of two parts:
• The Domain Objects and their fields
• The relationships between those Domain Objects
Note that in our Domain Object Model we have both one-to-many and many-to-many
relationships. Although Roo also supports one-to-one relationships, this will not be shown
here.

Creating the Domain Objects and fields


Roo provides two commands that allow us to create the Domain Objects and their fields:
• entity jpa: Creating Domain Objects
• field: Creating fields
We will now create each Domain Object with its corresponding fields by entering the
following Roo commands.
Note: As soon as you get the idea, please try to enter the commands yourself (without
looking at the solution) based on the Domain Object Model shown above.
Remember: Using CTRL-SPACE will help you entering the Roo commands.

1 Please do not enter "roo>". This is only to highlight, that a command is to be entered into the Roo Shell.

Page 5 of 16
Also note that the following fields (shown in the Domain Object Model) will be created later,
i.e., when creating relationships between those Domain Objects:
• city
• cities
• companies
• jobOffers
• company
• jobCategories

City:
roo> entity jpa --class ~.domain.City --testAutomatically
roo> field string --fieldName name --sizeMax 20 --notNull

In the "Package Explorer", have a look at "City", the just generated JPA Entity.
This class looks quite simple, it only contains the field we specified (i.e., "name").
However, note that "City" has a number of Roo annotations (e.g., @RooJavaBean,
@RooToString, @RooJpaActiveRecord). Those annotations indicate that Roo has
automatically generated Java code for us to help us speed up development time.
Spring Roo puts all generated code in separate AspectJ (*.aj) files that will be
automatically merged into the corresponding java-Files at build time - all transparent to the
developer.
However, those AspectJ files are very similar to Java code and may be viewed by the
developer. This way, developers can concentrate on the key details (e.g., the Domain
Object fields), while all the boilerplate code is put in separate files.

We will now have a brief look at the AspectJ files generated for our Domain Object "City".
By default, AspectJ files are not visible. Hence, we first have to make them visible as
follows:
From the Package Explorer menu ( ) on the right upper side, choose "Filters". Deselect
the option "Hide generated Spring Roo ITDs" and click "OK".

By convention, all AspectJ files belonging to "City" are named "City_*.aj". Have a look at
those files and the functionality they add to our "City" class.
Of particular interest is "City_Roo_Jpa_ActiveRecord.aj", which enables "City" to not only
contain its data but also to load and persist its data from/to the underlying relational
database.

Now create the other Domain Objects accordingly (maybe you can already do that
yourself):

Page 6 of 16
Country:
roo> entity jpa --class ~.domain.Country --testAutomatically
roo> field string --fieldName name --sizeMax 20 --notNull

Company:
roo> entity jpa --class ~.domain.Company --testAutomatically
roo> field string --fieldName name --sizeMax 20 --notNull
roo> field string --fieldName streetName --sizeMax 20 --notNull
roo> field number --fieldName streetNo --type java.lang.Integer --min 0 --max 9999 --notNull
roo> field string --fieldName postCode --sizeMax 10 --notNull

JobCategory:
roo> entity jpa --class ~.domain.JobCategory --testAutomatically
roo> field string --fieldName name --sizeMax 20 --notNull

JobOffer:
roo> entity jpa --class ~.domain.JobOffer --testAutomatically
roo> field string --fieldName subject --sizeMax 20 --notNull
roo> field string --fieldName contactEmail --sizeMax 20 --notNull
roo> field string --fieldName description --sizeMax 200 --notNull

Page 7 of 16
Creating the relationships between Domain Objects
Now that the Domain objects are created, we use Spring Roo to define their relationships.
We will start defining the one-to-many relationships and finally the many-to-many
relationship between "JobOffer" and "JobCategory".

We will generally create bidirectional relationships where navigation is possible from both
sides (e.g., from companies to their city and from cities to companies). Hence, creating a
relationship between two Domain Objects is a two-step-process where each direction of
the relationship is created separately.

Note: Again, as soon as you get the idea, please try to enter the commands yourself
(without looking at the solution) based on the Domain Object Model shown above.
Remember: Using CTRL-SPACE will help you entering the Roo commands.

City-Company:
Each city may have a number of company headquarters (one-to-many).
roo> focus --class ~.domain.City
roo> field set --fieldName companies --type ~.domain.Company --cardinality
ONE_TO_MANY --mappedBy city

Note that Spring Roo has added the following field to the "City" class:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "city")
private Set<Company> companies = new HashSet<Company>();

Via the "@OneToMany" annotation, JPA knows about the relationship between "City" and
"Company" and will be able to generate the correct SQL when queries are issued. This will
be done transparent to the developer - the developer only needs to know about the
Domain Object Model.

The "mappedBy" option refers to the name of the field in "Company" that represents the
related "City". This instructs JPA to manage the relatioship at the "many" end 2, which we
will define in the following:

2 One-to-many relationships are typically managed at the "many" end. This makes sense, since the foreign
key (here: Company.city) lives in the "many" side.

Page 8 of 16
Every company has its headquarter in a particular city (many-to-one).

roo> focus --class ~.domain.Company


roo> field reference --fieldName city --type ~.domain.City --notNull --cardinality
MANY_TO_ONE

Note that Spring Roo has added the following field to the "Company" class:
@NotNull
@ManyToOne
private City city;

This is the field that is referred to by the "mappedBy" option when the one-to-many
relationship between "City" and "Company" was defined.

The bidirectional one-to-many relationship between "City" and "Company" is now complete
where the following rules have been established:
• Cities contain sets of Companies in a collection named companies
• Companies reference their City in the reference variable "city"
• Removing/saving a City will also remove/save its assigned Companies (cascading)
• If JPA is used to load a City, JPA will automatically fetch assigned Companies when
the "getCompanies" method is called (defined in City_Roo_JavaBean.aj)

Page 9 of 16
Country-City:
Each country has a number of cities (one-to-many).

roo> focus --class ~.domain.Country


roo> field set --fieldName cities --type ~.domain.City --cardinality ONE_TO_MANY
--mappedBy country

Every city is located in a particular country (many-to-one).

roo> focus --class ~.domain.City


roo> field reference --fieldName country --type ~.domain.Country --notNull --cardinality
MANY_TO_ONE

Company-JobOffer:
Each company may have a number of job offers (one-to-many).

roo> focus --class ~.domain.Company


roo> field set --fieldName jobOffers --type ~.domain.JobOffer --cardinality
ONE_TO_MANY --mappedBy company

Every job offer has been published by a particular company (many-to-one).

roo> focus --class ~.domain.JobOffer


roo> field reference --fieldName company --type ~.domain.Company --notNull
--cardinality MANY_TO_ONE

Page 10 of 16
JobOffer-JobCategory:

A many-to-many relationship may be defined in two ways using JPA:


1. Using three Domain Objects where an intersecting object is defined to associate
"JobOffer" entities to "JobCategory" entities using two one-to-many relationships.
2. Using two Domain Objects and a many-to-many relationship.

Note that option 1 allows us to specify fields for the intersecting object (i.e., fields that
belong to the relationship between "JobOffer" and "JobCategory" like for instance
"categoryAssignedByUser".
However, in this tutorial, we will be using the simpler option 2:

Each job offer may belong to one or more job categories (many-to-many).

roo> focus --class ~.domain.JobOffer


roo> field set --fieldName jobCategories --type ~.domain.JobCategory --cardinality
MANY_TO_MANY

Each job category may be assigned to a number of job offers (many-to-many).

roo> focus --class ~.domain.JobCategory


roo> field set --fieldName jobOffers --type ~.domain.JobOffer --cardinality
MANY_TO_MANY --mappedBy jobCategories

Note that the "mappedBy" option defines the name of the set within the "JobOffer" and
indicates that "JobCategory" is not in charge of persisting relationships to "JobOffers".
In a bidirectional many-to-many relationship, we have to define one side as the primary,
i.e., active side, and the other side as the inverse side (via the mappedBy option). When
using JPA, we need to know, which is the active side, since only updates on this side will
actually trigger JPA persistence for relationships.
There can only be one active side of the many-to-many relationship to be watched by JPA,
since otherwise the same rows may be inserted twice in the underlying relational
database.
For most bidirectional one-to-many relationships, the appropriate active side is the "many"
side, as the foreign key lives in the child (i.e., the "many" side).
For many-to-many relationships, the choice is arbitrary and may be decided on a case-by-
case basis. In our case it seems more natural for "JobOffer" to be the active side.

Page 11 of 16
The underlying relational data model
We have now finished creating our Domain Object Model in Spring Roo.
Before testing some of the persistence functionality that Spring Roo has generated for us,
let us take a brief look at the automatically generated corresponding underlying relational
data model.

Page 12 of 16
Note the following about the relational data model:
• Entities are related to each other traditionally using primary and foreign keys.
• The many-to-many relationship between "JobOffer" and "JobCategory" results in
three tables where an intermediate table (job_offer_job_categories) is used to
implement the many-to-many relationship between job offers and job categories.

Testing the persistence functionality generated for us


While creating the Domain Object Model, Spring Roo has also created a number of JUnit
tests and helper classes for us. Let us look at a concrete example. To create the "City"
entity, we used the following Roo command: "entity jpa --class ~.domain.City
--testAutomatically".
Just by specifying the "testAutomatically" option, Roo automatically generated a number of
JUnit tests (CityIntegrationTest.java and related AspectJ files) and a helper class to , e.g.,
generate "City" instances (CityDataOnDemand.java and related AspectJ files) for us.

Have a look at "CityIntegrationTest_Roo_IntegrationTest.aj", where a number of JUnit tests


are defined to exercise "City" persistence functionality.
You may then run those tests by right-clicking on "CityIntegrationTest.java" and selecting
"Run as->JUnit Test". All tests should run successfully.

Now you may specify your own simple JUnit test by adding the following test method to
"CityIntegrationTest.java".

@Test
public void testWriteReadCity() {
CityDataOnDemand cityDod = new CityDataOnDemand();
City city = cityDod.getNewTransientCity(0);

city.persist();
city.flush();
city.clear();

City cityLoaded = City.findCity(city.getId());


Assert.assertNotNull(cityLoaded.getId());

Please ensure, that org.junit.Assert is used (i. e., import org.junit.Assert).

Re-run the tests with the now newly added test method.

Page 13 of 16
Using the Roo-generated Business Objects in your own code
The Roo-generated Business Objects are of course ready to be used in your own code as
well. However, before you can do that, you will need to bootstrap Spring's container to be
able to have access to all functionality offered.
For a stand-alone Java application, that needs to be done manually in the main() method.
Suppose, we want to create a new City ("Ulm") and persist it. The following Class
"MyOwnCode", which you may create in the package " com.springroo.myjoboffers"
shows, how that can be done:

package com.springroo.myjoboffers;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.springroo.myjoboffers.domain.Country;

public class MyOwnCode {

public static void main(String[] args) {


// Bootstrap Spring's container
GenericXmlApplicationContext ctx = new
GenericXmlApplicationContext();
ctx.load("classpath:META-INF/spring/applicationContext.xml");
ctx.refresh();

// Using the Roo-generated Business Object "Country"


Country country = new Country();
country.setName("Germany");
country.persist();
country.flush();
country.clear();

Country readCountry = country.findCountry(country.getId());


System.out.println(readCountry.getName());
}
}

After having created this class, you may run it by right-clicking on "MyOwnCode.java" and
selecting "Run As->Java Application".
After that you may also experiment with the other Domain Objects available (e.g., City,
Company, ...).

Page 14 of 16
Create a CRUD-based Spring MVC Web Application based on
our Domain Object Model
You may finally turn your Spring project into a CRUD-based Spring MVC Web Application
by entering the following Roo commands:
roo> web mvc setup
roo> web mvc all --package com.springroo.myjoboffers.web

Please wait until STS has finished building the newly generated code.

Run the Web Application by right-clicking on the "MyJobOffers" project folder in the
"Package Explorer" and selecting "Run As-> Run on Server" and clicking on Finish.

You may now use that Web Application to maintain your Job Offers.
Please note that in our set-up, the persisted data will be re-created each time you run your
Spring-based (Web-)Application. Hence, the just created city "Ulm" will not be listed via the
Web-Application.

History and re-play of Roo commands


One other useful feature of Spring Roo is that it keeps a history of all Roo commands
executed in the Roo Shell. This history is stored in a text file called "log.roo" and is located
in the root folder of your project.
If you would like to re-play any of the roo commands, this can be done by copying all those
commands in a text file located in your home directory (e.g., "~/myRooLog.roo", on
Windows: "C:\Users\username\myRooLog.roo") and entering the following Roo command
into the Roo Shell:
roo> script --file ~/myRooLog.roo

This will sequentially execute all Roo commands contained in the file specified. This way,
you may easily re-create the project you have just been working on.

You may try this out by copying log.roo to your home directory, deleting your MyJobOffers
project and trying to re-create your project from scratch using the re-play feature.
Note: All manual additions (i.e., not via Roo commands) like for instance the manual
addition of JUnit tests will get lost - so it may be useful to make a copy of your project
first...

Page 15 of 16
If there is some time left
In case there is still some time left, you may do the following:
• Add further tests
• Add finders and expose them to the web interface (see presentation)
• Create your own Spring Roo project in the Spring Tool Suite

References
K. Rimple et al., „Spring Roo in Action“, Manning Publications, 2012

Page 16 of 16

You might also like