Chapter 9. Persistence Layers with Spring Roo

Spring Roo is a rapid application development tool for Java developers. With Roo, you can easily build full Java applications in minutes.

We won’t be covering all aspects of Roo development in this chapter. We will focus on the new repository support for JPA and MongoDB that uses Spring Data to provide this support. If you want to read more about Roo, go to the Spring Roo project home page, where you can find links to the reference manual. While on the project home page, look for a link to download a free O’Reilly ebook by Josh Long and Steve Mayzak called Getting Started with Roo [LongMay11]. This ebook covers an older 1.1 version of Roo that does not support the repository layer, but it is a good introduction to Roo in general. The most up-to-date guide for using Spring Roo is Spring Roo in Action by Ken Rimple and Srini Penchikala [RimPen12].

A Brief Introduction to Roo

Roo works its magic using code generation combined with AspectJ for injecting behavior into your domain and web classes. When you work on a Roo project, the project files are monitored by Roo and additional artifacts are generated. You still have your regular Java classes that you can edit, but there are additional features provided for free. When you create a class with Roo and annotate that class with one or more annotations that provide additional capabilities, Roo will generate a corresponding AspectJ file that contains one or more AspectJ inter type declarations (ITD). There is, for instance, an @RooJavaBean annotation that triggers the generation of an AspectJ aspect declaration that provides ITDs that introduce getters and setters in your Java class. There’s no need to code that yourself. Let’s see a quick example of how that would look. Our simple bean class in shown in Example 9-1.

Example 9-1. A simple Java bean class: Address.java

@RooJavaBean
public class Address {

    private String street;

    private String city;

    private String country;
}

As you can see, we don’t code the getters and setters. They will be introduced by the backing AspectJ aspect file since we used the @RooJavaBean annotation. The generated AspectJ file looks like Example 9-2.

Example 9-2. The generated AspectJ aspect definition: Address_Roo_JavaBean.aj

// WARNING: DO NOT EDIT THIS FILE. THIS FILE IS MANAGED BY SPRING ROO.
// You may push code into the target .java compilation unit if you wish to edit any member(s).

package com.oreilly.springdata.roo.domain;

import com.oreilly.springdata.roo.domain.Address;

privileged aspect Address_Roo_JavaBean {
    
    public String Address.getStreet() {
        return this.street;
    }
    
    public void Address.setStreet(String street) {
        this.street = street;
    }
    
    public String Address.getCity() {
        return this.city;
    }
    
    public void Address.setCity(String city) {
        this.city = city;
    }
    
    public String Address.getCountry() {
        return this.country;
    }
    
    public void Address.setCountry(String country) {
        this.country = country;
    }
    
}

You can see that this is defined as a privileged aspect, which means that it will have access to any private variables declared in the target class. The way you would define ITDs is by preceding any method names with the target class name, separated by a dot. So public String Address.getStreet() will introduce a new method in the Address class with a public String getStreet() signature.

As you can see, Roo follows a specific naming pattern that makes it easier to identify what files it has generated. To work with Roo, you can either use a command-line shell or edit your source files directly. Roo will synchronize all changes and maintain the source and generated files as necessary.

When you ask Roo to create a project for you, it generates a pom.xml file that is ready for you to use when you build the project with Maven. In this pom.xml file, there is a Maven compile as well as an AspectJ plug-in defined. This means that all the AspectJ aspects are woven at compile time. In fact, nothing from Roo remains in the Java class files that your build generates. There is no runtime jar dependency. Also, the Roo annotations are source-level retention only, so they will not be part of your class files. You can, in fact, easily get rid of Roo if you so choose. You have the option of pushing all of the code defined in the AspectJ files into the appropriate source files and removing any of these AspectJ files. This is called push-in refactoring, and it will leave you with a pure Java solution, just as if you had written everything from scratch yourself. Your application still retains all of the functionality.

Roo’s Persistence Layers

Spring Roo started out supporting JPA as the only persistence option. It also was opinionated in terms of the data access layer. Roo prescribed an active record data access style where each entity provides its finder, save, and delete methods.

Starting with Roo version 1.2, we have additional options for the persistence layer (see Figure 9-1). Roo now allows you to choose between the default active record style and a repository-based persistence layer. If you choose the repository approach, you have a choice between JPA and MongoDB as the persistence providers. The actual repository support that Roo uses is the one provided by Spring Data, which we have already seen in Chapter 2.

Spring Roo 1.2 layer architecture

Figure 9-1. Spring Roo 1.2 layer architecture

In addition to an optional repository layer, Roo now also lets you define a service layer on top of either the active record style or repository style persistence layer.

Quick Start

You can use Roo either as a command-line tool or within an IDE, like the free Spring Tool Suite, that has built-in Roo support. Another IDE that has support for Roo is IntelliJ IDEA, but we won’t be covering the support here.

Using Roo from the Command Line

First, you need to download the latest Spring Roo distribution from the download page. Once you have the file downloaded, unzip it somewhere on your system. In the bin directory, there is a roo.sh shell script for Unix-style systems as well as a roo.bat batch file for Windows. When you want to create a Roo project, simply create a project directory and start Roo using the shell script or the batch file. If you add the bin directory to your path, you can just use the command name to start Roo; otherwise, you will have to provide the fully qualified path.

Once Roo starts up, you are greeted with the following screen (we entered hint at the prompt to get the additional information):

    ____  ____  ____  
   / __ / __ / __  
  / /_/ / / / / / / / 
 / _, _/ /_/ / /_/ /  
/_/ |_|\____/\____/    1.2.2.RELEASE [rev 7d75659]


Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
roo> hint
Welcome to Roo! We hope you enjoy your stay!

Before you can use many features of Roo, you need to start a new project.

To do this, type 'project' (without the quotes) and then hit TAB.

Enter a --topLevelPackage like 'com.mycompany.projectname' (no quotes).
When you've finished completing your --topLevelPackage, press ENTER.
Your new project will then be created in the current working directory.

Note that Roo frequently allows the use of TAB, so press TAB regularly.
Once your project is created, type 'hint' and ENTER for the next suggestion.
You're also welcome to visit http://forum.springframework.org for Roo help.
roo>

We are now ready to create a project and start developing our application. At any time, you can enter hint, and Roo will respond with some instruction on what to do next based on the current state of your application development. To cut down on typing, Roo will attempt to complete the commands you enter whenever you hit the Tab key.

Using Roo with Spring Tool Suite

The Spring Tool Suite comes with built-in Roo support, and it also comes bundled with Maven and the Developer Edition of VMware vFabric tc Server. This means that you have everything you need to develop applications with Roo. Just create your first Roo application using the menu option File→New→Spring Roo Project. You can see this in action in Figure 9-2.

Creating a Spring Roo project—menu option

Figure 9-2. Creating a Spring Roo project—menu option

This opens a “Create a new Roo Project” dialog screen, as shown in Figure 9-3.

Creating a Spring Roo project—new project dialog

Figure 9-3. Creating a Spring Roo project—new project dialog

Just fill in the “Project name” and “Top level package name,” and then select WAR as the packaging. Click Next, and then click Finish on the next screen. The project should now be created, and you should also see the Roo shell window, as shown in Figure 9-4.

Creating a Spring Roo project—new project with Roo Shell

Figure 9-4. Creating a Spring Roo project—new project with Roo Shell

A Spring Roo JPA Repository Example

We are now ready to build the first Roo project. We will start with a customer service application based on the same domain model that we have seen in earlier chapters. We will create a Customer class and an associated Address class, link them together, and create repositories and really basic data entry screens for them. Since Roo’s repository support supports both JPA and MongoDB, using the Spring Data repository support, we will create one of each kind of application. As you will see, they are almost identical, but there are a couple of differences that we will highlight. So, let’s get started. We’ll begin with the JPA application.

Creating the Project

If you are using Spring Tool Suite, then just follow the aforementioned instructions to create a new Spring Roo project. On the “Create a new Roo Project” dialog screen, provide the following settings:

  • Project name: roo-spring-data-jpa

  • Top level package name: com.oreilly.springdata.roo

  • Packaging: WAR

If you are using the command-line Roo shell, you need to create a roo-spring-data-jpa directory; once you change to this new directory, you can start the Roo shell as just explained. At the roo> prompt, enter the following command:

project --topLevelPackage com.oreilly.springdata.roo 
  --projectName roo-spring-data-jpa --java 6 --packaging WAR

You now have created a new project, and we are ready to start developing the application. From here on, the actions will be the same whether you are using the Roo shell from the command line or inside the Spring Tool Suite.

Setting Up JPA Persistence

Setting up the JPA persistence configuration consists of selecting a JPA provider and a database. We will use Hibernate together with HSQLDB for this example. At the roo> prompt, enter the following:

jpa setup --provider HIBERNATE --database HYPERSONIC_PERSISTENT

Note

Remember that when entering these commands, you can always press the Tab key to get completion and suggestions for available options. If you are using the Spring Tool Suite, press Ctrl+Space instead.

Creating the Entities

Let’s create our entities, starting with the Address class:

entity jpa --class ~.domain.Address --activeRecord false
field string --fieldName street --notNull
field string --fieldName city --notNull
field string --fieldName country --notNull

That wasn’t too hard. Note that we specified --activeRecord false, which means that we will have to provide the CRUD functionality using a repository. The resulting Address class looks like this:

package com.oreilly.springdata.roo.domain;

import javax.validation.constraints.NotNull;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.entity.RooJpaEntity;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooJpaEntity
public class Address {

    @NotNull
    private String street;

    @NotNull
    private String city;

    @NotNull
    private String country;
}

We see the private fields we declared and three Roo annotations: @RooJavaBean, @RooToString, and @RooJpaEntity. These annotations have corresponding AspectJ aspect declarations that you can find in the same directory as the Java class.

Let’s create the EmailAddress and Customer classes next. The EmailAddress is an embeddable class with a single value field. We need to ask Roo to ignore the fact that value is a reserved word for some SQL databases. We also provide a column name of email since that will be more descriptive for anyone inspecting the database table. Using this embeddable in a field declarations, we specify it as an embedded field.

embeddable --class ~.domain.EmailAddress
field string --fieldName value --notNull --column email --permitReservedWords
entity jpa --class ~.domain.Customer --activeRecord false
field string --fieldName firstName --notNull
field string --fieldName lastName --notNull
field embedded --fieldName emailAddress --type ~.domain.EmailAddress
field set --fieldName addresses --type ~.domain.Address

The last command creates a many-to-many relationship to the address table, allowing us to provide a number of addresses for each customer. This is the resulting Customer class:

package com.oreilly.springdata.roo.domain;

import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Embedded;
import javax.persistence.ManyToMany;
import javax.validation.constraints.NotNull;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.entity.RooJpaEntity;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooJpaEntity
public class Customer {

    @NotNull
    private String firstName;

    @NotNull
    private String lastName;

    @Embedded
    private EmailAddress emailAddress;

    @ManyToMany(cascade = CascadeType.ALL)
    private Set<Address> addresses = new HashSet<Address>();
}

For completeness, we’ll show the EmailAddress class as well:

package com.oreilly.springdata.roo.domain;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@Embeddable
public class EmailAddress {

    @NotNull
    @Column(name = "email")
    private String value;
}

The most interesting part of this class is that it is @Embeddable and that we have defined the value property to be stored in a database column named email.

Defining the Repositories

With the entities in place, we can now create the JPA repositories. We create one repository for each entity.

repository jpa --interface ~.repository.CustomerRepository --entity ~.domain.Customer
repository jpa --interface ~.repository.AddressRepository --entity ~.domain.Address

At this point we could also create a service layer, but since this is such a simple application, we’ll skip this step.

Creating the Web Layer

Now we need some really simple web pages so we can enter and modify our customer and address data. We’ll just stick with the screens generated by Roo.

web mvc setup
web mvc scaffold --class ~.web.CustomerController --backingType ~.domain.Customer
web mvc scaffold --class ~.web.AddressController --backingType ~.domain.Address

There is one thing we have to do. Roo doesn’t know how to map the EmailAddress class between the String representation used for web pages and the EmailAddress type used for persistence. We need to add converters to the ApplicationConversionServiceFactoryBean that Roo generated; Example 9-3 shows how.

Example 9-3. The generated ApplicationConversionServiceFactoryBean.java with converters added

package com.oreilly.springdata.roo.web;

import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.roo.addon.web.mvc.controller.converter.RooConversionService;

import com.oreilly.springdata.roo.domain.EmailAddress;

/**
 * A central place to register application converters and formatters. 
 */
@RooConversionService
public class ApplicationConversionServiceFactoryBean 
        extends FormattingConversionServiceFactoryBean {

  @Override
  protected void installFormatters(FormatterRegistry registry) {
    super.installFormatters(registry);
    // Register application converters and formatters
    registry.addConverter(getStringToEmailAddressConverter());
    registry.addConverter(getEmailAddressConverterToString());
  }

  public Converter<String, EmailAddress> getStringToEmailAddressConverter() {
    return new Converter<String, EmailAddress>() {
      @Override
      public EmailAddress convert(String source) {
        EmailAddress emailAddress = new EmailAddress();
        emailAddress.setAddress(source);
        return emailAddress;
      }
    };
  }

  public Converter<EmailAddress, String> getEmailAddressConverterToString() {
    return new Converter<EmailAddress, String>() {
      @Override
      public String convert(EmailAddress source) {
        return source.getAddress();
      }
    };
  }
}

Running the Example

Now we are ready to build and deploy this example. For Spring Tool Suite, just drag the application to the tc server instance and start the server. If you use the command line, simply exit the Roo shell and from the command line run the following Maven commands:

mvn clean package
mvn tomcat:run

You should now be able to open a browser and navigate to http://localhost:8080/roo-spring-data-jpa/ and see the screen shown in Figure 9-5.

The JPA application

Figure 9-5. The JPA application

Our application is now complete, and we can add some addresses and then a customer or two.

Note

If you get tired of losing your data every time you restart your app server, you can change the schema creation properties in src/main/resources/META-INF/persistence.xml. Change <property name="hibernate.hbm2ddl.auto" value="create" /> to have a value of "update".

A Spring Roo MongoDB Repository Example

Since Spring Data includes support for MongoDB repositories, we can use MongoDB as a persistence option when using Roo. We just won’t have the option of using the active record style for the persistence layer; we can only use the repositories. Other than this difference, the process is very much the same as for a JPA solution.

Creating the Project

If you are using Spring Tool Suite, then just follow the aforementioned instructions to create a new Spring Roo project. On the “Create a new Roo Project” dialog screen, provide the following settings:

  • Project name: roo-spring-data-mongo

  • Top level package name: com.oreilly.springdata.roo

  • Packaging: WAR

When using the command-line Roo shell, create a roo-spring-data-mongo directory. Change to this new directory and then start the Roo Shell as previously explained. At the roo> prompt, enter the following command:

project --topLevelPackage com.oreilly.springdata.roo 
  --projectName roo-spring-data-mongo --java 6 --packaging WAR

Setting Up MongoDB Persistence

Setting up the persistence configuration for MongoDB is simple. We can just accept the defaults. If you wish, you can provide a host, port, username, and password, but for a default local MongoDB installation the defaults work well. So just enter the following:

mongo setup

Creating the Entities

When creating the entities, we don’t have the option of using the active record style, so there is no need to provide an --activeRecord parameter to opt out of it. Repositories are the default, and the only option for the persistence layer with MongoDB. Again, we start with the Address class:

entity mongo --class ~.domain.Address
field string --fieldName street --notNull
field string --fieldName city --notNull
field string --fieldName country --notNull

That looks very similar to the JPA example. When we move on to the Customer class, the first thing you’ll notice that is different is that with MongoDB you don’t use an embeddable class. That is available only for JPA. With MongoDB, you just create a plain class and specify --rooAnnotations true to enable the @RooJavaBean support. To use this class, you specify the field as other. Other than these minor differences, the entity declaration is very similar to the JPA example:

class --class ~.domain.EmailAddress --rooAnnotations true
field string --fieldName value --notNull --permitReservedWords
entity mongo --class ~.domain.Customer
field string --fieldName firstName --notNull
field string --fieldName lastName --notNull
field other --fieldName emailAddress --type ~.domain.EmailAddress
field set --fieldName addresses --type ~.domain.Address

Defining the Repositories

We declare the MongoDB repositories the same way as the JPA repositories except for the mongo keyword:

repository mongo --interface ~.repository.CustomerRepository 
  --entity ~.domain.Customer
repository mongo --interface ~.repository.AddressRepository --entity ~.domain.Address

Creating the Web Layer

The web layer is exactly the same as for the JPA example:

web mvc setup
web mvc scaffold --class ~.web.CustomerController --backingType ~.domain.Customer
web mvc scaffold --class ~.web.AddressController --backingType ~.domain.Address

Don’t forget to add the converters to the ApplicationConversionServiceFactoryBean like we did for JPA in Example 9-3.

Running the Example

Now we are ready to build and deploy this example. This is again exactly the same as the JPA example, except that we need to have MongoDB running on our system. See Chapter 6 for instructions on how to install and run MongoDB.

For Spring Tool Suite, just drag the application to the tc server instance and start the server. If you use the command line, simply exit the Roo shell and from the command line run the following Maven commands:

mvn clean package
mvn tomcat:run

You should now be able to open a browser and navigate to http://localhost:8080/roo-spring-data-mongo/ and see the screen in Figure 9-6.

The MongoDB application

Figure 9-6. The MongoDB application

Our second example application is now complete, and we can add some addresses and then a customer or two.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.18.218