Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Delving into Spring Roo

2010, eclipse, java, review

I had to pick up JPA recently and since it’s been a while since I did anything in this space, thought I would take the opportunity to find out more about Spring Roo. I first heard about it at QCon London 2010, and at the time recalled thinking how easy it was to put together an application from simple components.

One of the things that also encouraged me was the generated application was also a valid OSGi bundle; great. So when Roo 1.1 was released recently, I gave it a spin. (Sadly, and somewhat ironically, whilst Roo 1.1 is now running in an OSGi container, the generated products are no longer OSGi bundles. Roo-1052 has more information about this slide backwards.)

Before going into how to use Spring Roo, it’s worth mentioning what it does and why. The goal of Roo is to make it easy to put together web-based applications that have persistent entities; in other words, your fairly typical web/servlet/jsp/hibernate kind of setup. However, the way it achieves this is somewhat different to other tools. Instead of modifying source code that you write, it creates additional files which it generates. It then uses – effectively – a #include at compile time to bring those fragments into your class. This is achieved with the AspectJ compiler, and in a unique and fairly useful way, using AspectJ as more than just wrapping-a-method-with-log-statements.

The net result is you write a minimal set of code in your class, and Roo automatically generates the necessary AspectJ fragments to support what you’ve written. (Those who have seen Project Lombok may already have seen this kind of approach in an IDE.)

Using Spring Roo is fairly easy. There’s a roo.sh executable (roo.exe on Windows) which brings up a roo> prompt, from which you can hit a number of commands. Unlike a standard OSGi shell, there’s TAB completion; also a bonus is the fact that commands which aren’t enabled are hidden from the list. Finally, there’s a hint system that you can call (with hint) to bring up a list of what-you-can-do.

The steps are as follows:

  • Create a project
  • Setup the persistence mechanism (database, mapping provider)
  • Create one (or more) entities
  • (Optionally) Create a web container

Project

Creating a project is easy enough – you need to run project --topLevelPackage com.example. It generates a number of source directories, a spring folder and a log4j properties file, along with a Maven project to build them all. Think of it as a one-liner for Maven archetypes and you’ll be close to what’s required.

roo> project --topLevelPackage com.example
Created /tmp/example/pom.xml
Created SRC_MAIN_JAVA
Created SRC_MAIN_RESOURCES
Created SRC_TEST_JAVA
Created SRC_TEST_RESOURCES
Created SRC_MAIN_WEBAPP
Created SRC_MAIN_RESOURCES/META-INF/spring
Created SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Created SRC_MAIN_RESOURCES/log4j.properties

Persistence

Setting up persistence is also as easy. persistence setup --provider p --database db will do all the legwork for you in terms of setting up a persistence.xml file, the driver classes to use and the per-provider magic settings that you need to know. Providers such as EclipseLink, OpenJPA and Hibernate are available, as are database drivers like DB2, Derby, Oracle and so on. (The setup notes that if you use a commercial driver you have to install it manually into your Maven repository in order for it to be found.) Use the TAB key to get a list, or complete what you’re typing, in doing this.

com.example roo> persistence setup --provider ECLIPSELINK  --database DERBY 
Managed SRC_MAIN_RESOURCES/META-INF/spring/applicationContext.xml
Created SRC_MAIN_RESOURCES/META-INF/persistence.xml
Created SRC_MAIN_RESOURCES/META-INF/spring/database.properties
Managed ROOT/pom.xml [Added dependency org.apache.derby:derby:10.6.1.0]
Managed ROOT/pom.xml [Added dependency org.eclipse.persistence:eclipselink:2.1.0]
Managed ROOT/pom.xml [Added dependency org.eclipse.persistence:javax.persistence:2.0.1]
Managed ROOT/pom.xml [Added dependency org.hibernate:hibernate-validator:4.1.0.Final]
Managed ROOT/pom.xml [Added dependency javax.validation:validation-api:1.0.0.GA]
Managed ROOT/pom.xml [Added dependency cglib:cglib-nodep:2.2]
Managed ROOT/pom.xml [Added dependency javax.transaction:jta:1.1]
Managed ROOT/pom.xml [Added dependency org.springframework:spring-jdbc:${spring.version}]
Managed ROOT/pom.xml [Added dependency org.springframework:spring-orm:${spring.version}]
Managed ROOT/pom.xml [Added dependency commons-pool:commons-pool:1.5.4]
Managed ROOT/pom.xml [Added dependency commons-dbcp:commons-dbcp:1.3]
Managed ROOT/pom.xml

Entities

Now we’re able to create entities. The entity --class c kicks off the entity generation process; you can type in a fully qualified name or use ~ to represent the project package.

com.example roo> entity --class ~.Employee 
Created SRC_MAIN_JAVA/com/example
Created SRC_MAIN_JAVA/com/example/Employee.java
Created SRC_MAIN_JAVA/com/example/Employee_Roo_Configurable.aj
Created SRC_MAIN_JAVA/com/example/Employee_Roo_Entity.aj
Created SRC_MAIN_JAVA/com/example/Employee_Roo_ToString.aj

At this point, we have a project that’s capable of being used as a pure JPA provider. Before going further, it’s worth looking at what’s been generated:

  • pom.xml - the project details, source directories and so on
  • persistence.xml - which defines the database, configuration mappings and so on
  • *.properties - for supplying mutable data, like userid, password and logging levels
  • *.aj - the aspect fragments
  • Employee.java - a single Java file

The Employee is fairly simple; at the moment, we’ve not added anything to it. In fact, other than a few annotations (@RooJavaBean, @RooToString, @RooEntity) it has no contents. We can add a field using the console to give an employee a name and a manager.

~.Employee roo> field string --fieldName name 
Managed SRC_MAIN_JAVA/com/example/Employee.java
Created SRC_MAIN_JAVA/com/example/Employee_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/com/example/Employee_Roo_ToString.aj
~.Employee roo> field reference --fieldName manager --type ~.Employee
Managed SRC_MAIN_JAVA/com/example/Employee.java
Managed SRC_MAIN_JAVA/com/example/Employee_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/com/example/Employee_Roo_ToString.aj

All this has done is added a couple of fields to the class, one with a single JPA annotation:

@RooJavaBean
@RooToString
@RooEntity
public class Employee {
    private String name;
    @ManyToOne
    private Employee manager;
}

The interesting thing is what you don’t see, which are being generated in the *.aj files. For example, take a look at the Employee_Roo_ToString.aj file:

privileged aspect Employee_Roo_ToString {
    public String Employee.toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Id: ").append(getId()).append(", ");
        sb.append("Version: ").append(getVersion()).append(", ");
        sb.append("Name: ").append(getName()).append(", ");
        sb.append("Manager: ").append(getManager());
        return sb.toString();
    }
}

This aspect, when compiled with AspectJ, effectively inserts a toString() into your class automatically. It uses the name and manager that we’ve just added; and in fact, if you were to go into the Employee.java file and edit it with your favourite text editor, when you save it, Roo will notice and update the toString() automatically.

The id and version are defined in the Employee_Roo_Entity.aj file, so all Roo entities have these. IDs are represented with a Long by default (though you can change that when the entity is created) as well as an Integer version (to support verification of recency when two updates occur on the same row in the database).

Finally, we’ve also got Employee_Roo_JavaBean.aj which generates the getName() and setName() methods based on the fields you add. Of course, most IDEs can do this for you but Roo takes it out of your IDE and into a standalone monitoring process which can update the aspects automatically.

If you have a need to do a specific implementation – say, to pre-validate a field – then you can simply write the setName() in your Employee.java file. Roo notices that it’s already there and doesn’t bother regenerating it.

There’s a web controller as well, though I’m not going to go into it here; doing controller all will generate a huge amount of code for you, and perform command --mavenCommand jetty:run will bootstrap a Jetty environment to test it.

Since it’s scriptable, you can easily replay this by copying and pasting the below into a Roo shell prompt:

project --topLevelPackage com.example
persistence setup --provider ECLIPSELINK --database DERBY
entity --class ~.Employee
field string --fieldName name
field reference --fieldName manager --type Employee
controller all --package ~.web
perform command --mavenCommand jetty:run

Once you’ve done that, point your web browser at http://localhost:8080/example/ and see the app in action.

What’s not to like?

Simple project setup, integration with a variety of different providers and databases, single command entry – what could be better?

Well, although it’s an excellent idea in principle, it does have its drawbacks. One is that although using aspects in this way is a great idea, there is still some concern with using aspects which may put some people off. The second is that sometimes it’s not clear what is happening behind the covers which takes a bit of getting used to.

It’s a real shame that Roo has stopped generating OSGi bundles by default. Partially the enterprise spec runtimes aren’t there yet, so generating a Meta-Persistence header may not be immediately usable; but more was the complaints against Roo that it was using the SpringSource EBR instead of Maven central. Although EBR has been great for popularising OSGi, many upstream projects are migrating over to use OSGi metadata so it’s not clear immediately that it’s as much of an issue as it was when Roo originally came out.

The license is also a potential sticking point as well. Although the Roo annotations are licensed under an Apache License, Roo itself (which reads and generates the *.aj files) are GPL. Some are concerned that this might introduce viral dependencies on the GPL – though whether from some kind of indirect linkage with the annotations or whether it’s a bigger concern about the code that is automatically generated by Roo differs depending on who you ask. Either way, it’s something to consider when basing an application off Roo.

Conclusion

Spring Roo is a great environment for creating persistent entities and web applications to drive them. Obviously not all applications fit into this shape so it has a limited audience. Being a Spring project, it uses Spring heavily in the generation of the runtime entities; much more so than you need if you’re generating an OSGi JPA bundle. It’s also a great application of aspect-oriented-programming that is more than the log-it-and-see example that you come across.

However, concerns about the license and the fact that it no longer generates OSGi bundles mean that it’s probably better suited to prototyping or learning about how to generate JPA entities. The approach is promising though and with a different license or different style of generation it could be a real winner.