When I went to QCon San Francisco 2009, I attended Spring's Roo presentation by Rod Johnson. I have been interested in what Spring Source develops for a few years now; I have used the Spring framework and went to a training course as well, so I was really interested to see what Roo would be like.
Roo is a productivity tool: it is supposed to make your life easier and help you develop faster. It presents itself as a command-line tool, which can either be used from within a command window or your favourite IDE (I will talk more about that in a while). It has a lot of features, such as the tab completion, contextual awareness (which offers the user only the commands relevant at that stage of the project), hints (a lightweight manual) and scripting.
The main basic commands it has to offer are:
- creation of a new project
- setup of a database ORM: Hibernate, Eclispselink and OpenJPA are the only supported ORMs for now.
- creation of domain objects with their fields
- creation of tests
- creation of web controllers
- control of access to different views in the application
- customization of the look and feel of the Web UI for the business domain
Not surprisingly, Roo supports frameworks from the Spring stack, such as Spring MVC, Spring Web Flow and Spring Security. It also uses JSP and Tiles for the presentation tier. It relies on Maven as the build tool. I have personally seen a lot of projects in which Ant was used instead so it could be a problem in those cases (I would not recommend having both at the same time because it would likely mean maintaining 2 build scripts and potentially having local and remote libraries, which could be confusing). However, on a new project, this might not be such a big issue.
Roo relies heavily on AspectJ, generating several files that are supposedly meant to help the developer save time on tedious tasks such as writing getters, setters, and toString() for the entity beans. These files are generated if the relevant annotation is present in the entity bean class file. Roo automotically updates the aspects whenever a Java file it monitors is modified. For instance, if a new field is added, Roo will add the corresponding getter and setter.
To begin, I followed the 10-minute tutorial where I started the creation of a new project from scratch. It worked as expected but from my experience it is necessary to try out some other things that are slightly different to see if the tool still works fine.
I then decided to create my own project, so I started over. Creating the project and setting up the database went well. I decided to use MySQL as the database engine as opposed to Hypersonic in memory which is used in the tutorial. I wrote a very simple SQL script to create the relevant schema, with only one table and 1 string field, plus the id and a version field for Hibernate to use (for dealing with concurrent access).
I created the bean corresponding to my unique table. Then I added my field: the Roo command requires you to specify the type. Some types are predefined (such as string, integer, date to name only a few), others are not. In such a case, you just have to specify the fully qualified name and Roo makes the import for you (I didn't try to use 2 types with the same name from different packages just to see if it would get confused). This is pretty neat anyway. Roo also offers options to specify minimum and maximum sizes when relevant, which will be translated into the corresponding JPA annotations. It's not bad either. I made a mistake when I typed the sizes so I tried to rerun the command but the command applies for new fields only. I had to change the value manually, which was not a problem at all.
For some reason, I could not deploy the project on a server from within STS (Spring Tool Suite, based on Eclipse). This requires the project to become a WTP (Web Tools Platform), which supposedly happens when the first web controller gets created. However, it did not seem to have worked in this case. The documentation says that in order to fix the problem, you should remove the project from STS and import it again: I tried but it did not make any difference.
I then started over and followed the steps in the tutorial. I had a compilation error due to a Maven dependency. It worked before, but not this time. I fixed it manually but I'm still unclear as to why it happened.
Back in the class, I added an @Id annotation, which is used to specify the primary key in the JPA standard: Roo did not seem to like it because I kept getting the message "User provided @javax.persistence.Id field but failed to provide a public 'getId()' method". However, a getId() method was present in the Roo-generated aspect. I had to manually delete @Id, refresh the project, and build it. The impression I have is that it sometimes gets confused.
After I finally deployed the app in Tomcat (manually, using Maven's packaging task), I got it to run. In the JSP, Roo automatically generates a page to create a new domain object. That page contains all the entity fields which were, in my case, id, name, version. Id is auto-generated, and so is version. However, those two fields are purely administrative and should neither be presented to the user, nor set by the user. This means that each generated JSP will have to be updated to get rid of those. It's not such a big deal, but still some extra work. Another option that I did not try would be to add those fields manually in the bean after the JSP gets generated.
On a more theoretical level, a few things still bother me:
- the DAO layer has been removed and the documentation explains that "a DAO layer is extremely rarely added". It does not make too much sense to me as most enterprise applications need one since they are frequently dealing with complicated business logic that require writing complex queries. I simply don't see how an application of a decent size can live without it.
- according to the documentation "A web application will rarely require a services layer, as most logic can be placed in the web controller handle methods and the remainder in entity methods". In an n-tier application, the business logic generally goes into the service layer and not into web controllers. Mixing them together can be source of many issues such as maintainability, reusability and complexity.
- only Eclipse is supported. The Eclipse community is pretty big, but so is the IntelliJ community. In my team, lots of people use IntelliJ and we are just a few Eclipse users. I read that a plugin for IntelliJ was in progress, which is necessary for Roo to be adopted by a maximum number of users.
Despite its promises, I found Roo not reliable enough. When it's working properly it saves one some time, though this time may be lost later when something goes wrong. Like other code-generation tools, when they are misconfigured or misused, they make things harder to debug and figure out what is going on. I'd rather spend more time building each component one after the other, knowing exactly what happens and being able to fix a problem in a reasonable amount of time. In addition to the glitches I encountered, some of the architectural decisions that were made based on certain assumptions (no need for a DAO or service layer - see above) remain a problem to me.