Spring Roo Docs
Spring Roo Docs
1.3.2.RELEASE
Copyright 2009-2014 VMware, Inc. All Rights Reserved. Copies of this document may be made for your
own use and for distribution to others, provided that you do not charge any fee for such copies and further
provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
Preface .... xi
I. Welcome to Spring Roo .... 1
1. Introduction .... 2
1.1. What is Roo? .... 2
1.2. Why Use It .... 3
1.2.1. Higher Productivity .... 3
1.2.2. Stock-Standard Java .... 3
1.2.3. Usable and Learnable .... 4
1.2.4. No Engineering Trade-Offs .... 5
1.2.5. Easy Roo Removal .... 6
1.3. Installation .... 6
1.4. Optional ROO_OPTS Configuration .... 7
1.5. First Steps: Your Own Web App in Under 10 Minutes .... 8
1.6. Exploring the Roo Samples .... 10
1.7. Suggested Steps to Roo Productivity .... 10
2. Beginning With Roo: The Tutorial .... 12
2.1. What You'll Learn .... 12
2.2. Alternative Tutorial: The Wedding RSVP Application .... 12
2.3. Tutorial Application Details .... 13
2.4. Step 1: Starting a Typical Project .... 13
2.5. Step 2: Creating Entities and Fields .... 16
2.6. Step 3: Integration Tests .... 18
2.7. Step 4: Using Your IDE .... 18
2.8. Step 5: Creating A Web Tier .... 19
2.9. Step 6: Loading the Web Server .... 20
2.10. Securing the Application .... 21
2.11. Customizing the Look & Feel of the Web UI .... 23
2.12. Selenium Tests .... 24
2.13. Backups and Deployment .... 24
2.14. Where To Next .... 25
3. Application Architecture .... 26
3.1. Architectural Overview .... 26
3.2. Critical Technologies .... 26
3.2.1. AspectJ .... 26
3.2.2. Spring .... 29
3.3. Entity Layer .... 30
3.4. Web Layer .... 31
3.5. Optional Services Layer .... 32
3.6. Goodbye DAOs .... 32
3.7. Maven .... 34
3.7.1. Packaging .... 34
3.7.2. Multi-Module Support .... 35
4. Usage and Conventions .... 38
4.1. Usability Philosophy .... 38
4.2. Shell Features .... 39
4.3. IDE Usage .... 41
4.3.1. Install the STS Roo Support .... 42
4.4. Build System Usage .... 43
4.5. File System Conventions .... 44
1.3.2.RELEASE
ii
1.3.2.RELEASE
iii
1.3.2.RELEASE
iv
1.3.2.RELEASE
1.3.2.RELEASE
vi
1.3.2.RELEASE
vii
1.3.2.RELEASE
viii
1.3.2.RELEASE
ix
1.3.2.RELEASE
Preface
I still recall the moment when I realised that I would like to program. The motivation for me was
recognition that creativity with software is mostly constrained by your imagination and skills, whereas
creativity outside the software world is typically constrained by whatever physical items you happen
to possess. Of course at that early stage I hadn't yet come across the subtle constraints in my optimistic
assessment of software (such as CPU capabilities, memory, CAP theory etc!), but the key principle
that software was almost boundlessly flexible sparked an interest that continues to this day.
Of course, the creativity potential of software implies an abundance of time, as it is time that is the
principal ingredient in building and maintaining software. Ever since the "castle clock" in 1206 we
have been exploring better ways of programming ever-increasingly sophisticated computers, and the
last decade in particular has seen a surge in new languages and techniques for doing so.
Despite this 800 year history of programming, software projects are no different from other projects in
that they are still bound by the project management triangle: "cost, scope or schedule: pick any two".
Professional software developers grapple with this reality every day, constantly striving for new tools
and techniques that might help them deliver quality software more quickly.
While initial delivery remains the key priority for most software projects, the long-term operational
dimensions of that software are even more critical. The criticality of these operational dimensions is
easily understood given that most software needs to be executed, managed, maintained and enhanced
for many years into the future. Architectural standards are therefore established to help ensure that
software is of high quality and preferably based on well-understood, vendor-agnostic and standardsbased mainstream engineering approaches.
There is of course a natural tension between the visibility of initial delivery and the conservatism
typically embodied in architectural standards. Innovative new approaches often result in greater
productivity and in turn faster project delivery, whereas architectural standards tend to restrict these
new approaches. Furthermore, there is a social dimension in that most developers focus their time on
acquiring knowledge, skills and experience with those technologies that will realistically be used, and
this in turn further cements the dominance of those technologies in architectural standards.
It was within this historical and present-day context that we set out to build something that would offer
both genuine innovation and architectural desirability. We sought to build something that would deliver
compelling developer productivity without compromising on engineering integrity or discarding
mainstream existing technologies that benefit from architectural standards approval, excellent tooling
and a massive pool of existing developer knowledge, skills and experience.
Spring Roo is the modern-day answer to enterprise Java productivity. It's the normal Java platform
you know, but with productivity levels you're unlikely to have experienced before (at least on Java!).
It's simple to understand and easy to learn. Best of all, you can use Roo without needing to seek
architectural approval, as the resulting applications use nothing but the mainstream Java technologies
you already use. Plus all your existing Java knowledge, skills and experience are directly applicable
when using Roo, and applications built with Roo enjoy zero CPU or memory overhead at runtime.
Thank you for taking the time to explore Spring Roo. We hope that you enjoy using Roo as much as
we've enjoyed creating it.
Ben Alex, Founder - Spring Roo
1.3.2.RELEASE
xi
1.3.2.RELEASE
Chapter 1. Introduction
1.1. What is Roo?
Spring Roo is an easy-to-use productivity tool for rapidly building enterprise applications in the Java
programming language. It allows you to build high-quality, high-performance, lock-in-free enterprise
applications in just minutes. Best of all, Roo works alongside your existing Java knowledge, skills and
experience. You probably won't need to learn anything new to use Roo, as there's no new language or
runtime platform needed. You simply program in your normal Java way and Roo just works, sitting
in the background taking care of the things you don't want to worry about. It's an approach unlike
anything you've ever seen before, we guarantee it!
You work with Roo by loading its "shell" in a window and leaving it running. You can interact with Roo
via commands typed into the shell if you like, but most of the time you'll just go about programming
in your text editor or IDE as usual. As you make changes to your project, Roo intelligently determines
what you're trying to do and takes care of doing it for you automatically. This usually involves
automatically detecting file system changes you've made and then maintaining files in response. We
say "maintaining files" because Roo is fully round-trip aware. This means you can change any code
you like, at any time and without telling Roo about it, yet Roo will intelligently and automatically
deal with whatever changes need to be made in response. It might sound magical, but it isn't. This
documentation will clearly explain how Roo works and you'll find yourself loving the approach - just
like so the many other people who are already using Roo.
Before you start wondering how Roo works, let's confirm a few things it is NOT:
Roo is not a runtime. Roo is not involved with your project when it runs in production. You won't
find any Roo JARs in your runtime classpath or Roo annotations compiled into your classes. This is
actually a wonderful thing. It means you have no lock-in to worry about (you can remove Roo from
your project in just a couple of minutes!). It probably also means you won't need to get approval to
use Roo (what's to approve when it's more like a command line tool than a critical runtime library
like Spring Framework?). It also means there is no technical way possible for Roo to slow your
project down at runtime, waste memory or bloat your deployment artefacts with JARs. We're really
proud of the fact that Roo imposes no engineering trade-offs, as it was one of our central design
objectives.
Roo is not an IDE plugin. There is no requirement for a "Roo Eclipse plugin" or "Roo IntelliJ plugin".
Roo works perfectly fine in its own operating system command window. It sits there and monitors
your file system, intelligently and incrementally responding to changes as appropriate. This means
you're perfectly able to use vi or emacs if you'd like (Roo doesn't mind how your project files get
changed).
Roo is not an annotation processing library. There is a Java 6 feature known as the annotation
processing API. Roo does not use this API. This allows Roo to work with Java 5, and also gives us
access to a much more sophisticated and extensible internal model.
So how does Roo actually work then? The answer to that question depends on how much detail you'd
like. In super-summary form, Roo uses an add-on based architecture that performs a combination of
passive and active code generation of inter-type declarations. If you're interested in how that works at a
practical project level, we cover that shortly in the "Beginning With Roo: The Tutorial" chapter. Or for
an advanced look at Roo internals, we've covered that in Part III: Internals and Add-On Development.
1.3.2.RELEASE
Introduction
1.3.2.RELEASE
Introduction
would feel right at home. If you've ever built an enterprise application with Java, some or all of the
technologies that Roo uses by default will already be familiar to you.
Some of the common technologies Roo projects use include Spring (such as Spring Framework, Spring
Security and Spring Web Flow), Maven, Java Server Pages (JSP), Java Persistence API (JPA, such
as Hibernate), Tiles and AspectJ. We've chosen technologies which are extremely commonly used in
enterprise Java projects, ensuring you've probably either already used them or at least will have no
difficulty finding hundreds of thousands of other people who have (and the resultant books, blogs,
samples etc that exist for each). Also, because most of these technologies are implemented using addons, if you'd like Roo to use a different technology on your project it's quite easy to do so.
By using standard Java technologies, Roo avoids reinventing the wheel or providing a limited-value
abstraction over them. The technologies are available to you in their normal form, and you can use
them in the same way as you always have. What Roo brings to the table is automatic setup of those
technologies into a Spring-certified best-practice application architecture and, if you wish, automatic
maintenance of all files required by those technologies (such as XML, JSP, Java etc). You'll see this
in action when you complete the ten minute test.
You'll also find that Roo adopts a very conservative, incremental approach to adding technologies to
your project. This means when you first start a new project Roo will only assume you want to build
a simple JAR. As such it will have next to no dependencies. Only when you ask to add a persistence
provider will JPA be installed, and only when you add a field using JavaBean Validation annotations
will that library be installed. The same holds true for Spring Security, Spring Web Flow and the other
technologies Roo supports. With Roo you really do start small and incrementally add technologies if
and when you want to, which is consistent with Roo's philosophy of there being no engineering tradeoffs.
1.3.2.RELEASE
Introduction
The learnability of Roo is concurrently addressed on three fronts. First, we favor using standard Java
technologies that you probably already know. Second, we are careful to keep Roo out of your way.
The more Roo simply works in the background automatically without needing your involvement, the
less you need to learn about it in the first place. This is consistent with Raskin's recommendation to
never interrupt your locus of attention. Third, we offer a lot of learnability features in Roo itself. These
include the "hint" command, which suggests what you may wish to do next based on your present
project's state. It's quite easy to build an entire Roo project simply by typing "hint", pressing enter, and
following the instructions Roo presents (we do this all the time during conference talks; it's always
easier than remembering commands!). There's also the intelligent tab completion, which has natural,
friendly conventions like completing all mandatory arguments step-by-step (without distracting you
with unnecessary optional arguments). There's also the online "help" command, sample scripts, this
documentation and plenty of other resources.
Roo also follows a number of well-defined conventions so that you always know what it's doing. Plus
it operates in a "fail safe" manner, like automatically undoing any changes it makes to the file system
should something go wrong. You'll quickly discover that Roo is a friendly, reliable companion on your
development journey. It doesn't require special handling and it's always there for you when you need it.
In summary, we've spent a lot of time thinking about usability and learnability to help ensure you enjoy
your Roo experience.
1.3.2.RELEASE
Introduction
While some people would argue these deployment size, CPU and memory considerations are minor,
the fact is they add up when you have a large application that needs to scale. With Roo your applications
will use your system resources to their full potential. Plus as we move more and more enterprise
applications into virtualized and cloud-hosted environments, the requirement for performant operation
on shared hardware will become even more relevant.
You'll also find that Roo provides a well thought out application architecture that delivers pragmatism,
flexibility and ease of maintainability. You'll see we've made architectural decisions like eliminating
the DAO layer, using annotation-based dependency injection, and automatically providing dependency
injection on entities. These decisions dramatically reduce the amount of Java and XML code you have
to write and maintain, plus improve your development cycle times and refactoring experiences.
With Roo, you don't have to make a trade-off between productivity or performance. Now it's easy to
have both at the same time.
1.3. Installation
Roo is a standard Java application that is fully self-contained within the Roo distribution ZIPs. You
can download Roo from one of the download sites, or build a distribution ZIP yourself from our source
control repository.
If you are upgrading from an existing version of Spring Roo, you should consult the upgrade notes
for important information.
1.3.2.RELEASE
Introduction
Before attempting to install Roo, please ensure you have the following system dependencies:
A Linux, Apple or Windows-based operating system (other operating systems may work but are
not guaranteed)
A Java 6 or 7 installation, with the $JAVA_HOME environment variable pointing to the installation.
Note that Java 8 is currently not supported.
Apache Maven 2.0.9 or above installed and in the path
We have listed various considerations concerning the Java Development Kit (JDK) and operating
systems in the known issues section of this documentation. We always recommend you use the latest
version of Java and Maven that are available for your platform. We also recommend that you use
Spring Tool Suite (STS), which is our free Eclipse-based IDE that includes a number of features that
make working with Roo even easier (you can of course use Roo with normal Eclipse or without an
IDE at all if you prefer).
Once you have satisfied the initial requirements, you can install Roo by following these steps:
1. Unzip the Roo installation ZIP to a directory of your choice; this will be known as $ROO_HOME in
the directions below
2. If using Windows, add $ROO_HOME\bin to your %PATH% environment variable
3. If using Linux or Apple, create a symbolic link using a command such as sudo ln -s $ROO_HOME/
bin/roo.sh /usr/bin/roo
Next verify Roo has been installed correctly. This can be done using the following commands:
$ mkdir roo-test
$ cd roo-test
$ roo quit
____ ____ ____
/ __ \/ __ \/ __ \
/ /_/ / / / / / / /
/ _, _/ /_/ / /_/ /
/_/ |_|\____/\____/
Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
$ cd ..
$ rmdir roo-test
If you see the logo appear, you've installed Roo successfully. For those curious, the "[rev RRR]" refers
to the Git commit ID used to compile that particular build of Roo.
1.3.2.RELEASE
Introduction
$ export ROO_OPTS="-Droo.bright=true"
$ set ROO_OPTS="-Droo.bright=true"
// Linux or Apple
// Windows users
There is an enhancement request within our issue tracker for customisable shell color schemes. If
you're interested in seeing this supported by Roo, you may wish to consider voting for ROO-549.
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.
Notice the output from the "hint" command guides you through what to do next. Let's do that:
roo> project --topLevelPackage com.tenminutes
Created /home/balex/ten-minutes/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
roo> hint
Roo requires the installation of a JPA provider and associated database.
Type 'jpa setup' and then hit TAB three times.
We suggest you type 'H' then TAB to complete "HIBERNATE".
After the --provider, press TAB twice for database choices.
For testing purposes, type (or TAB) HYPERSONIC_IN_MEMORY.
If you press TAB again, you'll see there are no more options.
1.3.2.RELEASE
Introduction
As such, you're ready to press ENTER to execute the command.
Once JPA is installed, type 'hint' and ENTER for the next suggestion.
At this point you've now got a viable Maven-based project setup. But let's make it more useful by
setting up JPA. In the interests of time, I'll just include the commands you should type below. Be sure
to try using the TAB key when using the shell, as it will save you from having to type most of these
commands:
roo> jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
roo> hint
roo> entity jpa --class ~.Timer --testAutomatically
roo> hint
roo> field string --fieldName message --notNull
roo> hint web mvc
roo> web mvc setup
roo> web mvc all --package ~.web
roo> selenium test --controller ~.web.TimerController
roo> perform tests
roo> perform package
roo> perform eclipse
roo> quit
$ mvn tomcat:run
The "perform" commands could have been easily undertaken from the command prompt using "mvn"
instead. We just did them from within Roo to benefit from TAB completion. You could have also
skipped the "perform eclipse" command if you are using the m2eclipse plugin. If you are using Spring
Tool Suite (STS), it automatically includes m2eclipse and as such you do not need to use the "perform
eclipse" command. Indeed if you're an STS user, you could have started your Roo project right from
within the IDE by selecting the File > New > Spring Roo menu option and completing the steps. In that
case a Roo Shell view will open within STS and from there you can enter the remaining commands.
Now that you've loaded Tomcat, let's run the Selenium tests. You can do this by loading
a new command window, changing into the ten-minutes directory, and then executing mvn
selenium:selenese. You should see your FireFox web browser execute the generated Selenium tests.
You can also visit your new web application at http://localhost:8080/tenminutes, which should look
similar to the picture below.
Naturally in this short ten minute test we've skipped dozens of features that Roo can provide, and didn't
go into any detail on how you could have customised the application. We just wanted to show you that
Roo works and you can build an application in record-time. The Beginning With Roo: The Tutorial
chapter will go through the process of building an application in much more depth, including how to
work with your IDE and so on.
1.3.2.RELEASE
Introduction
The filename.roo shown in the statements above should be substituted with one of the filenames from
this list (note that you get filename completion using TAB):
clinic.roo: The Petclinic sample script is our most comprehensive. It builds a large number of
entities, controllers, Selenium tests and dynamic finders. It also sets up Log4J and demonstrates
entity relationships of different cardinalities.
vote.roo: The Voting sample script was built live on-stage during SpringOne Europe 2009, as
detailed in the project history section. This is a nice sample script because it's quite small and only
has two entities. It also demonstrates Spring Security usage.
wedding.roo: The Wedding RSVP sample script is the result of the wedding RSVP tutorial. If you're
looking for another Roo tutorial, this sample script (along with the associated blog entry) is a good
choice. This project includes Selenium tests, dynamic finders and Log4j configuration.
pizzashop.roo: The PizzaShop sample script demonstrates Roo's integration of JPA composite
primary keys. It produces a headless application which is accessible via JSON (available through
Spring MVC REST integration). To add a Web UI on top of it, simply run the web mvc all command.
The application is described in greater detail in our tutorial.
1.3.2.RELEASE
10
Introduction
We welcome your comments and suggestions as you go about using Roo. One convenient way to
share your experiences is to Tweet with the @springroo hash code. You can also follow Roo's core
development team via Twitter for the latest Roo updates. In any event, we thank you for exploring
Roo and hope that you enjoy your Roo journey.
1.3.2.RELEASE
11
1.3.2.RELEASE
12
While this class diagram represents a simplified model of the problem domain for the pizza shop
problem domain, it is a good starting point for the project at hand in order to deliver a first prototype of
the application to the Pizza Shop owner. Later tutorials will expand this domain model to demonstrate
more advanced features of Spring Roo.
Next, we start Spring Roo and type 'hint' to obtain context-sensitive guidance from the Roo shell:
pizza> roo
____ ____ ____
/ __ \/ __ \/ __ \
/ /_/ / / / / / / /
/ _, _/ /_/ / /_/ /
/_/ |_|\____/\____/
Welcome to Spring Roo. For assistance press TAB or type "hint" then hit ENTER.
roo>
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.
1.3.2.RELEASE
13
There are quite a few usability features within the Roo shell. After typing hint you may have noticed
that this command guides you in a step-by-step style towards the completion of your first project. Or
if you type help you will see a list of all commands available to you in the particular context you
are in. In our case we have not created a new project yet so the help command only reveals higher
level commands which are available to you at this stage. To create an actual project we can use the
project command:
roo> project --topLevelPackage com.springsource.roo.pizzashop
Created ROOT/pom.xml
Created SRC_MAIN_RESOURCES
Created SRC_MAIN_RESOURCES/log4j.properties
Created SPRING_CONFIG_ROOT
Created SPRING_CONFIG_ROOT/applicationContext.xml
com.springsource.roo.pizzashop roo>
When you used the project command, Roo created you a Maven pom.xml file as well as a Mavenstyle directory structure. The top level package you nominated in this command was then used as the
<groupId> within the pom.xml. When typing later Roo commands, you can use the "~" shortcut key to
refer to this top-level-package (it is read in by the Roo shell from the pom.xml each time you load Roo).
The following folder structure now exists in your file system:
For those familiar with Maven you will notice that this folder structure follows standard Maven
conventions by creating separate folders for your main project resources and tests. Roo also installs a
1.3.2.RELEASE
14
1.3.2.RELEASE
15
You will notice that besides the creation of Java and AspectJ sources, the entity jpa command in the
Roo shell takes care of creating the appropriate folder structure in your project for the top level package
you defined earlier. You will notice that we used the '~' character as a placeholder for the project's
top level package. While this serves a convenience to abbreviate long commands, you can also tabcomplete the full top level package in the Roo shell.
As a next step we need to add the 'name' field to our Topping domain class. This can be achieved by
using the field command as follows:
~.domain.Topping roo> hint
You can add fields to your entities using either Roo or your IDE.
To add a new field, type 'field' and then hit TAB. Be sure to select
your entity and provide a legal Java field name. Use TAB to find an entity
name, and '~' to refer to the top level package. Also remember to use TAB
to access each mandatory argument for the command.
1.3.2.RELEASE
16
As explained in the documentation by typing the hint command you can easily add constraints to
your fields by using optional attributes such as --notNull and --sizeMin 2. These attributes result
in standards-compliant JSR-303 annotations which Roo will add to your field definition in your Java
sources. You will also notice that the Roo shell is aware of the current context within which you are
using the field command. It knows that you have just created a Topping entity and therefore assumes
that the field command should be applied to the Topping Java source. Roo's current context is visible
in the shell prompt.
If you wish to add the field to a different target type you can specify the --class attribute as part of
the field command which then allows you to tab complete to any type in your project.
As a next step you can create the Base and the Pizza domain object in a similar fashion by issuing the
following commands (shell output omitted):
entity jpa --class ~.domain.Base --testAutomatically
field string --fieldName name --notNull --sizeMin 2
entity jpa --class ~.domain.Pizza --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field number --fieldName price --type java.lang.Float
After adding the name and the price field to the Pizza domain class we need to deal with its
relationships to Base and Topping. Let's start with the m:m (one Pizza can have many Toppings and
one Topping can be applied to many Pizzas) relationship between Pizza and Toppings. To create
such many-to-many relationships Roo offers the field set command:
~.domain.Pizza roo> field set --fieldName toppings --type ~.domain.Topping
As you can see it is easy to define this relationship even without knowing about the exact JPA
annotations needed to create this mapping in our Pizza domain entity. In a similar way you can
define the m:1 relationship between the Pizza and Base domain entities by using the field reference
command:
~.domain.Pizza roo> field reference --fieldName base --type ~.domain.Base
In a similar fashion we can then continue to create the PizzaOrder domain object and add its fields by
leveraging the field date and field number commands:
entity jpa --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date
field set --fieldName pizzas --type ~.domain.Pizza
1.3.2.RELEASE
17
-----------------------------------------------------------------------BUILD SUCCESS
-----------------------------------------------------------------------Total time: 3.860s
Finished at: Tue Feb 14 18:01:45 EST 2012
Final Memory: 6M/81M
------------------------------------------------------------------------
As you can see Roo has issued a Maven command (equivalent to running 'mvn test' outside the Roo
shell) in order to execute the integration tests. All tests have passed, Roo has generated 9 integration
tests per domain object resulting in a total of 36 integration tests for all 4 domain objects.
1.3.2.RELEASE
18
-----------------------------------------------------------------------BUILD SUCCESS
-----------------------------------------------------------------------Total time: 1.685s
Finished at: Tue Feb 14 18:04:20 EST 2012
Final Memory: 7M/81M
------------------------------------------------------------------------
Note, when issuing this command for the first time you can expect delays while Maven downloads
the dependencies and their sources into your local repository. Once this command has completed you
are ready to import your project into STS by clicking 'File > Import > General > Existing Projects
into Workspace'. Once your project is imported into STS you can take a look at the Java sources. For
example you can run the included JUnit tests by right clicking the pizzashop project and then selecting
'Run As > JUnit Test'.
If you're using STS or have installed m2eclipse into an Eclipse-based IDE, as mentioned earlier you
can skip the perform eclipse command entirely. In this case you simply need to select in STS/Eclipse
the 'File > Import > General > Maven Projects' menu option.
As detailed in the Application Architecture chapter of this documentation Roo projects leverage
AspectJ Intertype declarations extensively. This does not, however, affect your ability to use code
completion features offered by STS. To see code completion working in action you can open an existing
integration test and use the testMarkerMethod() method to test it. For example you can open the
BaseIntegrationTest.java source file and try it out:
Note, most of the methods visible in the STS code assist are actually not in the Java sources but rather
part of the AspectJ ITD and are therefore introduced into the Java bytecode at compile time.
1.3.2.RELEASE
19
This command will scan the Pizza Shop project for any domain entities and scaffold a Spring MVC
controller for each entity detected. The --package attribute is needed to specify in which package the
controllers should be installed. This command can be issued from your normal Roo shell or from the
Roo shell, which ships with STS. In order to use the integrated Roo shell within STS you need to right
click on the pizzashop application and select 'Spring Tools > Open Roo Shell'.
Note, that with the web mvc setup command the nature of the project changes from a normal Java
project nature to a Web project nature in STS. This command will also add additional dependencies
such as Spring MVC, Tiles, etc to your project. In order to update the project classpath within STS with
these new dependencies you can issue 'perform eclipse' again, followed by a project refresh in STS.
All newly added Web artifacts which are needed for the view scaffolding can be found under the src/
main/webapp folder. This folder includes graphics, cascading style sheets, Java Server pages, Tiles
configurations and more. The purpose of these folders is summarized in the UI customization section.
The Roo generated Spring MVC controllers follow the REST pattern as much as possible by leveraging
new features introduced with the release of Spring Framework v3. The following URI - Resource
mappings are applied in Roo generated controllers:
1.3.2.RELEASE
20
Note, the Roo shell will hide the security setup command until you have created a Web layer. As
shown above, the security setup command manages the project pom.xml file. This means additional
dependencies have been added to the project. To add these dependencies to the STS workspace you
should run the perform eclipse command again followed by a project refresh (if you're using STS
or m2eclipse, the "perform eclipse" command should be skipped as it will automatically detect and
handle the addition of Spring Security to your project).
1.3.2.RELEASE
21
As a next step you can use the Spring Security JSP tag library to restrict access to the relevant menu
items in the menu.jspx file:
This leaves the pizza order view visible to the public. Obviously the delete and the update use case
for the pizza order view are not desirable. The easiest way to take care of this is to adjust the
@RooWebScaffold annotation in the PizzaOrderController.java source:
@RooWebScaffold(path = "pizzaorder",
formBackingObject = PizzaOrder.class,
delete=false,
update=false)
This will trigger the Roo shell to remove the delete and the update method from the
PizzaOrderController and also adjust the relevant view artifacts.
With these steps completed you can restart the application and the 'admin' user can navigate to http://
localhost:8080/pizzashop/login to authenticate.
1.3.2.RELEASE
22
The easiest way to customize the look & feel of the Roo Web UI is to change CSS and image resources
to suit your needs. The following look & feel was created for the specific purpose of the Pizza Shop
application:
Spring Roo also configures theming support offered by Spring framework so you can leverage this
feature with ease.
To achieve a higher level of customization you can change the default Tiles template (WEB-INF/
layouts/default.jspx) and adjust the JSP pages (WEB-INF/views/*.jspx). WIth release 1.1 of Spring
1.3.2.RELEASE
23
roo>
roo>
roo>
roo>
selenium
selenium
selenium
selenium
test
test
test
test
--controller
--controller
--controller
--controller
~.web.ToppingController
~.web.BaseController
~.web.PizzaController
~.web.PizzaOrderController
The generated tests are located in the src/main/webapp/selenium folder and can be run via the
following maven command (executed from command line, not the Roo shell):
pizza> mvn selenium:selenese
Running the maven selenium addon will start a new instance of the FireFox browser and run tests
against the Pizza Shop Web UI by using Roo generated seed data.
Please note that the maven selenium plugin configured in the project pom.xml assumes that the FireFox
Web browser is already installed in your environment. Running the maven selenium plugin also
assumes that your application is already started as discussed in step 6. Finally, there are limitations
with regards to locales used by the application. Please refer to the known issues section for details.
Finally, you may wish to deploy your application to a production Web container. For this you can
easily create a war archive by taking advantage of the perform package command:
~.web roo> perform package
[INFO] Scanning for projects...
[INFO] -----------------------------------------------------------------------[INFO] Building pizzashop
[INFO]
task-segment: [package]
1.3.2.RELEASE
24
[INFO] -----------------------------------------------------------------------...
[INFO] [war:war {execution: default-war}]
[INFO] Exploding webapp...
[INFO] Assembling webapp pizzashop in /Users/stewarta/projects/roo-test/pizzashop/target/pizzashop-0.1
[INFO] Copy webapp webResources to /Users/stewarta/projects/roo-test/pizzashop/target/pizzashop-0.1.0[INFO] Generating war /Users/stewarta/projects/roo-test/pizza/target/pizzashop-0.1.0-SNAPSHOT.war
[INFO] Building war: /Users/stewarta/projects/roo-test/pizza/target/pizzashop-0.1.0-SNAPSHOT.war
[INFO] -----------------------------------------------------------------------[INFO] BUILD SUCCESS
[INFO] -----------------------------------------------------------------------[INFO] Total time: 5.881s
[INFO] Finished at: Tue Feb 14 18:07:54 EST 2012
[INFO] Final Memory: 8M/81M
[INFO] -----------------------------------------------------------------------~.web roo>
This command produces your war file which can then be easily copied into your production Web
container.
1.3.2.RELEASE
25
3.2.1. AspectJ
AspectJ is a powerful and mature aspect oriented programming (AOP) framework that underpins many
large-scale systems. Spring Framework has offered extensive support for AspectJ since 2004, with
Spring 2.0 adopting AspectJ's pointcut definition language even for expressing Spring AOP pointcuts.
1.3.2.RELEASE
26
Application Architecture
Many of the official Spring projects offer support for AspectJ or are themselves heavily dependent
on it, with several examples including Spring Security (formerly Acegi Security System for Spring),
Spring Insight, SpringSource tc Server, SpringSource dm Server, Spring Enterprise and Spring Roo.
While AspectJ is most commonly known for its aspect oriented programming (AOP) features such as
applying advice at defined pointcuts, Roo projects use AspectJ's powerful inter-type declaration (ITD)
features. This is where the real magic of Roo comes from, as it allows us to code generate members
(artifacts like methods, fields etc) in a different compilation unit (i.e. source file) from the normal .java
code you'd write as a developer. Because the generated code is in a separate file, we can maintain
that file's lifecycle and contents completely independently of whatever you are doing to the .java files.
Your .java files do not need to do anything unnatural like reference the generated ITD file and the
whole process is completely transparent.
Let's have a look at how ITDs work. In a new directory, type the following commands and note the
console output:
roo> project --topLevelPackage com.aspectj.rocks
roo> jpa setup --database HYPERSONIC_IN_MEMORY --provider HIBERNATE
roo> entity jpa --class ~.Hello
Created SRC_MAIN_JAVA/com/aspectj/rocks
Created SRC_MAIN_JAVA/com/aspectj/rocks/Hello.java
Created SRC_MAIN_JAVA/com/aspectj/rocks/Hello_Roo_JpaActiveRecord.aj
Created SRC_MAIN_JAVA/com/aspectj/rocks/Hello_Roo_JpaEntity.aj
Created SRC_MAIN_JAVA/com/aspectj/rocks/Hello_Roo_ToString.aj
Created SRC_MAIN_JAVA/com/aspectj/rocks/Hello_Roo_Configurable.aj
roo> field string --fieldName comment
Managed SRC_MAIN_JAVA/com/aspectj/rocks/Hello.java
Managed SRC_MAIN_JAVA/com/aspectj/rocks/Hello_Roo_JavaBean.aj
Managed SRC_MAIN_JAVA/com/aspectj/rocks/Hello_Roo_ToString.aj
Notice how there is a standard Hello.java file, as well as a series of Hello_Roo_*.aj files. Any file
ending in *_Roo_*.aj is an AspectJ ITD and will be managed by Roo. You should not edit these files
directly, as Roo will automatically maintain them (this includes even deleting files that aren't required,
as we'll see shortly).
The Hello.java is just a normal Java file. It looks like this:
package com.aspectj.rocks;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.tostring.RooToString;
import org.springframework.roo.addon.entity.RooJpaActiveRecord;
@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class Hello {
private String comment;
}
As shown, there's very little in the .java file. There are some annotations, plus of course the field we
added. Note that Roo annotations are always source-level retention, meaning they're not compiled into
your .class file. Also, as per our usability goals you'll note that Roo annotations also always start
with @Roo* to help you find them with code assist.
By this stage you're probably wondering what the ITD files look like. Let's have a look at one of them,
Hello_Roo_ToString.aj:
1.3.2.RELEASE
27
Application Architecture
package com.aspectj.rocks;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
privileged aspect Hello_Roo_ToString {
public String Hello.toString() {
return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
Notice how the ITD is very similar to Java code. The main differences are that it is declared with
"privileged aspect", plus each member identifies the target type (in this case it is "Hello.toString",
which means add the "toString" method to the "Hello" type). The compiler will automatically
recognize these ITD files and cause the correct members to be compiled into Hello.class. We can see
that quite easily by using Java's javap command. All we need to do is run the compiler and view the
resulting class. From the same directory as you created the project in, enter the following commands
and observe the final output:
$ mvn compile
$ javap -classpath target/classes/.:target/test-classes/. com.aspectj.rocks.Hello
Compiled from "Hello.java"
public class com.aspectj.rocks.Hello extends java.lang.Object implements org.springframework.beans.fac
transient javax.persistence.EntityManager entityManager;
public com.aspectj.rocks.Hello();
public static java.lang.String ajc$get$comment(com.aspectj.rocks.Hello);
public static void ajc$set$comment(com.aspectj.rocks.Hello, java.lang.String);
public static java.lang.Long ajc$get$id(com.aspectj.rocks.Hello);
public static void ajc$set$id(com.aspectj.rocks.Hello, java.lang.Long);
public static java.lang.Integer ajc$get$version(com.aspectj.rocks.Hello);
public static void ajc$set$version(com.aspectj.rocks.Hello, java.lang.Integer);
static {};
public static long countHelloes();
public static final javax.persistence.EntityManager entityManager();
public static java.util.List findAllHelloes();
public static com.aspectj.rocks.Hello findHello(java.lang.Long);
public static java.util.List findHelloEntries(int, int);
public void flush();
public java.lang.String getComment();
public java.lang.Long getId();
public java.lang.Integer getVersion();
public com.aspectj.rocks.Hello merge();
public void persist();
public void remove();
public void setComment(java.lang.String);
public void setId(java.lang.Long);
public void setVersion(java.lang.Integer);
public java.lang.String toString();
}
While the javap output might look a little daunting at first, it represents all the members that
Roo has added (via AspectJ ITDs) to the original Hello.java file. Notice there isn't just the
toString method we saw in the earlier ITD, but we've also made the Hello class implement
Spring's ConfigurableObject interface, provided access to a JPA EntityManager, included a range
of convenient persistence methods plus even getters and setters. All of these useful features are
automatically maintained in a round-trip compatible manner via the ITDs.
A careful reader might be wondering about the long field names seen for introduced fields. You can
see that these field names start with "ajc$" in the output above. The reason for this is to avoid name
1.3.2.RELEASE
28
Application Architecture
collisions with fields you might have in the .java file. The good news is that you won't ever need
to deal with this unless you're trying to do something clever with reflection. It's just something to be
aware of for introduced fields in particular. Note that the names of methods and constructors are never
modified.
Naturally as a normal Roo user you won't need to worry about the internals of ITD source code and
the resulting .class files. Roo automatically manages all ITDs for you and you never need deal with
them directly. It's just nice to know how it all works under the hood (Roo doesn't believe in magic!).
The benefit of this ITD approach is how easily and gracefully Roo can handle code generation for you.
To see this in action, go and edit the Hello.java in your favourite text editor with Roo
running. Do something simple like add a new field. You'll notice the Hello_Roo_ToString.aj and
Hello_Roo_JavaBean.aj files are instantly and automatically updated by Roo to include your new
field. Now go and write your own toString method in the .java file. Notice Roo deletes the
Hello_Roo_ToString.aj file, as it detects your toString method should take priority over a generated
toString method. But let's say you want a generated toString as well, so change the Hello.java's
@RooToString annotation to read @RooToString(toStringMethod="generatedToString"). Now
you'll notice the Hello_Roo_ToString.aj file is immediately re-created, but this time it introduces
a generatedToString method instead of the original toString. If you comment out both fields in
Hello.java you'll also see that Roo deletes both ITDs. You can also see the same effect by quitting
the Roo shell, making any changes you like, then restarting the Roo shell. Upon restart Roo will
automatically perform a scan and discover if it needs to make any changes.
Despite the admittedly impressive nature of ITDs, AspectJ is also pretty good at aspect oriented
programming features like pointcuts and advice! To this end Roo applications also use AspectJ for all
other AOP requirements. It is AspectJ that provides the AOP so that classes are dependency injected
with singletons when instantiated and transactional services are called as part of method invocations.
All Roo applications are preconfigured to use the Spring Aspects project, which ships as part of Spring
Framework and represents a comprehensive "aspect library" for AspectJ.
3.2.2. Spring
Spring Roo applications all use Spring. By "Spring" we not only mean Spring Framework, but also the
other Spring projects like Spring Security and Spring Web Flow. Of course, only Spring Framework
is installed into a user project by default and there are fine-grained commands provided to install each
additional Spring project beyond Spring Framework.
All Roo applications use Spring Aspects, which was mentioned in the AspectJ section and ensures
Spring Framework's @Configurable dependency injection and transactional advice is applied.
Furthermore, Roo applications use Spring's annotation-driven component scanning by default and
also rely on Spring Framework for instantiation and dependency injection of features such as JPA
providers and access to database connection pools. Many of the optional features that can be used
in Roo applications (like JMS and SMTP messaging) are also built upon the corresponding Spring
Framework dependency injection support and portable service abstractions.
Those Roo applications that include a web controller will also receive Spring Framework 3's MVC
features such as its conversion API, web content negotiation view resolution and REST support. It is
possible (and indeed encouraged) to write your own web Spring MVC controllers in Roo applications,
and you are also free to use alternate page rendering technologies if you wish (i.e. not just JSP).
Generally speaking Roo will not modify any Spring-related configuration or setting file (e.g.
properties) unless specifically requested via a shell command. Roo also ensures that whenever it
1.3.2.RELEASE
29
Application Architecture
creates, modifies or deletes a file it explicitly tells you about this via a shell message. What this means
is you can safely edit your Spring application context files at any time and without telling Roo. This
is very useful if the default configuration offered by Roo is unsuitable for your particular application's
needs.
Because Spring projects are so extensively documented, and Roo just uses Spring features in the normal
manner, we'll refrain from duplicating Spring's documentation in this section. Instead please refer to
the excellent Spring documentation for guidance, which can be found in the downloadable distribution
files and also on the Spring web site.
org.springframework.roo.addon.javabean.RooJavaBean;
org.springframework.roo.addon.tostring.RooToString;
org.springframework.roo.addon.entity.RooJpaActiveRecord;
javax.validation.constraints.NotNull;
javax.validation.constraints.Size;
@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class Choice {
@NotNull
@Size(min = 1, max = 30)
private String namingChoice;
@Size(max = 80)
private String description;
}
The above entity is simply a JPA entity that contains two fields. The two fields are annotated with
JavaBean Validation API (JSR 303) annotations, which are useful if your JPA provider supports this
standard (as is the case if you nominate Hibernate as your JPA provider) or you are using a Rooscaffolded web application front end (in which case Roo will use Spring Framework 3's JSR 303
support). Of course you do not need to use the JavaBean Validation API annotations at all, but if you
1.3.2.RELEASE
30
Application Architecture
would like to use them the relevant Roo field commands provide tab-completion compatible options
for each. The first time you use one of these Roo field commands, Roo will add required JavaBean
Validation API libraries to your project (i.e. these libraries will not be in your project until you decide
to first use JavaBean Validation).
What's interesting about the above entity is what you can actually do with it. There are a series of
methods automatically added into the Choice.class courtesy of Roo code-generated and maintained
AspectJ ITDs. These include static methods for retrieving instances of Choice, JPA facade methods
for persisting, removing, merging and flushing the entity, plus accessors and mutators for both the
identifier and version properties. You can fine-tune these settings by modifying attributes on the
@RooJpaActiveRecord annotation. You can also have Roo remove these services by simply removing
the @RooJpaActiveRecord annotation from the class, in which case you'll be left with a normal JPA
@Entity that you'll need to manage by hand (e.g. provide your own persistence methods, identifier,
version etc).
The @RooJavaBean annotation causes an accessor and mutator (getter and setter) to automatically be
generated for each field in the class. These accessors and mutators are automatically maintained in
an AspectJ ITD by Roo. If you write your own accessor or mutator in the normal .java file, Roo will
automatically remove the corresponding generated method from the ITD. You can also remove the
@RooJavaBean annotation if you don't want any generated accessors or mutators (although those related
to the version and identifier fields will remain, as they are associated with @RooJpaActiveRecord
instead of @RooJavaBean).
Finally, the @RooToString annotation causes Roo to create and maintain a public String toString()
method in a separate ITD. This method currently is used by any scaffolded web controllers if they
need to display a related entity. The generated method takes care to avoid circular references that
are commonly seen in bidirectional relationships involving collections. The method also formats Java
Calendar objects in an attractive manner. As always, you can write your own toString() method by
hand and Roo will automatically remove its generated toString() method, even if you still have the
@RooToString annotation present. You can of course also remove the @RooToString annotation if you
no longer wish to have a generated toString() method.
Before leaving this discussion on entities, it's worth mentioning that you are free to create your own
entity .java classes by hand. You do not need to use the Roo shell commands to create entities or
maintain their fields - just use any IDE. Also, you are free to use the @RooToString or @RooJavaBean
(or both) annotations on any class you like. This is especially useful if you have a number of domain
objects that are not persisted and are therefore not entities. Roo can still help you with those objects.
1.3.2.RELEASE
31
Application Architecture
team's recommended best practice architecture. In fact, the GWT team at Google wrote most of the
Roo GWT add-on, so you can be sure it uses the best GWT 2.1 features.
Scaffolded web controllers always delegate directly to methods provided on an @RooJpaActiveRecord
class. For maximum compatibility with scaffolded controllers, it is recommended to observe the default
identifier and version conventions provided by @RooJpaActiveRecord implementations. If you write
a web controller by hand (perhaps with the assistance of the web mvc controller command), it is
recommended you also use the methods directly exposed on entities. Most Roo applications will place
their business logic between the entities and web controllers, with only occasional use of services
layers. Please refer to the services layer section for a more complete treatment of when you'd use a
services layer.
1.3.2.RELEASE
32
Application Architecture
If we reflect for a moment on the main motivations for DAOs, it is easy to see why these are not
applicable in Roo applications:
Testing: In a normal application a DAO provides an interface that could be easily stubbed as part of
unit testing. The interesting point about testing is that most people use mocking instead of stubbing
in modern applications, making it attractive to simply mock the persistence method or two that you
actually require for a test (rather than the crudeness of stubbing an entire DAO interface). In Roobased applications you simply mock the persistence-related methods that have been introduced to
the entity. You can use normal mocking approaches for the instance methods on the Roo entity, and
use Spring Aspect's @MockStaticEntityMethods support for the static finder methods.
Separation of concern: One reason for having a DAO layer is that it allows a higher cohesion objectoriented design to be pursued. The high cohesion equates to a separation of concern that reduces the
conceptual weight of implementing the system. In a Roo-based application separation of concern
is achieved via the separate ITDs. The conceptual weight is also reduced because Roo handles the
persistence methods rather than force the programmer to deal with them. Therefore separation of
concern still exists in a Roo application without the requirement for a DAO layer.
Pluggable implementations: A further benefit of DAOs is they simplify the switching from one
persistence library to another. In modern applications this level of API abstraction is provided via
JPA. As Roo uses JPA in its generated methods, the ability to plug in an alternate implementation
is already fully supported despite there being no formal DAO layer. You can see this yourself by
issuing the jpa setup command and specifying alternate implementations.
Non-JPA persistence: It is possible that certain entities are stored using a technology that does not
have a JPA provider. In this case Roo does not support those entities out of the box. However, if
only a small number of entities are affected by this consideration there is no reason one or more
hand-written ITDs could not be provided by the user in order to maintain conceptual parity with
the remainder of the Roo application (which probably does have some JPA). If a large number of
entities are affected, the project would probably benefit from the user writing a Roo add-on which
will automatically manage the ITDs just as Roo does for JPA.
Security authorisation: Sometimes DAOs are used to apply security authorisation rules. It
is possible to protect persistence methods on the DAOs and therefore go relatively low
in the control flow to protecting the accessibility of entities. In practice this rarely works
well, though, as most authorisation workflows will target a use case as opposed to the
entities required to implement a use case. Further, the approach is unsafe as it is possible
to transitively acquire one entity from another without observing the authorisation rules (e.g.
person.getPartner().getChildren().get(1).setFirstName("Ben")). It is also quite crude in
that it does not support transparent persistence correctly, in that the example modification of the
first name would flush to the database without any authorisation check (assuming this mutative
operation occurred within the context of a standard transactional unit of work). While it's possible
to work around many of these issues, authorisation is far better tackled using other techniques than
the DAO layer.
Security auditing: In a similar argument to authorisation, sometimes DAOs are advocated for
auditing purposes. For the same types of reasons expressed for authorisation, this is a suboptimal
approach. A better way is to use AOP (e.g. AspectJ field set pointcuts), a JPA flush event handle,
or a trigger-like model within the database.
Finders: If you review existing DAOs, you'll find the main difference from one to another is the
finder methods they expose. Dynamic finders are automatically supported by Roo and introduced
1.3.2.RELEASE
33
Application Architecture
directly to the entity, relieving the user from needing DAOs for this reason. Furthermore, it is quite
easy to hand-write a finder within the entity (or an ITD that adds the finder to the entity if a separate
compilation unit is desired).
Architectural reasons: Often people express a preference for a DAO because they've always done
it that way. While maintaining a proven existing approach is generally desirable, adopting Roo for
an application diminishes the value of a DAO layer to such an extent that it leaves little (if any)
engineering-related reasons to preserve it.
It's also worth observing that most modern RAD frameworks avoid DAO layers and add persistence
methods directly to entities. If you compare similar technologies to Roo, you will see this avoidance
of a DAO layer is commonplace, mainstream and does not cause problems.
Naturally you can still write DAOs by hand if you want to, but the majority of Roo add-ons will not
be compatible with such DAOs. As such you will not receive automated testing or MVC controllers
that understand your hand-written DAOs. Our advice is therefore not to hand write DAOs. Simply use
the entity methods provided by @RooJpaActiveRecord, as it's engineering-wise desirable and it's also
far less effort for you to write and maintain.
If you are interested in DAO support despite the above Roo offers support for different repository
layers as of release 1.2.0. Please refer to the application layering chapter for details.
3.7. Maven
3.7.1. Packaging
Roo supports a number of Maven packaging types out of the box, such as jar, war, pom, and bundle.
These are provided via Roo's PackagingProvider interface. If you wish to customise the POMs or
other artifacts that Roo generates for a given packaging type when creating a project or module, either
for one of the above packaging types or a completely different one, you can implement your own
PackagingProvider that creates exactly the files you want with the contents you want. The procedure
for doing this is as follows:
In a new directory, start Roo and run "addon create simple" to create a simple addon.
Delete:
the four .java files created in src/main/java
the two .tagx files created in src/main/resources
Create your custom packaging class (e.g. MyPackaging.java) in your preferred package.
Pick a unique ID for the Roo shell to use when referring to your PackagingProvider (e.g. "customjar"). Do not use any of the core Maven packaging type names, as these are reserved for use by Roo.
Make your packaging class implement the o.s.r.project.packaging.PackagingProvider
interface, either by:
Implementing PackagingProvider directly, with full control over (but no assistance with) artifact
generation, or
1.3.2.RELEASE
34
Application Architecture
Extending o.s.r.project.packaging.AbstractPackagingProvider to have Roo create the
POM from a template you specify, with various substitutions made automatically (e.g. groupId
and artifactId). This approach requires you to:
Create your custom POM template in src/main/resources plus whatever package you chose
above.
Create a public no-arg constructor that calls the AbstractPackagingProvider constructor with
the following arguments:
The unique ID of your custom packaging type (see above).
The Maven name of your packaging type (typically jar/war/ear/etc, but could be something
else if you've extended Maven to support custom packaging types).
The path to your POM template relative to your concrete PackagingProvider (e.g. "mypom-template.xml" if it's in the same package). Note that this POM can contain as much or
as little content as you like, with the following caveats:
It must have the standard Maven "project" root element with all the usual namespace
details.
If you extend AbstractPackagingProvider, that class will ensure that the POM's
coordinates can be resolved either from a "parent" element or from explicit "groupId",
"artifactId", and "version" elements.
Add the Felix annotations @Component and @Service to your concrete PackagingProvider, so that
it's detected by Roo's PackagingProviderRegistry.
Build and install the addon in the usual way, i.e.:
Run "mvn install" in the addon directory to create the OSGi bundle.
Change to the directory of the project that will be using the custom packaging provider.
Run
"osgi
start
--url
file:///path/to/addon/project/target/
com.example.foo-0.1.0.BUILD-SNAPSHOT.jar"
Run "osgi scr list"; your custom PackagingProvider component should appear somewhere
in the list.
Whenever you run the "project" or "module create" commands, your custom PackagingProvider's
ID should appear in the list of possible completions for the "--packaging" option
1.3.2.RELEASE
35
Application Architecture
Change into the "ui/mvc"" directory.
Run "mvn tomcat:run" or "mvn jetty:run".
Point your browser to http://localhost:8080/mvc.
The rest of this section assumes that you are familiar with multi-module projects, in particular the
difference between POM inheritance (one POM has another as its parent) and project nesting (one
project is in a sub-directory of another, i.e. is a module of that parent project).
3.7.2.1. Features
Roo's multi-module support has the following features (a formal list of Roo's Maven-related commands
appears in Appendix C):
Roo now has the concept of a module, which in practice means a directory tree whose root contains
a Maven POM. A project consists of zero or more modules. When you run Roo from the operating
system prompt, you do so from the directory of the root module.
Once any modules exist, one of them always has the "focus", in other words will be used as the
context for any shell commands that interact with the user project (as opposed to housekeeping
commands such as "osgi ps"). For example, running the "web flow" command will add Spring
Web Flow support to the currently focused module.
The "module focus" command, available once the project contains more than one module, changes
the currently focused module. Tab completion is available, with the module name "~" signifying
the root module.
The "module create" command creates a new module as a sub-directory of the currently focused
module. The latter module's POM will be updated to ensure it has "pom" packaging, allowing the
Maven reactor to properly recurse the module tree at build time. Note that the newly created POM
will by default not inherit from the parent module's POM. If the new module's POM should have
a parent, specify it via the "module create" command's optional "parent" parameter. The parent
POM need not be located within the user project. A typical use case is that a development team
might have a standard base POM from which all their projects inherit, or a standard web POM from
which all their web modules inherit. As with the "project" command, the new module's Maven
packaging can be specified via the optional "packaging" parameter. Custom packaging behaviour
is supported, as described above.
3.7.2.2. Limitations
Roo's multi-module support has the following limitations:
Limited automatic creation of dependencies between modules. If your project needs any intermodule dependencies beyond those added by Roo, simply create them using the "dependency add"
command.
No command for removing a module; this is in line with the absence of commands for removing
other project artifacts such as classes, enums, JSPs, and POMs. In any event, it's simple enough to do
manually; just delete the directory, delete the relevant "<module>" element from the parent module's
POM, and delete the module as a dependency from any other modules' POMs.
One area where there's considerable scope for improvement is in the management of
dependencies in general. In an ideal Maven project, dependency information in the form of both
1.3.2.RELEASE
36
Application Architecture
"dependencyManagement" entries and live "dependency" elements themselves would be pushed as
far up the POM inheritance hierarchy as possible, in order to minimise duplication and reduce the
incidence of version conflicts. As it stands, Roo adds and removes dependencies to and from the
currently focused module in response to shell commands, regardless of what dependencies are in
effect for other modules in the project.
Likewise, plugin management is currently quite basic. Roo adds/removes plugins to the POM of
the currently focused module with no attempt to rationalise them in concert with the POMs of other
modules (for example, two Spring MVC modules will independently have the Jetty plugin declared
in their own POMs rather than having this plugin declared in the lowest common ancestor POM).
As with dependencies (see above), this is an area in which Roo could conceivably take some of the
load off developers.
There's no Roo command for changing a modules packaging between two arbitrary values, as this
could require too many other changes to the users project. However, Roo does change a module's
packaging in two specific circumstances:
Adding a module to the currently focused module changes the latter's packaging to "pom", as
described above under the "module create" command.
Adding web support to a module changes its packaging to "war".
Roo does not create any parent-child relationships between different modules Spring application
contexts; the user can always create these relationships manually, and Roo will not remove them.
1.3.2.RELEASE
37
1.3.2.RELEASE
38
1.3.2.RELEASE
39
1.3.2.RELEASE
40
1.3.2.RELEASE
41
1.3.2.RELEASE
42
1.3.2.RELEASE
43
1.3.2.RELEASE
44
Essentially you need to decide if you trust the PGP key ID or not. There is a pgp key view
command that will help you learn more about a given key ID if you would like to use it. You
can also view keys at public PGP key servers such as http://pgp.mit.edu/. You essentially have
two options to cause an untrusted httppgp download to be performed by Roo:
1. Use the pgp trust command to trust the PGP key ID shown in the error message. This will
permanently trust the key ID, and it will show up if you use the pgp list trusted keys command
(you can of course remove it via the pgp untrust command as well). All of the keys you trust
are stored in ~/.spring_roo_pgp.bpg, which is a binary encoded PGP key store which you
can also view and manage using normal PGP tools. An example of the command to trust a
key is shown below:
roo> pgp trust --keyId 0xC3A61B10
2. Alternately, you can decide to simply switch off key verification and automatically trust any
keys encountered. Such keys are stored in your ~/.spring_roo_pgp.bpg file. You should use
caution with this command, although it can be convenient if you'd simply like to install some
new add-ons and their dependencies without considering every key used to sign them. To use
automatic trust, simply type pgp automatic trust and press enter:
roo> pgp automatic trust
Automatic PGP key trusting enabled (this is potentially unsafe);
disable by typing 'pgp automatic trust' again
Once one of the above have been completed, you can repeat the command that attempted to
download a httppgp:// resource and it should succeed.
It is easy to extend the capabilities of Spring Roo with installable add-ons. This section will offer
a basic overview of Roo's add-on distribution model and explain how to install new add-ons. If
you're considering writing an add-on, please refer to the more advanced information in Part III of this
reference guide.
First of all, it's important to recognize that Roo ships with a large number of base add-ons. These builtin add-ons may be all you ever require. Nevertheless, there is a growing community of add-ons written
1.3.2.RELEASE
45
addon search
found, sorted by rank; T = trusted developer; R = Roo 1.1 compatible
R DESCRIPTION ------------------------------------------------------------Y 2.3.0.0001 This bundle wraps the standard Maven artifact:
protobuf-java-2.3.0-lite.
02 Y - 0.3.0.RELEASE Addon for Spring Roo to provide generic DAO and query
methods based on Hades.
03 Y Y 0.9.94.0001 This bundle wraps the standard Maven artifact:
jline-0.9.94.S2-A (S2-A is a private patched version; see ROO-350 for...
04 - - 1.1.6 Addons that adds Content Negotiating View Resolver configuration
to your application context: MVC multiple representations By default...
...(output truncated for reference guide inclusion)...
1.3.2.RELEASE
46
There are various options you can pass to the search command to see more lines per result, perform
filtering and so on. Just use --TAB as usual to see these options.
If you can't see the add-on you're looking for, you can repeat the command with the optional --refresh
option. This will refresh your local RooBot index from our server.
To review details about a specific add-on, use the addon info id command as mentioned in the hint
at the bottom of the search results. There is also a related command called addon info bundle which
requires a "bundle symbolic name", which is usually the add-on's top-level package. However, it's
often more convenient to use the search result "ID" number (to the left hand side of each row) rather
than typing out a bundle symbolic name. Let's try this. To view details about the second add-on listed,
enter this command:
roo> addon info id --searchResultId 02
In the above output "BSN" means bundle symbolic name, which is the alternate way of referring to a
given add-on. The output also shows you the Roo shell commands that are available via the add-on.
These commands are automatically seen by the Roo shell, so if you typed in this case "hades install"
without first having installed the add-on, Roo would have performed a search and shown you this addon offered the command. This is a great feature and means you can often just type commands you
think you might need and find out which add-ons offer them without performing an explicit search. A
similar feature exists for JDBC resolution if you try to reverse engineer a database for which there is
no installed JDBC driver (Roo will automatically suggest the add-on you need and instruct you which
command to use to install it).
If you decide to install a specific add-on, simply use the addon install id command:
1.3.2.RELEASE
47
If you don't define a stability level through the addon upgrade settings command it defaults to
RELEASE - meaning only release versions will be upgraded (if upgrades for this level are available).
Other stability levels to choose from are RELEASE_CANDIDATE, MILESTONE, and ANY (i.e.
snapshots).
To list all available upgrades for currently installed add-ons you can use the addon upgrade available
command. This will provide an overview of add-ons which can be upgraded and their respective
stability levels. Furthermore, you can also upgrade individual add-ons by using the addon upgrade
bundle command which allows you to specify the add-on bundle symbolic name (and the add-on
version in case multiple versions are available). Finally, you can use the addon upgrade id command
to upgrade a specific add-on which has appeared in a search result to the latest version available.
Of course, you can remove add-ons as well. To uninstall any given add-on, just use the addon
remove command. On this occasion we'll use the bundle symbolic name (which is available via TAB
completion as is usual with Roo):
roo> addon remove --bundleSymbolicName de.saxsys.roo.equals.addon
Successfully removed add-on: de.saxsys.roo.equals.addon
Note that all of the "addon" commands only work with add-ons listed in the central RooBot index file.
This is fine, as most public Roo add-ons are listed there. However, sometimes an add-on cannot be
published into the RooBot index file. The most common reason is that it's an add-on internal to your
organization, or perhaps it's simply not ready for public consumption.
Even if an add-on is not listed in RooBot, you can still install it. The "osgi obr url add" command can
be used to add the add-on's OBR URL to your Roo installation. This command is typically followed
by an "osgi obr start" command to download and start the add-on. Importantly, the additional security
verifications performed by RooBot are skipped given RooBot is not used with these commands (or
other related commands such as osgi start). That means bundles you start using the "osgi obr start"
command may not use httppgp:// for PGP signature verification. As such you should exercise caution
when using any installation-related commands that do not start with "addon", as such commands do
1.3.2.RELEASE
48
1.3.2.RELEASE
49
1.3.2.RELEASE
50
1.3.2.RELEASE
51
Removing Roo
1.3.2.RELEASE
52
Removing Roo
themselves and no longer enjoy optimised Roo commands, you'll likely find that over time you lose
some of the consistency and engineering advantages of having used Roo in the first place.
Higher cost: With the above in mind, you'll probably find development takes longer, maintenance
takes longer and your runtime solution will be less efficient than if you'd stayed with Roo.
As such we believe using Roo and continuing to use Roo makes a lot of sense. But if you're willing
to accept the trade-offs of removing Roo (which basically means you switch to writing your project
the unproductive "old fashioned way"), you can remove Roo very easily. Don't forget when in doubt
you can always defer the decision. It's not as if Roo won't let you remove it just as easily in six months
or two years from now!
1.3.2.RELEASE
53
Removing Roo
> Search > File Search, containing text "\n.*[@\.]Roo[^t_]+?.*$" (without the quotes), file name
pattern "*.java" (without the quotes), ticking the "Regular expression" and "Case sensitive" checkboxes and clicking "Replace". When the next window appears and asks you for a replacement pattern,
leave it blank and continue. All of the Roo statements will have now been removed. We have noticed
for an unknown reason that sometimes this operation needs to be repeated twice in Eclipse.
1.3.2.RELEASE
54
1.3.2.RELEASE
55
1.3.2.RELEASE
56
1.3.2.RELEASE
57
Also, if you dont want Jetty (or Tomcat) to be conflicting with oracle-xe web-server, you should use
the following command: mvn jetty:run -Djetty.port=8090.
ORM Provider Options:
EclipseLink
Hibernate
1.3.2.RELEASE
58
Persistence Add-On
OpenJPA
DataNucleus 3.0
In addition, the jpa setup command accepts optional databaseName, userName and password attributes
for your convenience. However, it's not necessary to use this command. You can easily edit these
details in the database.properties file at any time. Finally, you can also specify a pre-configured
JNDI datasource via the jndiDataSource attribute.
The jpa setup command can be re-run at any time. This means you can change your ORM provider or
database when you plan to move your application between your development setup (e.g. Hibernate with
HSQLDB) to your production setup (e.g. EclipseLink with DB2). Of course this is a convenience only.
You'll naturally experience fewer deployment issues if you use the same platform for both development
and production.
Running the jpa setup command in the Roo shell takes care of configuring several aspects in your
project:
1. JPA dependencies are registered in the project pom.xml Maven configuration. It includes the JPA
API, ORM provider (and its dependencies), DB driver, Spring ORM, Spring JDBC, Commons
DBCP, and Commons Pool
2. Persistence XML configuration with a persistence-unit preconfigured based on your choice of ORM
provider and Database. Here is an example for the EclipseLink ORM provider and HSQL database:
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<properties>
<property name="eclipselink.target-database"
value="org.eclipse.persistence.platform.database.HSQLPlatform"/>
<!--value='drop-and-create-tables' to build a new database on each run;
value='create-tables' creates new tables if needed;
value='none' makes no changes to the database-->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
<property name="eclipselink.weaving" value="static"/>
</properties>
</persistence-unit>
</persistence>
By default the persistence unit is configured to build a new database on each application restart.
This helps to avoid data inconsistencies during application development when the domain model
is not yet finalized (new fields added to an entity will yield new table columns). If you feel that
your domain model is stable you can manually switch to a mode which allows data persistence
across application restarts in the persistence.xml file. This is documented in the comment above the
relevant property. Each ORM provider uses different property names and values to achieve this.
3. A database properties file (src/main/resources/META-INF/spring/database.properties)
which contains user name, password, JDBC driver name and connection URL details:
1.3.2.RELEASE
59
Persistence Add-On
database.url=jdbc\:hsqldb\:mem\:foo
database.username=sa
database.password=
database.driverClassName=org.hsqldb.jdbcDriver
This file can be edited manually, or you can use the properties set command, or by using the
databaseName, userName and password attributes of the jpa setup command. You can edit the
properties file or use any of these commands at any time.
4. A DataSource definition and a transaction manager are added to the Spring application context:
[...]
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
</bean>
As you can see from the Roo shell messages there are 6 files generated (also, note that the context has
changed to the Person type in the Roo shell):
1. Person.java:
@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class Person {
}
You will notice that by default, the Person type does not contain any fields (these will be added
with the field commands or manually in the type) or methods.
1.3.2.RELEASE
60
Persistence Add-On
2. Person_Roo_JavaBean.aj (this will only be generated when fields are added to the Person type)
The first annotation added by the entity jpa command is the @RooJavaBean annotation. This
annotation will automatically add public accessors and mutators via an ITD for each field added to
the Person type. This annotation (like all Roo annotations) has source retention (so it will not be
present in the generated byte code).
3. Person_Roo_ToString.aj
The second annotation added to the Person type is the @RooToString annotation. This annotation
will generate a toString method for the Person type via an ITD. The toString() method will
contain a concatenated representation of all field names and their values using the commonslang RefectionToStringBuilder by default. If you want to provide your own toString() method
alongside the Roo generated toString() method you can declare the toStringMethod attribute in the
@RooToString annotation. This attribute allows you to change the default method name of the
Roo-managed toString() (default name) method, thereby allowing your custom toString() method
alongside the Roo-managed method.
4. Person_Roo_Configurable.aj
This ITD is automatically created and does not require the @RooConfigurable annotation to
be introduced into the Person.java type. It takes care of marking the Person type with Spring's
@Configurable annotation. This annotation allows you to inject any types from the Spring bean
factory into the Person type. The injection of the JPA entity manager (which is defined as a bean in
the application context) is possible due to the presence of the @Configurable annotation.
5. Person_Roo_Jpa_Entity.aj
The forth annotation is the @RooJpaActiveRecord annotation. This annotation triggers the creation
of two ITDs: the Person_Roo_Jpa_Entity.aj ITD and the Person_Roo_Jpa_ActiveRecord.aj ITD.
Note that If you do not want ActiveRecord-style methods in your domain object you can just use
the @RooJpaEntity annotation.
The JPA @Entity annotation is added to the Person_Roo_Jpa_Entity.aj ITD. This annotation marks
the Person as persistable. By default, the JPA implementation of your choice will create a table
definition in your database for this type. Once fields are added to the Person type, they will be added
as columns to the Person table.
privileged aspect Person_Roo_Jpa_Entity {
declare @type: Person: @Entity;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long Person.id;
@Version
@Column(name = "version")
private Integer Person.version;
public Long Person.getId() {
return this.id;
}
public void Person.setId(Long id) {
this.id = id;
1.3.2.RELEASE
61
Persistence Add-On
}
public Integer Person.getVersion() {
return this.version;
}
public void Person.setVersion(Integer version) {
this.version = version;
}
}
As can be seen, the Person_Roo_Jpa_Entity.aj ITD introduces two fields by default. An id field
(which is auto-incremented) and a version field (used for JPA-managed optimistic locking).
6. Person_Roo_Jpa_ActiveRecord.aj
As mentioned previously, the @RooJpaActiveRecord annotation also triggers the creation of
the Person_Roo_Jpa_ActiveRecord.aj ITD. This contains a number of persistence related CRUD
methods into your Person type via the ITD:
privileged aspect Person_Roo_Jpa_ActiveRecord {
@PersistenceContext
transient EntityManager Person.entityManager;
@Transactional
public void Person.persist() {
if (this.entityManager == null) this.entityManager = entityManager();
this.entityManager.persist(this);
}
@Transactional
public void Person.remove() {
if (this.entityManager == null) this.entityManager = entityManager();
if (this.entityManager.contains(this)) {
this.entityManager.remove(this);
} else {
Person attached = this.entityManager.find(this.getClass(), this.id);
this.entityManager.remove(attached);
}
}
@Transactional
public void Person.flush() {
if (this.entityManager == null) this.entityManager = entityManager();
this.entityManager.flush();
}
@Transactional
public Person Person.merge() {
if (this.entityManager == null) this.entityManager = entityManager();
Person merged = this.entityManager.merge(this);
this.entityManager.flush();
return merged;
}
1.3.2.RELEASE
62
Persistence Add-On
public static long Person.countPeople() {
return entityManager().createQuery("select count(o) from Person o", Long.class)
.getSingleResult();
}
@SuppressWarnings("unchecked")
public static List<Person> Person.findAllPeople() {
return entityManager().createQuery("select o from Person o", Person.class).getResultList();
}
public static Person Person.findPerson(Long id) {
if (id == null) return null;
return entityManager().find(Person.class, id);
}
@SuppressWarnings("unchecked")
public static List<Person> Person.findPersonEntries(int firstResult, int maxResults) {
return entityManager().createQuery("select o from Person o", Person.class)
.setFirstResult(firstResult).setMaxResults(maxResults).getResultList();
}
}
with
Spring's
Transaction
support
Similar to the @RooToString annotation you can change the default method name for
all persistence-related methods generated through the @RooJpaActiveRecord annotation. For
example:
@RooJpaActiveRecord(persistMethod = "save")
The entity jpa command offers a number of optional (but very useful) attributes worth mentioning. For
example the --testAutomatically attribute can be used to have Roo to generate and maintain integration
tests for the Person type (and the persistence methods generated as part of it). Furthermore, the -abstract and --extends attributes allow you to mark classes as abstract or inheritance patterns. Of
course this can also be done directly in the Java sources of the Person type but sometimes it is useful to
do this through a Roo command which can be scripted and replayed if desired. Other attributes allow
you to define the identifier field name as well as the identifier field type which, in turn, allows the use
of complex identifier types.
1.3.2.RELEASE
63
Persistence Add-On
~.Person roo>
You'll notice that the @Temporal annotation is part of the JPA specification and defines how date
values are persisted to and retrieved from the database in a transparent fashion. The @DateTimeFormat
annotation is part of the Spring framework and takes care of printing and parsing Dates to and from
String values when necessary (especially Web frontends frequently take advantage of this formatting
capability).
Also note that Roo created a Person_Roo_JavaBean.aj ITD to generate accessors and mutators for the
birthDay field and it also updated the toString() method to take the birthDay field into account.
Aside from the Date (and Calendar) type, the field command offers String, Boolean, Enum, Number,
Reference and Set types. The Reference and Set types are of special interest here since they allow you
to define relationships between your entities:
1. The field reference command will create a JPA many-to-one (default) or one-to-one relationship:
~.Person roo> field reference --fieldName car --type com.foo.Car
The field definition added to the Person type contains the appropriate JPA annotations:
@ManyToOne
@JoinColumn
private Car car;
The optional --cardinality command attribute allows you to define a one-to-one relationship (via
JPAs @OneToOne annotation) between Person and Car if you wish:
@OneToOne
@JoinColumn
private Car car;
You can add the mappedBy attribute to the @OneToOne annotation to define the FK name handled
by the inverse side (Car) of this relationship.
Consider the following constraint: when you delete a Person, any Car they have should also be
deleted, but not vice versa (i.e. you should be able to delete a Car without deleting its owner). In
the database, the foreign key should be in the "car" table.
@Entity
@RooJavaBean
@RooJpaActiveRecord
public class Person {
// Inverse side ("car" table has the FK column)
@OneToOne(cascade = CascadeType.ALL, mappedBy = "owner")
private Car car;
}
@Entity
1.3.2.RELEASE
64
Persistence Add-On
@RooJavaBean
@RooJpaActiveRecord
public class Car {
// Owning side (this table has the FK column)
@OneToOne
@JoinColumn
private Person owner;
}
If you delete a Person from the Person list, both the Person and the Car are deleted. So the cascading
works. But if you delete a Car, the transaction will roll back and you will see an exception due
it being referenced by a person. To overcome this situation you can add the following method to
your Car.java:
@PreRemove
private void preRemove() {
this.getOwner().setCar(null);
}
This hooks into the JPA lifecycle callback function and will set the reference between Person and
Car to null before attempting to remove the record.
2. The field set command will allow you to create a many-to-many (default) or a one-to-many
relationship:
field set --fieldName cars --type com.foo.Car
The field definition added to the Person type contains the appropriate JPA annotation:
@ManyToMany(cascade = CascadeType.ALL)
private Set<Car> cars = new HashSet<Car>();
To change the mapping type to one-to-many simply use the --cardinality attribute. To achieve a
true m:n relationship you will need to issue the field set commands for both sides of the relationship.
Like the entity jpa command, the field command offeres a number of optional (but very useful)
attributes worth mentioning. For example, you can change the field / column name translations with
the --column attribute. Furthermore there are a number of attributes which translate directly to their
equivalents defined in JSR 303 (Bean Validation). These attributes include --notNull, --sizeMin, -sizeMax and other related attributes. Please refer to the field command in the appendix to review the
different attributes offered.
1.3.2.RELEASE
65
9.1. Introduction
9.1.1. What are the benefits of Roo's incremental reverse engineering?
Traditional JPA reverse engineering tools are designed to introspect a database schema and produce
a Java application tier once. Roo's incremental database reverse engineering feature differs because
it has been designed to enable developers to repeatedly re-introspect a database schema and update
their Java application. For example, consider if a column or table has been dropped from the database
(or renamed). With Roo the re-introspection process would discover this and helpfully report errors
in the Java tier wherever the now-missing field or entity was referenced. In simple terms, incremental
database reverse engineering ensures Java type safety and easy application maintenance even if the
database schema is constantly evolving. Just as importantly, Roo's incremental reverse engineering
is implemented using the same unique design philosophy as the rest of Roo. This means very fast
application delivery, clutter-free .java source files, extensive usability features in the shell (such as tab
completion and hinting) and so on.
order
Order.java
line_item
LineItem.java
1.3.2.RELEASE
66
EAM_MEASUREMENT_DATA_1H
EamMeasurementData1h.java
COM-FOO\BAR
ComFooBar.java
Column name
order
order
EMPLOYEE_NUMBER
employeeNumber
USR_CNT
usrCnt
9.2. Installation
DBRE supports most of the relational databases that can be configured for Roo-managed projects
such as MySQL, MS SQL, and PostgreSQL. These drivers are auto-detected by Roo and you will
be prompted by the Roo shell to download your configured database's JDBC driver when you first
issue the database introspect or database reverse engineer commands (see Section 9.3, DBRE Add-On
commands below). For example, if you have configured your Roo project to use a MySQL database,
when the database introspect command is first issued, you will see the following console output:
roo> database introspect --schema no-schema-required
Located add-on that may offer this JDBC driver
1 found, sorted by rank; T = trusted developer; R = Roo 1.1 compatible
ID T R DESCRIPTION ------------------------------------------------------------01 Y Y 5.1.13.0001 #jdbcdriver driverclass:com.mysql.jdbc.Driver. This...
-------------------------------------------------------------------------------[HINT] use 'addon info id --searchResultId ..' to see details about a search result
[HINT] use 'addon install id --searchResultId ..' to install a specific search result, or
[HINT] use 'addon install bundle --bundleSymbolicName TAB' to install a specific add-on version
JDBC driver not available for 'com.mysql.jdbc.Driver'
You can get further information about the search result with the following command:
roo> addon info id --searchResultId 01
Alternatively, to install a different version (if available) of the driver you can use the following
command:
The JDBC driver for MySQL is immediately available for you to use. You can now enter the database
introspect and database reverse engineer commands (see Section 9.3, DBRE Add-On commands
below).
Note: currently there are no open-source JDBC drivers for Oracle or DB2 and Roo does not provide
OSGi drivers for these databases. If you are an Oracle or DB2 user, you will need to obtain an OSGi-
1.3.2.RELEASE
67
This command displays the database structure, or schema, in XML format. The --schema is
mandatory and for databases which support schemas, you can press tab to display a list of schemas
from your database. You can use the --file option to save the information to the specified file.
The --enableViews option when specified will also retrieve database views and display them with
the table information.
Notes:
The term "schema" is not used by all databases, such as MySQL and Firebird, and for these
databases the target database name is contained in the JDBC URL connection string. However the
--schema option is still required but Roo's tab assist feature will display "no-schema-required".
PostgreSQL upper case schema names are not supported.
2.
This command creates JPA entities in your project representing the tables and columns in your
database. As for the database introspect command, the --schema option is required and tab assistance
is available. You can use the --package option to specify a Java package where your entities will
be created. If you do not specify the --package option on second and subsequent executions of the
database reverse engineer command, new entities will be created in the same package as they were
previously created in.
Use the --activeRecord option to create 'Active Record' entities (default if not specified).
Use the --repository option to create Spring Data JPA Repositories for each entity. If specified as
true, the --activeRecord option is ignored.
Use the --service option to create a service layer for each entity.
Use the --testAutomatically option to create integration tests automatically for each new entity
created by reverse engineering.
1.3.2.RELEASE
68
roo> database reverse engineer --schema order --package ~.domain --excludeTables "foo* bar?"
This will reverse engineer all tables except any table whose name starts with 'foo' and any table
called bar with one extra character, such as 'bar1' or 'bars'.
You can use the --includeTables and --excludeTables option to specify tables that you want or
do not want reverse engineered respectively. The options can take one or more table names. If
more than one table is required, the tables must be enclosed in double quotes and each separated
by a space. Wild-card searching is also permitted using the asterisk (*) character to match one or
more characters or the '?' character to match exactly one character. For example:
Note: excluding tables not only prevent entities from being created but associations are also not
created in other entities. This is done to prevent compile errors in the source code.
roo> database reverse engineer --schema order --package ~.domain --includeTables "foo* bar?"
This will reverse engineer all tables who table whose name starts with 'foo' and any table called
bar with one extra character, such as 'bar1' or 'bars'.
You can also reverse engineer more than one schema by specifying a doubled-quoted spaceseparated list of schemas. Reverse engineering of foreign-key releationships between tables in
different schemas is supported. For example:
roo> database reverse engineer --schema "schema1 schema2 schema3" --package ~.domain
This will reverse engineer all tables from schemas "schema1", "schema2", and "schema3".
69
Along with the standard entity, toString, configurable ITDs, a DbManaged ITD is created if there are
more columns in the employee table apart from a primary key column. For example, if the employee
table has mandatory employee name and employee number columns, and a nullable age column the
ITD could look like this:
privileged aspect Employee_Roo_DbManaged {
@Column(name = "employee_number")
@NotNull
private String Employee.employeeNumber;
public String Employee.getEmployeeNumber() {
return this.employeeNumber;
}
public void Employee.setEmployeeNumber(String employeeNumber) {
this.employeeNumber = employeeNumber;
}
@Column(name = "employee_name", length = "100")
@NotNull
private String Employee.employeeName;
public String Employee.getEmployeeName() {
return this.employeeName;
}
public void Employee.setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
@Column(name = "age")
private Integer Employee.age;
public Integer Employee.getAge() {
return this.age;
}
public void Employee.setAge(Integer age) {
this.age = age;
}
...
}
1.3.2.RELEASE
70
@RooIdentifier(dbManaged = true)
public class LineItemPK {
}
Roo will automatically create the JPA entity ITD containing a field annotated with @EmbeddedId
with type LineItemPK as follows:
privileged aspect LineItem_Roo_JpaEntity {
declare @type: LineItem: @Entity;
declare @type: LineItem: @Table(name = "line_item", schema = "order");
@EmbeddedId
private LineItemPK LineItem.id;
public LineItemPK LineItem.getId() {
return this.id;
}
public void LineItem.setId(LineItemPK id) {
this.id = id;
}
...
}
1.3.2.RELEASE
71
If you decide that your table does not require a composite primary key anymore, the next time you
execute the database reverse engineer command, Roo will automatically change the entity to use a
single primary key and remove the identifier class if it is permitted.
1.3.2.RELEASE
72
DBRE will also create many-to-many associations where the two tables each have composite primary
keys. For example:
privileged aspect Foo_Roo_DbManaged {
@ManyToMany
@JoinTable(name = "foo_bar",
joinColumns = {
@JoinColumn(name = "foo_bar_id1",
@JoinColumn(name = "foo_bar_id2",
inverseJoinColumns = {
@JoinColumn(name = "foo_bar_id1",
@JoinColumn(name = "foo_bar_id2",
private Set<Bar> Foo.bars;
referencedColumnName = "foo_id1"),
referencedColumnName = "foo_id2") },
referencedColumnName = "bar_id1"),
referencedColumnName = "bar_id2") })
...
}
1.3.2.RELEASE
73
referencedColumnName = "foo_id1"),
referencedColumnName = "foo_id2") },
referencedColumnName = "bar_id1"),
referencedColumnName = "bar_id2") })
referencedColumnName = "foo_id1"),
referencedColumnName = "foo_id2") },
referencedColumnName = "bar_id1"),
referencedColumnName = "bar_id2") })
...
}
1.3.2.RELEASE
74
9.6. Troubleshooting
This section explains scenarios that may be encountered when using the DBRE feature.
Executing the database introspect or database reverse engineer commands causes the message
'JDBC driver not available for oracle.jdbc.OracleDriver' to be displayed
This is due to the Oracle JDBC driver not having been installed. The driver must be installed if
you have installed Roo for the first time. See Section 9.2, Installation. This also applies to other
databases, for example, HSQL and H2.
Executing the database introspect or database reverse engineer commands with the
Firebird database configured causes the message 'Exception in thread "JLine Shell"
java.lang.NoClassDefFoundError: javax/resource/ResourceException' to be displayed
This is due to the javax.resource connector jar not installed. Remove the cache directory under your
Roo installation directory, start the Roo shell, and run the command:
1.3.2.RELEASE
75
1.3.2.RELEASE
76
Note: This section provides an overview of the application layering options Spring Roo offers
since the 1.2.0.M1 release. It does not discuss the merits of different approaches to architecting
enterprise applications.
While there are a number of new layering and persistence choices available, by default Roo will
continue to support the JPA Active Record Entity by default (marked orange). However, you can easily
change existing applications by adding further service or repository layers (details below). If you add
new layers Roo will automatically change its ITDs in the consumer layer or service layer respectively.
For example it will automatically inject and call a new service layer within an existing MVC controller,
Integration test or data on demand for a given domain type.
1.3.2.RELEASE
77
Application Layering
This configures your project to use the Hibername object relational mapper along with a in-memory
database (HSQLDB). Further details about this persistence option can be found here.
Active record-style JPA entities supported by Roo need to have a @RooJpaActiveRecord annotation
which takes care of providing an ID field along with its accessor and mutator, In addition this annotation
creates the typical CRUD methods to support data access.
roo> entity jpa --class ~.domain.Pizza
This command will create a Pizza domain type along with active record-style methods to persist,
update, read and delete your entity. The following example also contains a number of fields which can
be added through the field command via the Roo shell.
@RooJavaBean
@RooToString
@RooJpaActiveRecord
public class Pizza {
@NotNull
@Size(min = 2)
private String name;
private BigDecimal price;
@ManyToMany(cascade = CascadeType.ALL)
private Set<Topping> toppings = new HashSet<Topping>();
@ManyToOne
private Base base;
}
Further details about command options and functionalities provided by active record-style JPA Entities
please refer to the Persistence Add-on chapter.
By defining --activeRecord false you can opt out of the otherwise default Active Record style. The
following example also contains a number of fields which can be added through the field command
via the Roo shell.
@RooJavaBean
@RooToString
1.3.2.RELEASE
78
Application Layering
@RooJpaEntity
public class Pizza {
@NotNull
@Size(min = 2)
private String name;
private BigDecimal price;
@ManyToMany(cascade = CascadeType.ALL)
private Set<Topping> toppings = new HashSet<Topping>();
@ManyToOne
private Base base;
}
With a domain type in place you can now create a new repository for this type by using the repository
jpa command:
roo> repository jpa --interface ~.repository.PizzaRepository --entity ~.domain.Pizza
This will create a simple interface definition which leverages Spring Data JPA:
@RooJpaRepository(domainType = Pizza.class)
public interface PizzaRepository {
}
Of course, you can simply add the @RooJpaRepository annotation on any interface by hand in lieu
of issuing the repository jpa command in the Roo shell.
The adition of the @RooJpaRepository annotation will trigger the creation of a fairly trivial AspectJ
ITD which adds an extends statement to the PizzaRepository interface resulting in the equivalent of
this interface definition:
public interface PizzaRepository extends JpaRepository<Pizza, Long> {}
Note, the JpaRepository interface is part of the Spring Data JPA API and provides all CRUD
functionality out of the box.
This will configure your Spring Application context to use a MongoDB installation running on
localhost and the default port. Optional command attributes allow you to define host, port, database
name, username and password. Furthermore, to configure your application for deployment on VMware
CloudFoundry you can use the --cloudFoundry attribute.
10.2.3.2. Entities
Once the application is configured for MongoDB support, the entity mongo and repository mongo
commands become available:
1.3.2.RELEASE
79
Application Layering
roo> entity mongo --class ~.domain.Pizza
This command will create a Pizza domain type annotated with @RooMongoEntity. This annotation
is responsibe for triggering the creation of an ITD which provides a Spring Data ID annotated field as
well as its accessor and mutator. The following example also contains a number of fields which can
be added through the field command via the Roo shell.
@RooJavaBean
@RooToString
@RooMongoEntity
public class Pizza {
@NotNull
@Size(min = 2)
private String name;
private BigDecimal price;
@ManyToMany(cascade = CascadeType.ALL)
private Set<Topping> toppings = new HashSet<Topping>();
@ManyToOne
private Base base;
}
10.2.3.3. Repository
With a domain type in place you can now create a new repository for this type by using the repository
mongo command (or by applying the @RooMongoRepository annotation to an arbitrary interface:
roo> repository mongo --interface ~.repository.PizzaRepository --entity ~.domain.Pizza
This will create a simple interface definition which leverages Spring Data MongoDB:
@RooMongoRepository(domainType = Pizza.class)
public interface PizzaRepository {
List<Pizza> findAll();
}
Similar the Spring Data JPA driven repository seen above, this interface is augmented through an ITD
which introduces the PagingAndSortingRepository provided by the Spring Data API and is responsible
for providing all necessary CRUD functionality. In addition this interface defines a 'custom' finder
which is not offered by the PagingAndSortingRepository implementation: List<Pizza> findAll();. This
method iis required by Spring Roo's UI scaffolding and is automatically implemented by the query
builder mechanism offered by Spring Data MongoDB.
10.2.3.4. Example & Cloud Foundry Deployment
Similar to applications which use JPA persistence (see this blog for details on using JPA with Postgres)
MongoDB applications can be easily deployed to VMware CloudFoundry. The following script
provides an example of the Pizza Shop sample application which has been adjusted for use with a
MongoDB-backed repository layer:
// Create a new project.
project com.springsource.pizzashop
1.3.2.RELEASE
80
Application Layering
// Create configuration for MongoDB peristence
mongo setup --cloudFoundry true
// Define domain model.
entity mongo --class ~.domain.Base --testAutomatically
field string --fieldName name --sizeMin 2 --notNull --class ~.domain.Base
entity mongo --class ~.domain.Topping --testAutomatically
field string --fieldName name --sizeMin 2 --notNull --class ~.domain.Topping
entity mongo --class ~.domain.Pizza --testAutomatically
field string --fieldName name --notNull --sizeMin 2 --class ~.domain.Pizza
field number --fieldName price --type java.lang.Float
field set --fieldName toppings --type ~.domain.Topping
field reference --fieldName base --type ~.domain.Base
entity mongo --class ~.domain.PizzaOrder --testAutomatically
field string --fieldName name --notNull --sizeMin 2 --class ~.domain.PizzaOrder
field string --fieldName address --sizeMax 30
field number --fieldName total --type java.lang.Float
field date --fieldName deliveryDate --type java.util.Date
field set --fieldName pizzas --type ~.domain.Pizza
// Add layer support.
repository mongo --interface ~.repository.ToppingRepository --entity ~.domain.Topping
repository mongo --interface ~.repository.BaseRepository --entity ~.domain.Base
repository mongo --interface ~.repository.PizzaRepository --entity ~.domain.Pizza
repository mongo --interface ~.repository.PizzaOrderRepository --entity ~.domain.PizzaOrder
service type --interface ~.service.ToppingService --entity ~.domain.Topping
service type --interface ~.service.BaseService --entity ~.domain.Base
service type --interface ~.service.PizzaService --entity ~.domain.Pizza
service type --interface ~.service.PizzaOrderService --entity ~.domain.PizzaOrder
// Create a Web UI.
web mvc setup
web mvc all --package ~.web
// Package the application into a war file.
perform package
// Deploy and
cloud foundry
cloud foundry
cloud foundry
cloud foundry
cloud foundry
1.3.2.RELEASE
81
Application Layering
This command will create the PizzaService interface in the defined package and additionally a
PizzaServiceImpl in the same package (the name and package of the PizzaServiceImpl can be
customized via the optional --class attribute).
@RooService(domainTypes = { Pizza.class })
public interface PizzaService {
}
Following Roo conventions the default CRUD method definitions can be found in the ITD:
void savePizza(Pizza pizza);
Pizza findPizza(Long id);
List<Pizza> findAllPizzas();
List<Pizza> findPizzaEntries(int firstResult, int maxResults);
long countAllPizzas();
Pizza updatePizza(pizza pizza);
void deletePizza(Pizza pizza);
Through the AspectJ ITD the PizzaServiceImpl type is annotated with the @Service and
@Transactional annotations by default. Furthermore the ITD will introduce the following methods
and fields into the target type:
@Autowired PizzaRepository pizzaRepository;
public void savePizza(Pizza pizza) {
pizzaRepository.save(pizza);
}
public Pizza findPizza(Long id) {
return pizzaRepository.findOne(id);
}
public List<Pizza> findAllPizzas() {
return pizzaRepository.findAll();
}
As you can see, Roo will detect if a persistence provider layer exists for a given domain type and
automatically inject this component in order to delegate all service layer calls to this layer. In case no
persistence (or other 'lower level' layer exists, the service layer ITD will simply provide method stubs.
1.3.2.RELEASE
82
The Web MVC add-ons allow you to conveniently scaffold Spring MVC controllers and JSP(X) views
for an existing domain model. Currently this domain model is derived from the Roo supported JPA
integration through the entity jpa and related field commands. As shown in the Introduction and the
Beginning With Roo: The Tutorial the Web MVC scaffolding can deliver a fully functional Web
frontend to your domain model. The following features are included:
Automatic update of JSPX view artifacts reflecting changes in the domain model
A fully customizable set JSP of tags is provided, all tags are XML only (no tag-backing Java source
code is required)
Tags offer integration with the Dojo Ajax toolkit for client-side validation, date pickers, tool tips,
filtering selects etc
Automatic URL rewriting to provide best-practice RESTful URIs
Integration of Apache Tiles templating framework to allow for structural customization of the Web
user interface
Use of cascading stylesheets to allow for visual customization of the Web user interface
Use of Spring MVC themeing support to dynamically adjust Web user interface by changing CSS
Internationalization of complete Web UI is supported by simply adding new message bundles (6+
languages are already suppprted)
Pagination integration for large datasets
Client- and server-side validation based on JSR 303 constraints defined in the domain layer
Generated controllers offer best-practice use of Spring framework MVC support
The following sections will offer further details about available commands to generate Web MVC
artifacts and also the new JSP(X) round-tripping model introduced in Roo 1.1.
The first time the web mvc setup command is executed Roo will install all artifacts required for
the Web UI.
1.3.2.RELEASE
83
2.
The controller scaffold command will create a Spring MVC controller for the Person entity with
the following method signatures:
Method Signature
Comment
public String create(@Valid Person person, The create method is triggered by HTTP POST
BindingResult result, ModelMap modelMap) {..}
requests to /<app-name>/people. The submitted form
data will be converted to a Person object and validate
against JSR 303 constraints (if present). Response i
redirected to the show method.
public String createForm(ModelMap modelMap) {..} The create form method is triggered by a HTTP GET
request to /<app-name>/people?form. The resultin
form will be prepopulated with a new instance o
Person, referenced Cars and datepatterns (if needed)
Returns the Tiles view name.
public String show(@PathVariable("id") Long id, The show method is triggered by a HTTP GET reques
ModelMap modelMap) {..}
to /<app-name>/people/<id>. The resulting form i
populated with a Person instance identifier by the i
parameter. Returns the Tiles view name.
public String list(@RequestParam(value = "page",
required = false) Integer page, @RequestParam(value
= "size", required = false) Integer size, ModelMap
modelMap) {..}
public String update(@Valid Person person, The update method is triggered by a HTTP PUT
BindingResult result, ModelMap modelMap) {..}
request to /<app-name/people. The submitted form
data will be converted to a Person object and validate
against JSR 303 constraints (if present). Response i
redirected to the show method.
public String updateForm(@PathVariable("id") Long The update form method is triggered by a HTT
id, ModelMap modelMap) {
GET request to /<app-name>/people/<id>?form. Th
resulting form will be prepopulated with a Perso
instance identified by the id parameter, referenced Car
and datepatterns (if needed). Returns the Tiles view
name.
public String delete(@PathVariable("id") Long id,
@RequestParam(value = "page", required = false)
Integer page, @RequestParam(value = "size", required
= false) Integer size) {..}
1.3.2.RELEASE
84
Comment
void
addDateTimeFormatPatterns(ModelMap Method to register date and time patterns used for dat
modelMap) {..}
and time binding for form submissions.
As you can see Roo implements a number of methods to offer a RESTful MVC frontend to your
domain layer. All of these methods can be found in the PersonController_Roo_Controller.aj ITD.
Feel free to push-in any (or all) of these methods to change default behaviour implemented by Roo.
The web mvc scaffold command offers a number of optional attributes which let you refine
the way paths are managed and which methods should be generated in the controller. The -disallowedOperations attribute helps you refine which methods should not be generated in the
scaffolded Roo controller. If you want to prevent several methods from being generated provide
a comma-separated list (i.e.: --disallowedOperations delete,update,create). You can also specify
which methods should be generated and which not in the PersonController.java source:
@RooWebScaffold(path = "people", formBackingObject = Person.class, create = false,
update = false, delete = false)
@RequestMapping("/people")
@Controller
public class PersonController {}
If you don't define a custom path Roo will use the plural representation of the simple name of the
form backing entity (in our case 'people'). If you wish you can define more complex custom paths
like /public/people or /my/special/person/uri (try to to stick to REST patterns if you can though). A
good use case for creating controllers which map to custom paths is security. You can, for example
create two controllers for the Person entity. One with the default path (/people) for public access
(possibly with delete, and update functionality disabled) and one for admin access (/admin/people).
This way you can easily secure the /admin/* path with the Spring Security addon.
3.
The web mvc all command provides a convenient way to quickly generate Web MVC controllers
for all JPA entities Roo can find in your project. You need to specify the --package attribute to
define a package where these controllers should be generated. While the web mvc all command
is convenient, it does not give you the same level of control compared to the web mvc scaffold
command.
4.
The web mvc controller command is different from the other two controller commands shown
above. It does not generate an ITD with update, create, delete and other methods to integrate with a
specific form backing entity. Instead, this command will create a simple controller to help you get
started for developing a custom functionality by stubbing a simple get(), post() and index() method
inside the controller:
@RequestMapping("/public/car/**")
1.3.2.RELEASE
85
In addition, this controller is registered in the Web MVC menu and the application Tiles definition.
Furthermore, a simple view (under WEB-INF/views/public/car/index.jspx).
5.
The web mvc finder add command used from the Roo shell will introdroduce the @RooWebFinder
annotation into the specified target type.
6.
The web mvc finder all command used from the Roo shell will introdroduce the @RooWebFinder
annotations to all existing controllers which have a form backing type that offers dynamic finders.
<mvc:annotation-driven conversion-service="applicationConversionService"/>
...
<bean id="applicationConversionService" class="com.springsource.vote.web.ApplicationConversionServiceF
Spring MVC uses the ConversionService when it needs to convert between two objects types -- e.g.
Date and String. To become more familiar with its features we recommend that you review the (brief)
sections on "Type Conversion" and "Field Formatting" in the Spring Framework documentation.
The ApplicationConversionServiceFactoryBean is a Roo-managed Java class and it looks like this:
@RooConversionService
public class ApplicationConversionServiceFactoryBean extends FormattingConversionServiceFactoryBean {
@Override
protected void installFormatters(FormatterRegistry registry) {
super.installFormatters(registry);
// Register application converters and formatters
}
}
1.3.2.RELEASE
86
At this point Roo will notice that the addition of the method and will remove it from the ITD much
like overriding the toString() method in a Roo entity works.
Note, in some cases you may create a form backing entity which does not contain any suitable fields for
conversion. For example, the entity may only contain a field indicating a relationship to another entity
(i.e. type one-to-one or one-to-many). Since Roo does not use these fields for its generated converters it
will simply omit the creation of a converter for such form backing entities. In these cases you may have
to provide your own custom converter to convert from your entity to a suitable String representation
in order to prevent potential converter exceptions.
1.3.2.RELEASE
87
1.3.2.RELEASE
88
You will notice that this file is fairly concise compared to a normal jsp file. This is due to the extensive
use of the tag library which Roo has installed in your project in the WEB-INF/tags folder. Each tag
offeres a number of attributes which can be used to customize the appearance / behaviour of the tag
- please use code completion in your favourite editor to review the options or take a peek into the
actual tags.
All tags are completely self-reliant to provide their functionality (there are no Java sources needed to
implement specific behaviour of any tag). This should make it very easy to customize the behaviour of
the default tags without any required knowledge of traditional Java JSP tag development. You are free
to customize the contents of the Roo provided tag library to suit your own requirements. You could
even offer your customized tag library as a new addon which other Roo users could install to replace
the default Roo provided tag library.
Most tags have a few common attributes which adhere with Roo conventions to support round-tripping
of the jspx artifacts. The following rules should be considered if you wish to customize tags or jspx
files in a Roo managed project:
The id attribute is used by Roo to find existing elements and also to determine message labels used
as part of the tag implementation. Changing a tag identifier will result in another element being
generated by Roo when the Roo shell is active.
Roo provided tags are registered in the root element of the jspx document and are assigned a
namespace. You should be able to see element and attribute code completion when using a modern
IDE (i.e. SpringSource Tool Suite)
1.3.2.RELEASE
89
The hash code thus allows Roo to determine if the element is in its "original" Roo form, or if the
user has modified it in some way. If a user changes an element, the hash code will not match and this
indicates to Roo that the user has customized that specific element. Once Roo has detected such an
event, Roo will change the "z" attribute value to "user-managed". This helps clarify to the user that Roo
has adopted a "hands off" approach to that element and it's entirely the user's responsibility to maintain.
If the user wishes for Roo to take responsibility for the management of a "user-managed" element
once again, he or she can simply change the value of "z" to "?". When Roo sees this, it will replace
the questionmark character with a calculated hash code. This simple mechanism allows Roo to easily
round trip JSPX files without interfering with manual changes performed by the user. It represents a
significant enhancement from Roo 1.0 where a file was entirely user managed or entirely Roo managed.
Roo will order fields used in forms in the same sequence they appear in the domain object. The user can
freely change the sequence of form elements without interfering with Roo's round tripping approach
(Roo will honour user chosen element sequences as long as it can detect individual elements by their
id).
The user can nest Roo managed elements in in any structure he wishes without interfering with Roo
jspx round tripping. For example elements can be enclosed by HTML div or span tags to change visual
or structural appearance of a page.
Most default tags installed by Roo have a render attribute which is of boolean type. This allows users
to completely disable the rendering of a given tag (and potential sub tags). This is useful in cases where
you don't wish individual fields in a form to be presented to the user but rather have them autopopulated
through other means (i.e. input type="hidden"). The value of the render attribute can also be calculated
dynamically through the Spring Expression Language (SpEL) or normal JSP expression language. The
generated create.jspx in Roo application demonstrates this.
Scaffolding of JPA reference relationships
The Roo JSP addon will read JSR 303 (bean validation API) annotations found in a form-backing
object. The following convention is applied for the generation of create and update (and finder) forms:
1.3.2.RELEASE
90
Input
Textarea
& Input
Boolean
Checkbox
Date / Calendar (@Future & @Past are recognized) Input (with JS Date chooser)
(Spring's @DateTimeFormat in combination with the
style or pattern attributes is recognized)
Enum / @Enumerated
Select
@OneToOne
Select
@ManyToMany
Select (multi-select)
@ManyToOne
Select
@OneToMany *
* As mentioned above, Roo does not scaffold a HTML form element for the 'one' side of a
@OneToMany relationship. To make this relationship work, you need to provide a @ManyToOne
annotated field on the opposite side:
In case a field is annotated with @Pattern, the regular expression is passed on to the tag library where
it may be applied through the use of the JS framework of choice.
Automatic Scaffolding of dynamic finders
Roo will attempt to scaffold Spring MVC JSP views for all dynamic finders registered in the form
backing object. This is done by using the web mvc finder all or web mvc finder add command.
Due to file name length restrictions by many file systems (see http://en.wikipedia.org/wiki/
Comparison_of_file_systems) Roo can only generate JSP views for finders which have 244 characters
or less (including folders). If the finder name is longer than 244 characters Roo will silently skip the
generation of jsp view artifacts for the dynamic finder in question). More detail can be found in ticket
ROO-1027.
1.3.2.RELEASE
91
When this command is run for the first time in a single-module project or an empty module, the
necessary JSF artifacts are copied to the project or module such as the pom dependencies and
repositories and the web.xml file. A default PrimeFaces theme called "south-street" is configured
as well in the web.xml.
The web jsf setup command can be run as many times as you like to change the JSF implementation
and the theme.
The --implementation option when specifed allows you to chouse either the Oracle Mojarra or
Apache MyFaces JSF implementations.
The --library option has only one selectable value, being PRIMEFACES.
The --theme option lets you select one of 30 PrimeFaces themes for your UI.
1.3.2.RELEASE
92
The web jsf all command creates JSF managed beans and converters for all entities in the specified
package. A JSF XHTML page is also created in the src/main/webapp/pages directory for each entity.
3.
The web jsf scaffold command lets you create a managed bean for a particular entity in your project.
The --class option is where you specify the name of the managed bean class.
The --entity option lets you specify the entity for the managed bean and is only required if the focus
is not on the entity you want to create the managed bean for.
If you do not wish the 'create' and 'list' menu selections to appear for the entity in the menu on the
generated UI, specify false in the --includeOnMenu option.
4.
The web jsf media command is used for embedding multimedia content such as videos and music
on your JSF home page.
The --url option is where you specify the url of the the media content, such as a YouTube video.
The media player used is automaticallly selected based on the url or file extension of the media file
in the url if applicable, however, where this cannot be determined you can use the --player option
to select a suitable player.
93
1.3.2.RELEASE
94
The pgp command simply ensures the signed bundles needed by the Cloud Foundry add-on can
be installed. The addon install command instructs Roo to download and install the Cloud Foundry
support. The add-on is successfully installed once you see the Successfully installed add-on: Spring
Roo - Addon - Cloud Foundry [version: a.b.c.d] message on your screen.
As with all Roo add-ons, you could also install the Cloud Foundry add-on by simply attempting to
use it. To follow this alternate installation path, enter the pgp automatic trust command, then cloud
foundry and press enter. A list of matching add-ons will be displayed. Youll probably want to install
the first (and currently only match), so use the addon install id --searchResultId 1 command.
Alternatively you can just executing the following command which will prompt you to install the Cloud
Foundry add-on, it is still required that you enable automatic trust prior to installation.
pgp automatic trust
cloud foundry login
1.3.2.RELEASE
95
13.2.1. Logging In
cloud foundry login
This command takes in three options: email, password, and cloudControllerUrl. The
cloudControllerUrl is optional, but the when logging into Cloud Foundry for the first login the email
and password are mandatory. You aren't required to enter the email and password everytime you login,
Roo will store these locally for you. The cloudControllerUrl defaults the Cloud service provided by
VMware, api.cloudfoundry.com, but can be changed to point to private Cloud Foundry instances.
1.3.2.RELEASE
96
1.3.2.RELEASE
97
There are two other application deployed, both of which are started and bound to services. You will
also notice that a URL has been mapped to the each application and that the application that was just
deployed "new-expenses" is currently stopped and no services have been bound to it. The URL has
been created and mapped based on the application name, which is what Roo defaults to if a URL is
not provided.
1.3.2.RELEASE
98
If you were to run "cloud foundry list apps" at this point you would see that the application "newexpenses" is now bound to the MySQL service instance "misql". We should now be ready to start the
application, but before we do lets take a look at how much memory has been assigned to the application.
To do this we run "cloud foundry view app memory". When we first deployed the application no
memory value was specified so, as you can see below, the default value provisioned is 256 megabytes.
1.3.2.RELEASE
99
To verify that the application has actually started simply navigate to the URL you previously mapped
to the application, in this case it is "new-expenses.cloudfoundry.com", and you should see your
application.
1.3.2.RELEASE
100
13.3. Conclusion
Cloud Foundry is a ground breaking service and open source platform that allows developers to
maximise there productivity by not having to manage the platform to which they deploy. The initial
integration with Roo allows developers to deploy and manage their applications with very little effort
from with in the shell. In this chapter we have installed the Cloud Foundry Add-On in Roo which
enabled applications to be deployed to and managed on Cloud Foundry. We have shown how easy
Cloud Foundry makes it for the developer to take advantage of the cloud from with Roo, by going the
deployment process step-by-step. There are other commands that haven't been explicity covered by
this guide and may be expanded on in the future.
1.3.2.RELEASE
101
This method has a String parameter representing the JSON document and returns a domain type
instance if the document can be serialized by the underlying deserializer.
public static String toJsonArray(Collection<Owner> collection) {
return new JSONSerializer().exclude("*.class").serialize(collection);
}
This method will convert a collection of the target type, provided as method parameter, into a valid
JSON document containing an array.
public static Collection<Owner> fromJsonArrayToOwners(String json) {
return new JSONDeserializer<List<Owner>>().use(null,
ArrayList.class).use("values", Owner.class).deserialize(json);
}
This method will convert a JSON array document, passed in as a method parameter, into a collection
of the target type.
1.3.2.RELEASE
102
JSON Add-On
The @RooJson annotation can be used to customize the names of the methods being introduced
to the target type. Furthermore, you can disable the creation of any of the above listed methods
by providing an empty String argument for the unwanted method in the @RooJson annotation.
Example:
@RooJson(toJsonMethod="", fromJsonMethod="myOwnMethodName")
2. The json add Roo shell command will introduce the @RooJson annotation into the specified target
type.
3. The json all command will detect all domain entities in the project and annotate all of them with
the @RooJson annotation.
As you can see this method takes advantage of Spring's request mappings and will respond
to HTTP GET requests that contain an 'Accept=application/json' header. The @ResponseBody
annotation is used to serialize the JSON document.
To test the functionality with curl, you can try out the Roo "pizza shop" sample script (run roo>
script pizzashop.roo; then quit the Roo shell and start Tomcat 'mvn tomcat:run'):
curl -i -H "Accept: application/json" http://localhost:8080/pizzashop/toppings
showJson
@RequestMapping(value = "/{id}", headers = "Accept=application/json")
1.3.2.RELEASE
103
JSON Add-On
@ResponseBody
public ResponseEntity<String> ToppingController.showJson(@PathVariable("id") Long id) {
Topping topping = toppingService.findTopping(id);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
if (topping == null) {
return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<String>(topping.toJson(), headers, HttpStatus.OK);
}
This method accepts an HTTP GET request with a @PathVariable for the requested Topping
ID. The entity is serialized and returned as a JSON document if found, otherwise an HTTP 404
(NOT FOUND) status code is returned. The accompanying curl command is as follows:
curl -i -H "Accept: application/json" http://localhost:8080/pizzashop/toppings/1
createFromJson
@RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
public ResponseEntity<String> ToppingController.createFromJson(@RequestBody String json) {
Topping topping = Topping.fromJsonToTopping(json);
toppingService.saveTopping(topping);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
return new ResponseEntity<String>(headers, HttpStatus.CREATED);
}
This method accepts a JSON document sent via HTTP POST, converts it into a Topping instance,
persists that new instance, and returns an HTTP 201 (CREATED) status code. The accompanying
curl command is as follows:
curl -i -X POST -H "Content-Type: application/json" -H "Accept: application/json"
-d '{"name": "Thin Crust"}' http://localhost:8080/pizzashop/bases
createFromJsonArray
This method accepts a document containing a JSON array sent via HTTP POST and converts the
array into instances that are then persisted. The method returns an HTTP 201 (CREATED) status
code. The accompanying curl command is as follows:
curl -i -X POST -H "Content-Type: application/json" -H "Accept: application/json"
-d '[{"name":"Cheesy Crust"},{"name":"Thick Crust"}]'
http://localhost:8080/pizzashop/bases/jsonArray
updateFromJson
@RequestMapping(method = RequestMethod.PUT, headers = "Accept=application/json")
public ResponseEntity<String> ToppingController.updateFromJson(@RequestBody String json) {
HttpHeaders headers = new HttpHeaders();
1.3.2.RELEASE
104
JSON Add-On
headers.add("Content-Type", "application/json");
Topping topping = Topping.fromJsonToTopping(json);
if (toppingService.updateTopping(topping) == null) {
return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
}
return new ResponseEntity<String>(headers, HttpStatus.OK);
}
This method accepts a JSON document sent via HTTP PUT and converts it into a Topping
instance before attempting to merge it with an existing record. If no existing record is found, an
HTTP 404 (NOT FOUND) status code is sent to the client, otherwise an HTTP 200 (OK) status
code is sent. The accompanying curl command is as follows:
curl -i -X PUT -H "Content-Type: application/json" -H "Accept: application/json"
-d '{id:6,name:"Mozzarella",version:1}'
http://localhost:8080/pizzashop/toppings
updateFromJsonArray
@RequestMapping(value = "/jsonArray", method = RequestMethod.PUT,
headers = "Accept=application/json")
public ResponseEntity<String> BaseController.updateFromJsonArray(@RequestBody String json) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
for (Base base: Base.fromJsonArrayToBases(json)) {
if (baseService.updateBase(base) == null) {
return new ResponseEntity<String>(headers, HttpStatus.NOT_FOUND);
}
}
return new ResponseEntity<String>(headers, HttpStatus.OK);
}
This method accepts a document containing a JSON array sent via HTTP PUT and converts
the array into transient entities which are then merged. The method returns an HTTP 404 (NOT
FOUND) status code if any of the instances to be updated are not found, otherwise it returns an
HTTP 200 (OK) status code. The accompanying curl command is as follows:
curl -i -X PUT -H "Content-Type: application/json" -H "Accept: application/json"
-d '[{id:1,"name":"Cheesy Crust",version:0},{id:2,"name":"Thick Crust",version:0}]'
http://localhost:8080/pizzashop/bases/jsonArray
deleteFromJson
This method accepts an HTTP DELETE request with an @PathVariable identifying the Topping
instance to be deleted. HTTP status code 200 (OK) is returned if a Topping with that ID was
found, otherwise HTTP status code 404 (NOT FOUND) is returned. The accompanying curl
command is as follows:
1.3.2.RELEASE
105
JSON Add-On
curl -i -X DELETE -H "Accept: application/json" http://localhost:8080/pizzashop/toppings/1
jsonFind...
[Optional] Roo will also generate a method to retrieve a document containing a JSON array if
the form backing object defines dynamic finders. Here is an example taken from VisitController
in the pet clinic sample application, after adding JSON support to it:
This method accepts an HTTP GET request with a number of request parameters which define
the finder method as well as the finder method arguments. The accompanying curl command is
as follows:
curl -i -H Accept:application/json
http://localhost:8080/petclinic/visits?find=ByDescriptionAndVisitDate%26description=test%26v
If you need help configuring how FlexJson serializes or deserializes JSON documents, please refer to
their reference documentation.
1.3.2.RELEASE
106
This command installs the SolrJ driver dependency into the project pom.xml and registers your Solr
server in application context so it can be injected whereever you need it in your project.
2.
This command allows you to mark an individual entity for automatic Solr indexing. The
@RooSolrSearchable annotation will be added to the target entity (Person). Furthermore, the
following ITD is generated:
privileged aspect Person_Roo_SolrSearch {
@Autowired
1.3.2.RELEASE
107
1.3.2.RELEASE
108
The ITD introduces two search methods; one for conducting simple searches against Solr documents
for Person, and another one which works with a preconfigured SolrQuery object. The SolrQuery
object allows you to leverage all functionalities of the Solr search server (like faceting, sorting, term
highliting, pagination, etc).
The indexPerson(..) and indexPeople(..) methods allow you to add new person instances or even
collections of persons to the Solr index. The deleteIndex(..) method allows you to remove a person
from the Solr index.
All indexing, and delete operations are executed in s separate thread and will therefore
not impact the performance of your Web application (this is currently achieved through the
SolrSearchAsyncTaskExecutor.aj aspect).
Furthermore, to trigger automatic indexing of new person instances (or updated person instances)
this itd registers the postPersistOrUpdate() method which hooks into the JPA lifecycle through the
JPA @PostUpdate and @PostPersist annotations. Similarly, the preRemove() method hooks in the
JPA lifecylce through the @PreRemove annotation.
3.
This command will mark all entities in the project for automatic Solr indexing. The generated
functionality is the same as shown above.
This ensures each field is uniquely mapped across your domain model by prepending the entity name
followed by the field name and field type (which is used to trigger the dynamic field mapping). You
can change field names by adding a @Field annotation to a field in the domain object (i.e. Person)
which contains your own field (you need to provide a field definition in the Solr schema for it as well):
@Field("my:field:name:birthday")
@Temporal(TemporalType.TIMESTAMP)
@DateTimeFormat(style = "M-")
private Date birthDay;
1.3.2.RELEASE
109
The URL of the solr server location can be changed in the project src/main/resources/META-INF/
spring/solr.properties config file.
Front-end (controller and MVC/JSP views) are currently a work-in-progress. However, the following
Ajax Library offers a neat front-end for those who want to take this a step further: http://github.com/
evolvingweb/ajax-solr It is planned to provide a out of the box integration with the Ajax-Solr frontend through this addon in the medium term.
1.3.2.RELEASE
110
1.3.2.RELEASE
111
112
Development Processes
Every ITD-providing add-on registers a 'suffix' (namespace)
E.g. the 'Entity' add-on provides *_ROO_JPA_ACTIVE_RECORD.aj
A missing ITD provider causes AJ file removal
ITDs have proper import management
So they look and feel normal to developers
So they 'push-in refactor' in a natural form
4. Usability = Highest Priority
Interactivity of Roo Shell
Tab completion, context awareness, command hiding, hint support, etc
Background monitoring of externally made changes (allows integration with any development
style)
Background monitoring to avoid crude 'generation' steps
5. Immutability of Metadata Types
Immutability as a first step to manage concurrency
String-based keys (start with 'MID:')
Metadata and keys built on demand only (never persisted)
Metadata can depend on other metadata
if 'upstream' metadata changes, 'downstream' metadata is notified
Some metadata will want to monitor the file system
Central metadata service available and cache is provided to enhance performance
6. Conventions we follow
Ensure usability is first-class
Minimize the JAR footprint that Roo requires
Relocate runtime needs to sister Spring projects
Embrace immutability as much as possible
Maximize performance in generated code
Minimize memory consumption in generated code
Use long artifact IDs to facilitate identification
Don't put into @Roo* what you could calculate
1.3.2.RELEASE
113
Development Processes
Don't violate generator predictability conventions
git
git
git
git
status
add (files)
commit -m 'Explain what I changed'
format-patch origin/master --stdout > ROO-XXXX.patch
The resulting .patch file can then be attached to the ROO-XXXX ticket in our bug tracker.
1.3.2.RELEASE
114
This chapter will provide an introduction to Spring Roo add-on development. The intention is to
provide a step-by-step guide that walks the developer from zero code to a fully deployed and published
add-on that is immediately available to all Spring Roo users. With the release of Spring Roo 1.1, a new
set of commands is available that are designed to provide a fast introduction to add-on development,
as well as easy access to registered add-ons by Spring Roo 1.1 users.
OSGi in Spring Roo
Spring Roo runs in an OSGi container since version 1.1. This internal change is ideal for Roos
add-on model because it allows Roo users to install, uninstall, start, and stop different add-ons
dynamically without restarting the Roo shell. Furthermore, OSGi allows automatic provisioning
of external add-on repositories and provides very good infrastructure for developing modular,
as well as embedded, and service-oriented applications. Under the hood, Spring Roo uses the
Apache Felix OSGi implementation.
A new add-on named 'Add-On Creator' has been developed that facilitates the creation of a new Spring
Roo add-on. Furthermore, it offers out of the box support for the Subversion integration provided by
Google Code as well as zero setup for hosting the add-on in a public Maven repository hosted as part of
a Google Code project. In order to register the add-on with RooBot - a Spring Roo add-on registration
service - the add-on is also required to be OSGi compliant, needs to be signed with PgP keys and the
addon bundle needs to be registered through the httppgp protocol. Add-on developers get all these
features automatically configured if they use the new 'Add-On Creator' feature that ships with Spring
Roo 1.1.
The following sections will present a complete step-by-step guide demonstrating how to bootstrap a
new Spring Roo add-on, publish and release it as your own Google Code project, and register it with
the RooBot service.
1.3.2.RELEASE
115
Simple Add-Ons
1. Create a new project in Google Code: Sign in with your Google Account and navigate to http://
code.google.com/hosting/createProject where you can create your project:
Project Name - a meaningful name such as spring-roo-addon-mvc-i18n-french
Project Summary - a summary of your project such as 'Spring Roo Add-On to provide French
translation for Spring MVC scaffolding'
Project Description - description that could include a version compatibility matrix for your add-on
Version control system - Subversion
Source code license - GNU General Public License v3
Project Labels - Spring Roo, Java, Add-On
2. By default, SVN hosting in Google Code will give you a trunk, tags, branches and a wiki folder. In
order to host a Maven repository in your Google code project, you should also create a repo folder
as root for the new repository:
$ svn mkdir -m "create maven repository" https://<project-name>.googlecode.com/svn/repo --username
4. (optional) Enter your Google Code SVN credentials into your local maven repository settings.xml:
1.3.2.RELEASE
116
Simple Add-Ons
Once you have installed Java, Maven, PGP, and SVN tools, and have created and checked out your
Google Code project, you can change into the <project-name> directory, which at this stage should
contain only the .svn directory. In the <project-name> directory, you can start the Spring Roo shell
and use one of the new commands for add-on creation:
roo> addon create simple --topLevelPackage com.foo --projectName <project-name>
pom.xml
readme.txt
legal/LICENSE.TXT
src/main/java/com/foo/batch/BatchCommands.java
src/main/java/com/foo/batch/BatchOperations.java
src/main/java/com/foo/batch/BatchOperationsImpl.java
src/main/java/com/foo/batch/BatchPropertyName.java
src/main/assembly/assembly.xml
This newly created add-on project can be imported into the SpringSource Tool Suite via File > Import
> Maven > Existing Maven projects. Let's discuss some of these artefacts in more detail:
1.3.2.RELEASE
117
Simple Add-Ons
1. pom.xml - This is the Maven project configuration. This configuration ships with a number of
preinstalled Maven plugins that facilitate the PGP artefact signing process as well as the project
release process (including tagging etc). It also adds the OSGi and Felix dependencies needed for
the addon to run in the Roo Shell. Furthermore, several commonly used Spring Roo modules
are preinstalled. These modules provide functionalities such as file system monitoring, Roo shell
command registration, etc. More information about these functionalities is provided in the following
sections.
The add-on developer should open up the pom.xml file and modify some project specific references
and documentation (marked in bold font):
Some of these properties can also be provided when issuing the addon create command.
2. readme.txt - You can provide any setup or installation information about your add-on in this
file. This file is used by other developers who checkout your add-on source code from the SVN
repository.
3. legal/LICENSE.TXT - Copy the appropriate license text for your add-on into this file.
4. src/main/java/com/foo/batch/BatchCommands.java - This is a fully working code example
demonstrating how to register commands offered by your addon into the Spring Roo Shell (more
detailed information in the next section).
5. src/main/java/com/foo/batch/BatchOperations.java & BatchOperationsImpl.java - These
artefacts are used to perform operations triggered by a command (more information in the next
sections).
6. src/main/java/com/foo/batch/BatchPropertyName.java - This type provides a simple example
demonstrating the use of static command completion options for the Spring Roo Shell. An example
of static command completion options are for example the database selection options as part of the
jpa setup command.
7. src/main/assembly/assembly.xml - This artefact defines configurations used for the packaging of
the add-on.
1.3.2.RELEASE
118
Simple Add-Ons
[2] public class BatchCommands implements CommandMarker {
[3]
[4]
[4]
[5]
@CliAvailabilityIndicator("welcome property")
public boolean isPropertyAvailable() {
return operations.isProjectAvailable();
}
[6]
[7]
There are a few artefacts of interest when developing Spring Roo add-ons:
1. To register components and services in the Roo shell, the type needs to be annotated with the
@Component & @Service annotations provided by Felix. These components can be injected into
other add-ons (more interesting for functionalities exposed by operations types).
2. The command type needs to implement the CommandMarker interface, which Spring Roo scans
for in order to detect classes that contribute commands to the Roo Shell.
3. The Felix @Reference annotations are used to inject services and components offered by other
Spring Roo core components or even other add-ons. In this example, we are injecting a reference
to the add-on's own BatchOperations interface and the StaticFieldConverter component offered by
the Roo Shell OSGi bundle. The Felix @Reference annotation is similar in purpose to Spring's
@Autowired and @Inject annotations.
4. The activate and deactivate methods can optionally be implemented to get access to the lifecycle
of the addon's bundle as managed by the underlying OSGi container. Roo add-on developers can
use these lifecycle hooks for registration and deregistration of converters (typically in command
types) or for the registration of metadata dependencies (typically in ITD-providing add-ons) or any
other component initialization activities.
5. The optional @CliAvailabilityIndicator annotation allows you to limit when a command is
available in the Spring Roo Shell. Methods thus annotated should return a boolean to indicate
whether a command should be visible to the Roo Shell. For example, many commands are hidden
before a project has been created.
6. The @CliCommand annotation plays a central role for Roo add-on developers. It allows the
registration of new commands for the Roo Shell. Methods annotated with @CliCommand can
optionally return a String value to contribute a log statement to the Spring Roo Shell. Another, more
flexible, option to provide log statements in the Roo Shell is to register a standard JDK logger,
which allows the developer to present color-coded messages to the user in the Roo shell, with the
color coding being dependent on the log level (warning, info, error, etc).
7. The optional @CliOption annotation can be used to annotate method parameters. These parameters
define command attributes that are presented as part of a command. Roo will attempt to
1.3.2.RELEASE
119
Simple Add-Ons
automatically convert user-entered values into the Java type of the annotated method parameter.
In the example above, Roo will convert the user-entered String to a BatchPropertyName. By
default, Roo offers converters for common number types, String, Date, Enum, Locale, boolean and
Character. See the org.springframework.roo.shell.converters package for examples if you need to
implement a custom converter.
17.4. Operations
Almost all Spring Roo add-ons provide operations types. These types do most of the work behind
Roo's passive generation principle (active generation is taken care of by AspectJ Intertype declarations
(ITDs) - more about that later). Methods offered by the operations types provided by the add-on are
typically invoked by the accompanying "command" type. Alternatively, operations types can also be
invoked by other add-ons (this is a rather unusual case).
Implementations of the Operations interface need to be annotated with the Felix @Component
and @Service annotations to make their functionality available within Roo's OSGi container.
Dependencies can be injected into operations types via the Felix @Reference annotation. If the
dependency exists in a package that is not yet registered in the add-on's pom.xml, you need to add the
dependency there to add the relevant bundle to the add-on's classpath.
The Add-On Creator generated project includes example code which uses Roo's source path
abstractions, file manager and various Util classes that take care of project file management.
Typical functionality offered by operations types include:
Adding new dependencies, plugins, & repositories to the Maven project pom.xml.
Copying static artefacts from the add-on jar into the user project (i.e. CSS, images, tagx,
configuration files, etc).
Configuring application contexts, web.xml, and other config artefacts.
Managing properties files in the user project.
Creating new Java source types in the user project.
Adding trigger (or other) annotations to target types (most common), fields or methods.
Spring Roo offers a wide range of abstractions and metadata types that support these use cases. For
example, the following services are offered:
org.springframework.roo.process.manager.FileManager
use file manager for all file system operations in project (offers automatic undo on exception)
org.springframework.roo.project.PathResolver
offers abstraction over common project paths
org.springframework.roo.metadata.MetadataService
offers access to Roo metadata bean info metadata for mutators/accessors of target type
org.springframework.roo.project.ProjectMetadata
1.3.2.RELEASE
120
Simple Add-Ons
project name, top level package read access to project dependencies, repositories, etc
org.springframework.roo.project.ProjectOperations
add, remove project Maven dependencies, plugins, repositories, filters, properties, etc
This will generate your add-on OSGi bundle in the project's target directory. In a separate directory,
you can start the Spring Roo Shell and use the following command to test your new add-on:
roo> osgi start --url file:///<path-to-addon-project/target/<addon-bundle-name>.<version>.jar
This should install and activate your new Spring Roo Add-On. For troubleshooting, Roo offers the
following OSGi commands:
osgi ps - Displays OSGi bundle information & status. This should list your add-on as active.
osgi log - Access OSGi container logs. This could identify possible issues occurring during addon activation.
osgi scr list - Lists all currently registered services and components. This should list your add-on's
command, metadata provider, and operations types.
1.3.2.RELEASE
121
Simple Add-Ons
osgi scr info - Info about a specific component. This can be used to identify possible unresolved
dependencies.
osgi start - install a new add-on directly from a local or remote location.
help osgi - Help on Roo's ~20 osgi commands.
Once you have tested the add-on successfully in your development environment, you can release the
add-on source code to your Google Code project, create a tag, and install all relevant artifacts in the
project's Maven repository:
<project-name>$ svn add pom.xml src/ legal/ readme.txt
<project-name>$ svn commit -m "initial commit"
<project-name>$ mvn release:prepare release:perform
The Maven release plugin will ask for tag and release artefact names. Roo follows the OSGi
convention of using the major, minor and micro version numbers followed by a textual identifier, e.g.
0.1.1.RELEASE, 0.1.2.BUILD-SNAPSHOT, etc.
Deployment for bundles created with Roo's "wrapping" command can be deployed rather than released.
For example, to create a wrapped bundle of the PostgreSQL JDBC driver, use this command:
This can then be deployed to a Google code project (set up in the same way as described above) with
a simple deploy command:
<project-name>$ mvn deploy
1.3.2.RELEASE
122
Simple Add-Ons
Register your new add-on repository by sending an email to [email protected] where the subject
line MUST be the raw URL to OSGi repository.xml. The email body is not currently used (but you
can send greetings to the Roo team ;-). Other registration methods are being considered (web frontend, Roo shell command, etc).
RooBot verifies a few aspects before publishing your new add-on to the community:
The provided repository.xml must be a valid OSGi repository
The resource URI must use the httppgp prefix i.e.: <resource uri="httppgp://fr-test.googlecode.com/
svn//>
The bundle referenced in the repository has a corresponding .asc file containing the PgP public key
The public PGP key of the add-on signer needs to be available at http://keyserver.ubuntu.com/ A
guide to PGP key management can be found here. Make sure to publish your key with this command:
gpg --send-keys --keyserver keyserver.ubuntu.com <your-key-id>
RooBot will retrieve publicly accessible key information (key owner name, email) from public key
server
The referenced bundle contains an OSGi-compliant manifest.mf file. For example, it will verify that
the add-on version defined in your repository.xml matches the version defined in the manifest of
your add-on.
[Important] To ensure your repository is valid, RooBot will download all defined resources in the
repository. To do that, it will read the uri attribute and perform an HTTP GET request against the
defined URL (after replacing the httppgp:// protocol handler with http://). Should the download or
verification of any of the defined resources in the respository fail, RooBot will abort the processing
of the entire repository and try again later.
If all tests pass, RooBot will publish your add-on in a publicly accessible XML registry http://springroo-repository.springsource.org/roobot/roobot.xml. This registry is available to the RooBot client
integrated into the Spring Roo Shell.
Once you have sent your email to [email protected], you should receive a response from
RooBot indicating that the processing of your repository has started. If successful, you will
see your add-on listed at http://spring-roo-repository.springsource.org/roobot/roobot.xml within a
few hours. If this does not happen, you can visit the RooBot error log at http://spring-roorepository.springsource.org/roobot/roobot-log.txt, which is refreshed every 5 minutes.
Once RooBot has published your add-on sucessfully, it will periodically process your repository to
verify its ongoing validity. As part of this periodic processing, it will also automatically pick up new
versions (add-on releases) in your repository.xml. Therefore it should not be necessary to explicitly
notify RooBot of any changes in your repository.
1.3.2.RELEASE
123
Simple Add-Ons
As your plugin will result in an OSGi bundle, you need to change the packaging from jar to bundle.
This will cause the Maven bundle plugin to create the necessary metadata for you out of the box.
2. Change the type of the dependencies to bundle
Similar to the point above, you need to reference dependencies as bundles. Again, let the Maven
bundle plugin do its job.
3. Sync the build section of your pom with the one provided in the addon template
Compare your add-on's original pom.xml with a pom.xml generated by the addon create command
(see below). This is mostly related to the Maven bundle plugin as well as the Maven SCR plugin
(see next point for details).
Example 17.1. Creating a Roo addon project
addon create simple --topLevelPackage com.mycompany.myproject.roo.addon
The easiest way to do so is simply creating a dummy addon project using the template and copying
the plugin configuration into your pom.
4. Replace @ScopeDevelopment annotations with @Component and @Service
Roo uses Apache Felix as OSGi runtime and thus uses @Component and @Service annotations in
combination with the Maven SCR plugin1 to create descriptors for the OSGi declarative services
infrastructure.
Example 17.2. Component declaration with Apache Felix annotations
@Service
@Component
public class MyCommands implements CommandMarker {
@Reference MyOperations operations;
// Your code goes here
}
So every @ScopeDevelopment annotation you used in your command and operations classes has to
be replaced by @Service and @Component. If you had injected other services into your command or
operations class, you can use @Reference to wire them into your component instance. Note that your
class will have to implement at least one interface under which Felix can publish the component
instance. Check the output of the Maven SCR plugin for errors to see whether any further tweaks
are necessary.
1.3.2.RELEASE
124
18.1. Metadata
TBC
18.2. Annotations
TBC
18.4. Recommendations
TBC
1.3.2.RELEASE
125
1.3.2.RELEASE
126
1.3.2.RELEASE
127
Tailor Add-On
tailor deactivate Deactivate the tailor mode. There is no active configuration after this command
roo> tailor deactivate
19.4.1. Actions
19.4.1.1. execute
Adds a command to the list of commands to be executed. Note that each command configuration
should have at least one execute action, otherwise the tailor will not lead to any command executions.
1.3.2.RELEASE
128
Tailor Add-On
command
Command line to be executed. If empty, this action will add the original command to the list of
output commands at this point. (optional)
exclude
A comma separated list of arguments that should be removed from the command before execution.
This can be useful if the original command is executed ("command" argument not set), and it was
enhanced with additional arguments for the benefit of the tailoring. (optional)
19.4.1.2. defaultvalue
If the Roo user does not provide a value for an argument with the given name on the shell, this default
value will be chosen.
argument
Name of the Roo command's argument that will get a default value. (mandatory)
value
Default value for the argument. (mandatory)
force
If "true", the default value will be chosen even if the user specified an alternative value in the
command. (optional, defaults to "false")
19.4.1.3. focus
module
Focus on a module, in form of a simple pattern to match against the module names. Does not
support regular expressions, just a simple "contains" match. Use this instead of an "execute
command 'module focus...'" if you do not want to hard code your module names into the reusable
tailor configuration. (mandatory)
Advanced usage: Use a comma-separated list of strings to look for in module names. The comma
will be interpreted as "AND" by the search for a module. Use a slash "/" before a string in the list
to indicate that this next string must "NOT" be contained in the module name.
1.3.2.RELEASE
129
Tailor Add-On
Shell:
tailor activate --name mywebstyle
project --topLevelPackage com.foo.sample --projectName myapp
Shell:
entity jpa --class ~.Customer
Results in:
module focus --moduleName webapp-domain
entity jpa --class ~.Customer --activeRecord false
1.3.2.RELEASE
130
Tailor Add-On
tailor.xml:
<config command="layer">
<action type="focus" module="domain"/>
<!-- Create spring data JPA repository -->
<action type="execute" command="repository jpa --interface ${entity}Repository --entity ${entity}"/
<!-- Create service interface and implementation class-->
<action type="execute" command="service --interface ${entity}Service --class ${entity}ServiceImpl <action type="focus" module="web"/>
<action type="execute" command="web mvc scaffold --class ${entity}Controller --backingType ${entity
</config>
Shell:
layer --entity ~.Customer
Results in:
module focus --moduleName webapp-domain
repository jpa --interface ~.CustomerRepository --entity ~.Customer
service --interface ~.CustomerService --class ~.CustomerServiceImpl --entity ~.Customer
module focus --moduleName webapp-web
web mvc scaffold --class ~.CustomerController --backingType ~.Customer
Override createTailorConfiguration()
@Override
public TailorConfiguration createTailorConfiguration() {
String description = "Web project with 2 modules DOMAIN-PRESENTATION";
TailorConfiguration configuration = new TailorConfiguration("webstyle-simple", description);
configuration.addCommandConfig(createCommandConfigProject());
configuration.addCommandConfig(createCommandConfigJpaSetup());
return configuration;
1.3.2.RELEASE
131
Tailor Add-On
}
1.3.2.RELEASE
132
Part V. Appendices
The fourth and final part of the reference guide provides appendices and background information that does
not neatly belong within the other parts. The information is intended to be treated as a reference and not read
consecutively.
1.3.2.RELEASE
133
--bundleSymbolicName
The bundle symbolic name for the add-on of interest; default: '__NULL__' (mandatory)
--rating
How much did you like this add-on?; default: '__NULL__' (mandatory)
--comment
Your comments on this add-on eg "this is my comment!"; limit of 140 characters; default:
'__NULL__'
--bundleSymbolicName
The bundle symbolic name for the add-on of interest; default: '__NULL__' (mandatory)
--searchResultId
The bundle ID as presented via the addon list or addon search command; default:
'__NULL__' (mandatory)
1.3.2.RELEASE
134
Command Index
--bundleSymbolicName
The bundle symbolic name for the add-on of interest; default: '__NULL__' (mandatory)
--searchResultId
The bundle ID as presented via the addon list or addon search command; default:
'__NULL__' (mandatory)
--refresh
Refresh the add-on index from the Internet; default if option present: 'true'; default if option not
present: 'false'
--linesPerResult
The maximum number of lines displayed per add-on; default: '2'
--maxResults
The maximum number of add-ons to list; default: '99'
--trustedOnly
Only display trusted add-ons in search results; default if option present: 'true'; default if option
not present: 'false'
--communityOnly
Only display community provided add-ons in search results; default if option present: 'true'; default
if option not present: 'false'
--compatibleOnly
Only display compatible add-ons in search results; default if option present: 'true'; default if option
not present: 'false'
--bundleSymbolicName
The bundle symbolic name for the add-on of interest; default: '__NULL__' (mandatory)
1.3.2.RELEASE
135
Command Index
addon search
--requiresDescription
A comma separated list of search terms; default: '*'
--refresh
Refresh the add-on index from the Internet; default if option present: 'true'; default if option not
present: 'false'
--linesPerResult
The maximum number of lines displayed per add-on; default: '2'
--maxResults
The maximum number of add-ons to list; default: '20'
--trustedOnly
Only display trusted add-ons in search results; default if option present: 'true'; default if option
not present: 'false'
--compatibleOnly
Only display compatible add-ons in search results; default if option present: 'true'; default if option
not present: 'false'
--communityOnly
Only display community provided add-ons in search results; default if option present: 'true'; default
if option not present: 'false'
--requiresCommand
Only display add-ons in search results that offer this command; default: '__NULL__'
--addonStabilityLevel
The stability level of add-ons or components which are presented for upgrading (default: ANY);
default: '__NULL__'
1.3.2.RELEASE
136
Command Index
--bundleSymbolicName
The bundle symbolic name for the add-on to upgrade; default: '__NULL__' (mandatory)
--searchResultId
The bundle ID as presented via the addon list or addon search command; default:
'__NULL__' (mandatory)
--addonStabilityLevel
The stability level of add-ons or components which are presented for upgrading; default:
'__NULL__'
A.2.1. backup
Backup your project to a zip file
backup
contained
in
A.3.1. class
Creates a new Java class source file in any project path
class --class
--class
The name of the class to create; default: '__NULL__' (mandatory)
--rooAnnotations
Whether the generated class should have common Roo annotations; default if option present: 'true';
default if option not present: 'false'
1.3.2.RELEASE
137
Command Index
--path
Source directory to create the class in; default: 'FOCUSED|SRC_MAIN_JAVA'
--extends
The superclass (defaults to java.lang.Object); default if option not present: 'java.lang.Object'
--implements
The interface to implement; default: '__NULL__'
--abstract
Whether the generated class should be marked as abstract; default if option present: 'true'; default
if option not present: 'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
A.3.2. constructor
Creates a class constructor
constructor
--class
The name of the class to receive this constructor; default if option not present: '*'
--fields
The fields to include in the constructor. Multiple field names must be a double-quoted list separated
by spaces
--class
The name of the enum class to receive this field; default if option not present: '*'
--name
The name of the constant; default: '__NULL__' (mandatory)
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--class
The name of the enum to create; default: '__NULL__' (mandatory)
1.3.2.RELEASE
138
Command Index
--path
Source directory to create the enum in; default: 'FOCUSED|SRC_MAIN_JAVA'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
A.3.5. focus
Changes focus to a different type
focus --class
--class
The type to focus on; default: '__NULL__' (mandatory)
A.3.6. interface
Creates a new Java interface source file in any project path
interface --class
--class
The name of the interface to create; default: '__NULL__' (mandatory)
--path
Source directory to create the interface in; default: 'FOCUSED|SRC_MAIN_JAVA'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--provider
Cloud Provider's Name; default: '__NULL__' (mandatory)
--configuration
Plugin
Configuration.
Add
configuration
'key=value,key2=value2,key3=value3'; default: '__NULL__'
by
command
like
1.3.2.RELEASE
in
139
Command Index
--package
The package in which new controllers will be placed; default: '__NULL__' (mandatory)
--class
The path and name of the controller object to be created; default: '__NULL__' (mandatory)
--entity
The name of the entity object which the controller exposes to the web tier; default if option not
present: '*'
--path
The base path under which the controller listens for RESTful requests (defaults to the simple name
of the form backing object); default: '__NULL__'
--disallowedOperations
A comma separated list of operations (only create, update, delete allowed) that should not be
generated in the controller; default: '__NULL__'
--package
The package in which new controllers will be placed; default: '__NULL__' (mandatory)
--class
The path and name of the controller object to be created; default: '__NULL__' (mandatory)
--backingType
The name of the form backing type which the controller exposes to the web tier; default if option
not present: '*'
1.3.2.RELEASE
140
Command Index
--path
The base path under which the controller listens for RESTful requests (defaults to the simple name
of the form backing object); default: '__NULL__'
--disallowedOperations
A comma separated list of operations (only create, update, delete allowed) that should not be
generated in the controller; default: '__NULL__'
--topLevelPackage
The top level package of the new addon; default: '__NULL__' (mandatory)
--description
Description of your addon (surround text with double quotes); default: '__NULL__'
--projectName
Provide a custom project name (if not provided the top level package name will be used instead);
default: '__NULL__'
--topLevelPackage
The top level package of the new addon; default: '__NULL__' (mandatory)
--locale
The locale abbreviation (ie: en, or more specific like en_AU, or de_DE); default:
'__NULL__' (mandatory)
--messageBundle
Fully qualified path to the messages_xx.properties file; default: '__NULL__' (mandatory)
--language
The full name of the language (used as a label for the UI); default: '__NULL__'
--flagGraphic
Fully qualified path to flag xx.png file; default: '__NULL__'
--description
Description of your addon (surround text with double quotes); default: '__NULL__'
1.3.2.RELEASE
141
Command Index
--projectName
Provide a custom project name (if not provided the top level package name will be used instead);
default: '__NULL__'
--topLevelPackage
The top level package of the new addon; default: '__NULL__' (mandatory)
--description
Description of your addon (surround text with double quotes); default: '__NULL__'
--projectName
Provide a custom project name (if not provided the top level package name will be used instead);
default: '__NULL__'
--topLevelPackage
The top level package of the new wrapper bundle; default: '__NULL__' (mandatory)
--groupId
Dependency group id; default: '__NULL__' (mandatory)
--artifactId
Dependency artifact id); default: '__NULL__' (mandatory)
--version
Dependency version; default: '__NULL__' (mandatory)
--vendorName
Dependency vendor name); default: '__NULL__' (mandatory)
--licenseUrl
Dependency license URL; default: '__NULL__' (mandatory)
--docUrl
Dependency documentation URL; default: '__NULL__'
--description
Description of the bundle (use keywords with #-tags for better search integration); default:
'__NULL__'
--projectName
Provide a custom project name (if not provided the top level package name will be used instead);
default: '__NULL__'
1.3.2.RELEASE
142
Command Index
--osgiImports
Contents of Import-Package in OSGi manifest; default: '__NULL__'
contained
in
A.7.1. dod
Creates a new data on demand for the specified entity
dod
--entity
The entity which this data on demand class will create and modify as required; default if option
not present: '*'
--class
The class which will be created to hold this data on demand provider (defaults to the entity name
+ 'DataOnDemand'); default: '__NULL__'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--schema
The database schema names. Multiple schema names must be a double-quoted list separated by
spaces; default: '__NULL__' (mandatory)
--file
The file to save the metadata to; default: '__NULL__'
--enableViews
Display database views; default if option present: 'true'; default if option not present: 'false'
1.3.2.RELEASE
143
Command Index
--schema
The database schema names. Multiple schema names must be a double-quoted list separated by
spaces; default: '__NULL__' (mandatory)
--package
The package in which new entities will be placed; default: '__NULL__'
--testAutomatically
Create automatic integration tests for entities; default if option present: 'true'; default if option not
present: 'false'
--enableViews
Reverse engineer database views; default if option present: 'true'; default if option not present:
'false'
--includeTables
The tables to include in reverse engineering. Multiple table names must be a double-quoted list
separated by spaces
--excludeTables
The tables to exclude from reverse engineering. Multiple table names must be a double-quoted
list separated by spaces
--includeNonPortableAttributes
Include non-portable JPA @Column attributes such as 'columnDefinition'; default if option
present: 'true'; default if option not present: 'false'
--disableVersionFields
Disable 'version' field; default if option present: 'true'; default if option not present: 'false'
--disableGeneratedIdentifiers
Disable identifier auto generation; default if option present: 'true'; default if option not present:
'false'
--activeRecord
Generate CRUD active record methods for each entity; default: 'true'
--repository
Generate a repository for each entity; default if option present: 'true'; default if option not present:
'false'
--service
Generate a service for each entity; default if option present: 'true'; default if option not present:
'false'
in
1.3.2.RELEASE
144
Command Index
web mvc embed document --provider --documentId
--provider
The id of the document; default: '__NULL__' (mandatory)
--documentId
The id of the document; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
--url
The url of the source to be embedded; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
--location
The location of the map (ie "Sydney, Australia"); default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
--provider
The provider of the photo gallery; default: '__NULL__' (mandatory)
--userId
The user id; default: '__NULL__' (mandatory)
--albumId
The album id; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
1.3.2.RELEASE
145
Command Index
web mvc embed stream video --provider --streamId
--provider
The provider of the video stream; default: '__NULL__' (mandatory)
--streamId
The stream id; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
--searchTerm
The search term to display results for; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
--provider
The id of the video; default: '__NULL__' (mandatory)
--videoId
The id of the video; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
--waveId
The key of the wave; default: '__NULL__' (mandatory)
--viewName
The name of the jspx view; default: '__NULL__'
1.3.2.RELEASE
146
Command Index
A.10.1. equals
Add equals and hashCode methods to a class
equals
--class
The name of the class; default if option not present: '*'
--appendSuper
Whether to call the super class equals and hashCode methods; default if option present: 'true';
default if option not present: 'false'
--excludeFields
The fields to exclude in the equals and hashcode methods. Multiple field names must be a doublequoted list separated by spaces
A.11.1. exit
Exits the shell
exit
--[default]
The command to pass to Felix (WARNING: no validation or security checks are performed);
default: 'help'
--bundleSymbolicName
Limit results to a specific bundle symbolic name; default: '__NULL__'
1.3.2.RELEASE
147
Command Index
--url
The URL to obtain the bundle from; default: '__NULL__' (mandatory)
--maximumEntries
The maximum number of log messages to display; default: '__NULL__'
--level
The minimum level of messages to display; default: '__NULL__' (mandatory)
--bundleSymbolicName
The specific bundle to deploy; default: '__NULL__' (mandatory)
--bundleSymbolicName
The specific bundle to display information for; default: '__NULL__' (mandatory)
--keywords
Keywords to locate; default: '__NULL__'
--bundleSymbolicName
The specific bundle to start; default: '__NULL__' (mandatory)
1.3.2.RELEASE
148
Command Index
osgi obr url add --url
--url
The URL to add (eg http://felix.apache.org/obr/releases.xml); default: '__NULL__' (mandatory)
--url
The URL to refresh (list existing URLs via 'osgi obr url list'); default: '__NULL__' (mandatory)
--url
The URL to remove (list existing URLs via 'osgi obr url list'); default: '__NULL__' (mandatory)
A.11.14. osgi ps
Displays OSGi bundle information
osgi ps
--format
The format of bundle information; default: 'BUNDLE_NAME'
--bundleSymbolicName
The specific bundle to resolve; default: '__NULL__' (mandatory)
1.3.2.RELEASE
149
Command Index
This command does not accept any options.
--componentId
The specific component identifier (use 'osgi scr list' to list component identifiers); default:
'__NULL__' (mandatory)
--componentId
The specific component identifier (use 'osgi scr list' to list component identifiers); default:
'__NULL__' (mandatory)
--componentId
The specific component identifier (use 'osgi scr list' to list component identifiers); default:
'__NULL__' (mandatory)
--bundleId
Limit results to a specific bundle; default: '__NULL__'
--url
The URL to obtain the bundle from; default: '__NULL__' (mandatory)
1.3.2.RELEASE
150
Command Index
osgi uninstall --bundleSymbolicName
--bundleSymbolicName
The specific bundle to uninstall; default: '__NULL__' (mandatory)
--bundleSymbolicName
The specific bundle to update ; default: '__NULL__' (mandatory)
--url
The URL to obtain the updated bundle from; default: '__NULL__'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--assertFalse
Whether this value must assert false; default if option present: 'true'; default if option not present:
'false'
--assertTrue
Whether this value must assert true; default if option present: 'true'; default if option not present:
'false'
--column
The JPA @Column name; default: '__NULL__'
--value
Inserts an optional Spring @Value annotation with the given content; default: '__NULL__'
1.3.2.RELEASE
151
Command Index
--comment
An optional comment for JavaDocs; default: '__NULL__'
--primitive
Indicates to use a primitive type; default if option present: 'true'; default if option not present: 'false'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The Java type of the entity; default: '__NULL__' (mandatory)
--persistenceType
The type of persistent storage to be used; default: '__NULL__'
--class
The name of the class to receive this field; default if option not present: '*'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--future
Whether this value must be in the future; default if option present: 'true'; default if option not
present: 'false'
--past
Whether this value must be in the past; default if option present: 'true'; default if option not present:
'false'
--column
The JPA @Column name; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--value
Inserts an optional Spring @Value annotation with the given content; default: '__NULL__'
1.3.2.RELEASE
152
Command Index
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--dateFormat
Indicates the style of the date format (ignored if dateTimeFormatPattern is specified); default:
'MEDIUM'
--timeFormat
Indicates the style of the time format (ignored if dateTimeFormatPattern is specified); default:
'NONE'
--dateTimeFormatPattern
Indicates a DateTime format pattern such as yyyy-MM-dd hh:mm:ss a; default: '__NULL__'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The Java type of the @Embeddable class; default: '__NULL__' (mandatory)
--class
The name of the @Entity class to receive this field; default if option not present: '*'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The enum type of this field; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
1.3.2.RELEASE
153
Command Index
--column
The JPA @Column name; default: '__NULL__'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--enumType
The fetch semantics at a JPA level; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the file upload field to add; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--contentType
The content type of the file; default: '__NULL__' (mandatory)
--autoUpload
Whether the file is uploaded automatically when selected; default if option present: 'true'; default
if option not present: 'false'
--column
The JPA @Column name; default: '__NULL__'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
1.3.2.RELEASE
154
Command Index
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The entity which will be contained within the Set; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--mappedBy
The field name on the referenced type which owns the relationship; default: '__NULL__'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--sizeMin
The minimum number of elements in the collection; default: '__NULL__'
--sizeMax
The maximum number of elements in the collection; default: '__NULL__'
--cardinality
The relationship cardinality at a JPA level; default: 'MANY_TO_MANY'
--fetch
The fetch semantics at a JPA level; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
1.3.2.RELEASE
155
Command Index
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The Java type of the entity; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--decimalMin
The BigDecimal string-based representation of the minimum value; default: '__NULL__'
--decimalMax
The BigDecimal string based representation of the maximum value; default: '__NULL__'
--digitsInteger
Maximum number of integral digits accepted for this number; default: '__NULL__'
--digitsFraction
Maximum number of fractional digits accepted for this number; default: '__NULL__'
--min
The minimum value; default: '__NULL__'
--max
The maximum value; default: '__NULL__'
--column
The JPA @Column name; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--value
Inserts an optional Spring @Value annotation with the given content; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--primitive
Indicates to use a primitive type if possible; default if option present: 'true'; default if option not
present: 'false'
--unique
Indicates whether to mark the field with a unique constraint; default if option present: 'true'; default
if option not present: 'false'
1.3.2.RELEASE
156
Command Index
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the field; default: '__NULL__' (mandatory)
--type
The Java type of this field; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--column
The JPA @Column name; default: '__NULL__'
--value
Inserts an optional Spring @Value annotation with the given content; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The Java type of the entity to reference; default: '__NULL__' (mandatory)
1.3.2.RELEASE
157
Command Index
--class
The name of the class to receive this field; default if option not present: '*'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--joinColumnName
The JPA @JoinColumn name; default: '__NULL__'
--referencedColumnName
The JPA @JoinColumn referencedColumnName; default: '__NULL__'
--cardinality
The relationship cardinality at a JPA level; default: 'MANY_TO_ONE'
--fetch
The fetch semantics at a JPA level; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--type
The entity which will be contained within the Set; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--mappedBy
The field name on the referenced type which owns the relationship; default: '__NULL__'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
1.3.2.RELEASE
158
Command Index
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--sizeMin
The minimum number of elements in the collection; default: '__NULL__'
--sizeMax
The maximum number of elements in the collection; default: '__NULL__'
--cardinality
The relationship cardinality at a JPA level; default: 'MANY_TO_MANY'
--fetch
The fetch semantics at a JPA level; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--fieldName
The name of the field to add; default: '__NULL__' (mandatory)
--class
The name of the class to receive this field; default if option not present: '*'
--notNull
Whether this value cannot be null; default if option present: 'true'; default if option not present:
'false'
--nullRequired
Whether this value must be null; default if option present: 'true'; default if option not present: 'false'
--decimalMin
The BigDecimal string-based representation of the minimum value; default: '__NULL__'
--decimalMax
The BigDecimal string based representation of the maximum value; default: '__NULL__'
--sizeMin
The minimum string length; default: '__NULL__'
1.3.2.RELEASE
159
Command Index
--sizeMax
The maximum string length; default: '__NULL__'
--regexp
The required regular expression pattern; default: '__NULL__'
--column
The JPA @Column name; default: '__NULL__'
--value
Inserts an optional Spring @Value annotation with the given content; default: '__NULL__'
--comment
An optional comment for JavaDocs; default: '__NULL__'
--transient
Indicates to mark the field as transient; default if option present: 'true'; default if option not present:
'false'
--unique
Indicates whether to mark the field with a unique constraint; default if option present: 'true'; default
if option not present: 'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--lob
Indicates that this field is a Large Object; default if option present: 'true'; default if option not
present: 'false'
--class
The controller or entity for which the finders are generated; default if option not present: '*'
--finderName
The finder string as generated with the 'finder list' command; default: '__NULL__' (mandatory)
1.3.2.RELEASE
160
Command Index
--class
The controller or entity for which the finders are generated; default if option not present: '*'
--depth
The depth of attribute combinations to be generated for the finders; default: '1'
--filter
A comma separated list of strings that must be present in a filter to be included; default:
'__NULL__'
A.14.1. help
Shows system help
help
--command
Command name to provide help for; default: '__NULL__'
A.15.1. hint
Provides step-by-step hints and context-sensitive guidance
hint
--topic
The topic for which advice should be provided
contained
in
1.3.2.RELEASE
161
Command Index
test integration
--entity
The name of the entity to create an integration test for; default if option not present: '*'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--transactional
Indicates whether the created test cases should be run withing a Spring transaction; default: 'true'
--entity
The name of the entity this mock test is targeting; default if option not present: '*'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--class
The name of the class this mock test is targeting; default if option not present: '*'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
contained
in
A.17.1. */
End of block comment
*/
A.17.2. /*
Start of block comment
1.3.2.RELEASE
162
Command Index
/*
A.17.3. //
Inline comment markers (start of line only)
//
A.17.4. date
Displays the local date and time
date
A.17.6. script
Parses the specified resource file and executes its commands
script --file
--file
The file to locate and execute; default: '__NULL__' (mandatory)
--lineNumbers
Display line numbers when executing the script; default if option present: 'true'; default if option
not present: 'false'
A.17.8. version
Displays shell version
version
1.3.2.RELEASE
163
Command Index
--[default]
Special version flags; default: '__NULL__'
--fieldName
The name of the field to add; default: 'jmsOperations'
--class
The name of the class to receive this field; default if option not present: '*'
--async
Indicates if the injected method should be executed asynchronously; default if option present:
'true'; default if option not present: 'false'
--class
The name of the class to create; default: '__NULL__' (mandatory)
--destinationName
The name of the destination; default: 'myDestination'
--destinationType
The type of the destination; default: 'QUEUE'
--provider
The persistence provider to support; default: '__NULL__' (mandatory)
--destinationName
The name of the destination; default: 'myDestination'
--destinationType
The type of the destination; default: 'QUEUE'
1.3.2.RELEASE
164
Command Index
--key
The property key that should be removed; default: '__NULL__' (mandatory)
--key
The property key that should be changed; default: '__NULL__' (mandatory)
--value
The new vale for this property key; default: '__NULL__' (mandatory)
A.19.4. embeddable
Creates a new Java class source file with the JPA @Embeddable annotation in SRC_MAIN_JAVA
embeddable --class
--class
The name of the class to create; default: '__NULL__' (mandatory)
--serializable
Whether the generated class should implement java.io.Serializable; default if option present: 'true';
default if option not present: 'false'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
1.3.2.RELEASE
165
Command Index
entity jpa --class
--class
Name of the entity to create; default: '__NULL__' (mandatory)
--extends
The superclass (defaults to java.lang.Object); default if option not present: 'java.lang.Object'
--implements
The interface to implement; default: '__NULL__'
--abstract
Whether the generated class should be marked as abstract; default if option present: 'true'; default
if option not present: 'false'
--testAutomatically
Create automatic integration tests for this entity; default if option present: 'true'; default if option
not present: 'false'
--table
The JPA table name to use for this entity; default: '__NULL__'
--schema
The JPA table schema name to use for this entity; default: '__NULL__'
--catalog
The JPA table catalog name to use for this entity; default: '__NULL__'
--identifierField
The JPA identifier field name to use for this entity; default: '__NULL__'
--identifierColumn
The JPA identifier field column to use for this entity; default: '__NULL__'
--identifierType
The data type that will be used for the JPA identifier field (defaults to java.lang.Long); default:
'java.lang.Long'
--versionField
The JPA version field name to use for this entity; default: '__NULL__'
--versionColumn
The JPA version field column to use for this entity; default: '__NULL__'
--versionType
The data type that will be used for the JPA version field (defaults to java.lang.Integer); default if
option not present: 'java.lang.Integer'
--inheritanceType
The JPA @Inheritance value (apply to base class); default: '__NULL__'
--mappedSuperclass
Apply @MappedSuperclass for this entity; default if option present: 'true'; default if option not
present: 'false'
1.3.2.RELEASE
166
Command Index
--equals
Whether the generated class should implement equals and hashCode methods; default if option
present: 'true'; default if option not present: 'false'
--serializable
Whether the generated class should implement java.io.Serializable; default if option present: 'true';
default if option not present: 'false'
--persistenceUnit
The persistence unit name to be used in the persistence.xml file; default: '__NULL__'
--transactionManager
The transaction manager name; default: '__NULL__'
--permitReservedWords
Indicates whether reserved words are ignored by Roo; default if option present: 'true'; default if
option not present: 'false'
--entityName
The name used to refer to the entity in queries; default: '__NULL__'
--sequenceName
The name of the sequence for incrementing sequence-driven primary keys; default: '__NULL__'
--activeRecord
Generate CRUD active record methods for this entity; default: 'true'
--provider
The persistence provider to support; default: '__NULL__' (mandatory)
--database
The database to support; default: '__NULL__' (mandatory)
--applicationId
The Google App Engine application identifier to use; default if option not present: 'the project's
name'
--jndiDataSource
The JNDI datasource to use; default: '__NULL__'
--hostName
The host name to use; default: '__NULL__'
--databaseName
The database name to use; default: '__NULL__'
--userName
The username to use; default: '__NULL__'
1.3.2.RELEASE
167
Command Index
--password
The password to use; default: '__NULL__'
--transactionManager
The transaction manager name; default: '__NULL__'
--persistenceUnit
The persistence unit name to be used in the persistence.xml file; default: '__NULL__'
--provider
The persistence provider to support; default: '__NULL__' (mandatory)
--database
The database to support; default: '__NULL__' (mandatory)
--applicationId
The Google App Engine application identifier to use; default if option not present: 'the project's
name'
--jndiDataSource
The JNDI datasource to use; default: '__NULL__'
--hostName
The host name to use; default: '__NULL__'
--databaseName
The database name to use; default: '__NULL__'
--userName
The username to use; default: '__NULL__'
--password
The password to use; default: '__NULL__'
--transactionManager
The transaction manager name; default: '__NULL__'
--persistenceUnit
The persistence unit name to be used in the persistence.xml file; default: '__NULL__'
1.3.2.RELEASE
168
Command Index
--package
The package in which new JSF managed beans will be placed; default: '__NULL__' (mandatory)
--url
The url of the media source; default: '__NULL__' (mandatory)
--player
The name of the media player; default: '__NULL__'
--class
The path and name of the JSF managed bean to be created; default: '__NULL__' (mandatory)
--entity
The entity which this JSF managed bean class will create and modify as required; default if option
not present: '*'
--beanName
The name of the managed bean to use in the 'name' attribute of the @ManagedBean annotation;
default: '__NULL__'
--includeOnMenu
Include this entity on the generated JSF menu; default: 'true'
--implementation
The JSF implementation to use; default: '__NULL__'
--library
The JSF component library to use; default: '__NULL__'
--theme
The name of the theme; default: '__NULL__'
1.3.2.RELEASE
169
Command Index
--class
The java type to apply this annotation to; default if option not present: '*'
--rootName
The root name which should be used to wrap the JSON document; default: '__NULL__'
--deepSerialize
Indication if deep serialization should be enabled.; default if option present: 'true'; default if option
not present: 'false'
--iso8601Dates
Indication if dates should be formatted according to ISO 8601; default if option present: 'true';
default if option not present: 'false'
--deepSerialize
Indication if deep serialization should be enabled; default if option present: 'true'; default if option
not present: 'false'
--iso8601Dates
Indication if dates should be formatted according to ISO 8601; default if option present: 'true';
default if option not present: 'false'
--class
The path and name of the controller object to be created; default: '__NULL__' (mandatory)
--preferredMapping
Indicates a specific request mapping path for this controller (eg /foo/); default: '__NULL__'
1.3.2.RELEASE
170
Command Index
web mvc controller --class
--class
The path and name of the controller object to be created; default: '__NULL__' (mandatory)
--preferredMapping
Indicates a specific request mapping path for this controller (eg /foo/); default: '__NULL__'
--code
The language code for the desired bundle; default: '__NULL__' (mandatory)
--path
The path the static view to create in (required, ie '/foo/blah'); default: '__NULL__' (mandatory)
--viewName
The view name the mapping this view should adopt (required, ie 'index'); default:
'__NULL__' (mandatory)
--title
The title of the view; default: '__NULL__' (mandatory)
--code
The language code for the desired bundle; default: '__NULL__' (mandatory)
1.3.2.RELEASE
171
Command Index
web mvc update tags
--backup
Backup your application before replacing your existing tag library; default if option present: 'true';
default if option not present: 'false'
--path
The path the static view to create in (required, ie '/foo/blah'); default: '__NULL__' (mandatory)
--viewName
The view name the mapping this view should adopt (required, ie 'index'); default:
'__NULL__' (mandatory)
--title
The title of the view; default: '__NULL__' (mandatory)
--level
The log level to configure; default: '__NULL__' (mandatory)
--package
The package to append the logging level to (all by default); default: '__NULL__'
--hostServer
The host server; default: '__NULL__' (mandatory)
--protocol
The protocol used by mail server; default: '__NULL__'
1.3.2.RELEASE
172
Command Index
--port
The port used by mail server; default: '__NULL__'
--encoding
The encoding used for mail; default: '__NULL__'
--username
The mail account username; default: '__NULL__'
--password
The mail account password; default: '__NULL__'
--from
The 'from' email (optional); default: '__NULL__'
--subject
The message subject (obtional); default: '__NULL__'
--fieldName
The name of the field to add; default: 'mailTemplate'
--class
The name of the class to receive this field; default if option not present: '*'
--async
Indicates if the injected method should be executed asynchronously; default if option present:
'true'; default if option not present: 'false'
--groupId
The group ID of the dependency; default: '__NULL__' (mandatory)
--artifactId
The artifact ID of the dependency; default: '__NULL__' (mandatory)
1.3.2.RELEASE
173
Command Index
--version
The version of the dependency; default: '__NULL__' (mandatory)
--classifier
The classifier of the dependency; default: '__NULL__'
--scope
The scope of the dependency; default: '__NULL__'
--groupId
The group ID of the dependency; default: '__NULL__' (mandatory)
--artifactId
The artifact ID of the dependency; default: '__NULL__' (mandatory)
--version
The version of the dependency; default: '__NULL__' (mandatory)
--classifier
The classifier of the dependency; default: '__NULL__'
--id
The ID of the repository; default: '__NULL__' (mandatory)
--name
The name of the repository; default: '__NULL__'
--url
The URL of the repository; default: '__NULL__' (mandatory)
--id
The ID of the repository; default: '__NULL__' (mandatory)
--url
The URL of the repository; default: '__NULL__' (mandatory)
1.3.2.RELEASE
174
Command Index
--moduleName
The name of the module; default: '__NULL__' (mandatory)
--topLevelPackage
The uppermost package name (this becomes the <groupId> in Maven and also the '~' value when
using Roo's shell); default: '__NULL__' (mandatory)
--java
Forces a particular major version of Java to be used (will be auto-detected if unspecified; specify
6 or 7 only); default: '__NULL__'
--parent
The Maven coordinates of the parent POM, in the form "groupId:artifactId:version"; default:
'__NULL__'
--packaging
The Maven packaging of this module; default if option not present: 'jar'
--artifactId
The artifact ID of this module (defaults to moduleName if not specified); default: '__NULL__'
--moduleName
The module to focus on; default: '__NULL__' (mandatory)
1.3.2.RELEASE
175
Command Index
perform command --mavenCommand
--mavenCommand
User-specified Maven command (eg test:test); default: '__NULL__' (mandatory)
A.25.13. project
Creates a new Maven project
project --topLevelPackage
--topLevelPackage
The uppermost package name (this becomes the <groupId> in Maven and also the '~' value when
using Roo's shell); default: '__NULL__' (mandatory)
--projectName
The name of the project (last segment of package name used as default); default: '__NULL__'
--java
Forces a particular major version of Java to be used (will be auto-detected if unspecified; specify
5 or 6 or 7 only); default: '__NULL__'
--parent
The Maven coordinates of the parent POM, in the form "groupId:artifactId:version"; default:
'__NULL__'
--packaging
The Maven packaging of this project; default if option not present: 'jar'
1.3.2.RELEASE
176
Command Index
--maximumCapacity
The maximum number of metadata items to cache; default: '__NULL__' (mandatory)
--metadataId
The metadata ID (should start with MID:); default: '__NULL__' (mandatory)
--module
The module for which to retrieve the metadata (defaults to the focused module); default:
'__NULL__'
--type
The Java type for which to display metadata; default: '__NULL__' (mandatory)
1.3.2.RELEASE
177
Command Index
--level
The verbosity of notifications (0=none, 1=some, 2=all); default: '__NULL__' (mandatory)
in
--class
Implementation class for the specified interface; default: '__NULL__' (mandatory)
--identifierType
The ID type to be used for this domain type (defaults to BigInteger); default: '__NULL__'
--testAutomatically
Create automatic integration tests for this entity; default if option present: 'true'; default if option
not present: 'false'
--username
Username for accessing the database (defaults to ''); default: '__NULL__'
--password
Password for accessing the database (defaults to ''); default: '__NULL__'
--databaseName
Name of the database (defaults to project name); default: '__NULL__'
--port
Port for the database (defaults to '27017'); default: '__NULL__'
--host
Host for the database (defaults to '127.0.0.1'); default: '__NULL__'
--cloudFoundry
Deploy to CloudFoundry (defaults to 'false'); default if option present: 'true'; default if option not
present: 'false'
1.3.2.RELEASE
178
Command Index
--interface
The java interface to apply this annotation to; default: '__NULL__' (mandatory)
--entity
The domain entity this repository should expose; default if option not present: '*'
A.28. Os Commands
Os Commands are contained in org.springframework.roo.addon.oscommands.OsCommands.
A.28.1. !
Allows execution of operating system (OS) commands.
!
--command
The command to execute; default: ''
--keyId
The key ID to view (eg 00B5050F or 0x00B5050F); default: '__NULL__' (mandatory)
1.3.2.RELEASE
179
Command Index
This command does not accept any options.
--keyId
The key ID to trust (eg 00B5050F or 0x00B5050F); default: '__NULL__' (mandatory)
--keyId
The key ID to remove
'__NULL__' (mandatory)
trust
from
(eg
00B5050F
or
0x00B5050F);
default:
contained
in
--enabled
Activates development mode; default: 'true'
1.3.2.RELEASE
180
Command Index
poll speed --ms
--ms
The number of milliseconds between each poll; default: '__NULL__' (mandatory)
in
--enabled
Activates debug mode; default: 'true'
--name
Property file name (including .properties suffix); default: '__NULL__' (mandatory)
--path
Source path to property file; default: '__NULL__' (mandatory)
--name
Property file name (including .properties suffix); default: '__NULL__' (mandatory)
--path
Source path to property file; default: '__NULL__' (mandatory)
1.3.2.RELEASE
181
Command Index
--key
The property key that should be removed; default: '__NULL__' (mandatory)
--name
Property file name (including .properties suffix); default: '__NULL__' (mandatory)
--path
Source path to property file; default: '__NULL__' (mandatory)
--key
The property key that should be changed; default: '__NULL__' (mandatory)
--value
The new vale for this property key; default: '__NULL__' (mandatory)
contained
in
in
--interface
The java interface to apply this annotation to; default: '__NULL__' (mandatory)
--entity
The domain entity this repository should expose; default if option not present: '*'
1.3.2.RELEASE
182
Command Index
A.35.1. permissionEvaluator
Create a permission evaluator
permissionEvaluator --package
--package
The package to add the permission evaluator to; default: '__NULL__' (mandatory)
contained
in
--serverUrl
URL of the server where the web application is available, including protocol, port and hostname;
default: 'http://localhost:8080/'
--controller
Controller to create a Selenium test for; default: '__NULL__' (mandatory)
--name
Name of the test; default: '__NULL__'
--serverUrl
URL of the server where the web application is available, including protocol, port and hostname;
default: 'http://localhost:8080/'
1.3.2.RELEASE
contained
in
183
Command Index
--interfacePackage
The java interface package; default: '__NULL__' (mandatory)
--classPackage
The java package of the implementation classes for the interfaces; default: '__NULL__'
--useXmlConfiguration
When true, Spring Roo will configure services using XML. This is the default behavior for services
using GAE; default: '__NULL__'
--interfacePackage
The java interface package; default: '__NULL__' (mandatory)
--classPackage
The java package of the implementation classes for the interfaces; default: '__NULL__'
--requireAuthentication
Whether or not users must be authenticated to use the service; default if option present: 'true';
default if option not present: 'false'
--authorizedRole
The role authorized the use the methods in the service (additional roles can be added after creation);
default: '__NULL__'
--usePermissionEvaluator
Whether or not to use a PermissionEvaluator; default if option present: 'true'; default if option not
present: 'false'
--useXmlConfiguration
When true, Spring Roo will configure services using XML.; default: '__NULL__'
--interface
The java interface to apply this annotation to; default: '__NULL__' (mandatory)
1.3.2.RELEASE
184
Command Index
--class
Implementation class for the specified interface; default: '__NULL__'
--entity
The domain entity this service should expose; default if option not present: '*'
--requireAuthentication
Whether or not users must be authenticated to use the service; default if option present: 'ture';
default if option not present: 'false'
--authorizedRoles
The role authorized the use the methods in the service; default: '__NULL__'
--usePermissionEvaluator
Whether or not to use a PermissionEvaluator; default if option present: 'true'; default if option not
present: 'false'
--useXmlConfiguration
When true, Spring Roo will configure services using XML.; default: '__NULL__'
--interface
The java interface to apply this annotation to; default: '__NULL__' (mandatory)
--class
Implementation class for the specified interface; default: '__NULL__'
--entity
The domain entity this service should expose; default if option not present: '*'
--useXmlConfiguration
When true, Spring Roo will configure services using XML.; default: '__NULL__'
--class
The type to be made searchable; default if option not present: '*'
1.3.2.RELEASE
185
Command Index
solr all
--searchServerUrl
The URL of the Solr search server; default: 'http://localhost:8983/solr'
--name
The name of the tailor configuration; default: '__NULL__' (mandatory)
1.3.2.RELEASE
186
Command Index
--privacyLevel
The new UAA privacy level to use; default: '__NULL__' (mandatory)
--file
The file to save the UAA JSON content to; default: '__NULL__'
in
--formBackingType
The finder-enabled type; default: '__NULL__' (mandatory)
--class
The controller java type to apply this annotation to; default if option not present: '*'
1.3.2.RELEASE
187
Command Index
web mvc finder all
contained
in
Web
Json
Commands
are
contained
org.springframework.roo.addon.web.mvc.controller.json.WebJsonCommands.
in
--flowName
The name for your web flow; default: '__NULL__'
--jsonObject
The JSON-enabled object
'__NULL__' (mandatory)
which
backs
this
Spring
MVC
controller.;
default:
--class
The java type to apply this annotation to; default if option not present: '*'
--package
The package in which new controllers will be placed; default: '__NULL__'
1.3.2.RELEASE
188
1.3.2.RELEASE
189
1.3.2.RELEASE
190
Repository
Entity
@RooEntity
Command
entity
@RooRepositoryJpa @RooJpaEntity
entity
activeRecord false +
repository jpa
Spring
MongoDB
@RooRepositoryMongo
@RooMongoEntity
entity mongo +
repository mongo
Data
1.3.2.RELEASE
191
Repository
Entity
@RooJpaActiveRecord
Command
entity jpa
@RooJpaRepository@RooJpaEntity
entity
jpa
activeRecord false +
repository jpa
Spring
MongoDB
@RooMongoRepository
@RooMongoEntity
entity mongo +
repository mongo
Data
1.3.2.RELEASE
192
1.3.2.RELEASE
193
1.3.2.RELEASE
194
1.3.2.RELEASE
195
1.3.2.RELEASE
196
C.1. History
The Spring Roo available today is the result of relatively recent engineering, but the inspiration for
the project can be found several years earlier.
The historical motivation for "ROO" can be traced back to 2005. At that time the project's founder,
Ben Alex, was working on several enterprise applications and had noticed he was repeating the same
steps time and time again. Back in 2005 it was common to use a traditional layering involving DAOs,
services layer and web tier. A good deal of attention was also focused around that time on avoiding
anaemic domain objects and instead pursuing Domain Driven Design principles.
Pursuing a rich domain model led to domain objects that reflected proper object oriented principles,
such as careful application of encapsulation, immutability and properly defining the role of domain
objects within the enterprise application layering. Rich behaviour was added to these entities
via AspectJ and Spring Framework's recently-created @Configurable annotation (which enabled
dependency injection on entities irrespective of how the entities were instantiated). Naturally the web
frameworks of the era didn't work well with these rich domain objects (due to the lack of accessors,
mutators and no-argument constructors), and as such data transfer objects (DTOs) were created. The
mapping between DTOs and domain objects was approached with assembly technologies like Dozer.
To make all of this work nicely together, a code generator called Real Object Oriented - or "ROO" - was
created. The Real Object Oriented name reflected the rich domain object principles that underpinned
the productivity tool.
ROO was presented to audiences at the SpringOne Americas 2006 and TSSJS Europe 2007
conferences, plus the Stockholm Spring User Group and Enterprise Java Association of Australia. The
audiences were enthusiastic about the highly productive solution, with remarks like "it is the really
neatest and newest stuff I've seen in this conference" and "if ROO ever becomes an open source project,
I'm guessing it will be very polished and well-received". Nonetheless, other priorities (like the existing
Spring Security project) prevented the code from becoming release-ready. More than twelve months
later Ben was still regularly being asked by people, "whatever happened to the ROO framework?" and
as such he set out about resuming the project around August 2008.
By October 2008 a large amount of research and development had been undertaken on the new-andimproved ROO. The original productivity ideas within ROO had been augmented with considerable
feedback from real-life use of ROO and the earlier conferences. In particular a number of projects
in Australia had used the unreleased ROO technology and these projects provided a great deal of
especially useful feedback. It was recognised from this feedback that the original ROO model suffered
from two main problems. First, it did not provide a highly usable interface and as such developers
required a reasonable amount of training to fully make use of Roo. Second, it imposed a high level
of architectural purity on all applications - such as the forced use of DTOs - and many people simply
didn't want such purity. While there were valid engineering reasons to pursue such an architecture, it
was the productivity that motivated people to use ROO and they found the added burden of issues like
DTO mapping cancelled out some of the gains that ROO provided. A mission statement was drafted
that concisely reflected the vision of the project, and this was used to guide the technical design.
1.3.2.RELEASE
197
Project Background
In early December 2008 Ben took a completely rewritten ROO with him to SpringOne Americas
2008 and showed it to a number of SpringSource colleagues and community members. The response
was overwhelming. Not only had the earlier feedback been addressed, but many new ideas had been
incorporated into the Java-only framework. Furthermore, recent improvements to AspectJ and Spring
had made the entire solution far more effective and efficient than the earlier ROO model (such as
annotation-based component scanning, considerable enhancements to AJDT etc).
Feedback following the December 2008 demonstrations led to considerable focus on bringing the ROO
technology to the open source community. The name "ROO" was preserved as a temporary codename,
given that we planned to select a final name closer to official release. The "ROO" project was then
publicly presented on 27 April 2009 during Rod Johnson's SpringOne Europe keynote, "The Future
of Java Innovation". As part of the keynote the ROO system was used to build a voting application
that would allow the community to select a final name for the new project. The "ROO" name was
left as an option, although the case was changed to "Roo" to reflect the fact it no longer represented
any acronym. The resulting votes were Spring Roo (467), Spring Boost (180), Spring Spark (179),
Spring HyperDrive (64) and Spring Dart (62). As such "Spring Roo" became the official, communityselected name for the project.
Roo 1.0.0.A1 was released during the SpringOne Europe 2009 conference, along with initial tooling for
SpringSource Tool Suite. The Roo talk at the SpringOne Europe 2009 conference was the most highly
attended session and there was enormous enthusiasm for the solution. Roo 1.0.0.A2 was published
a few weeks later, followed by several milestones. By SpringOne/2GX North America in October
2009, Roo 1.0.0 had reached Release Candidate 2 stage, and again the Roo session was the most
highly attended session of the entire conference. SpringSource also started hosting the highly popular
Spring Discovery Days and showing people around the world what they could do with the exciting
new Roo tool. Coupled with Twitter, by this stage many members of the Java community had caught
a glimpse of Roo and it was starting to appear in a large number of conferences, user group meetings
and development projects - all before it had even reached 1.0.0 General Availability!
1.3.2.RELEASE
198
Project Background
"without compromising": Other tools, methodologies and frameworks claim to create solutions that
provide these benefits. However, they impose a serious cost in critical areas. We refuse to make
this compromise.
"engineering integrity": We embrace OO and language features the way Java language designers
intended, greatly simplifying understanding, refactoring, testing and debugging. We don't force
projects with significant performance requirements to choose between developer productivity or
deployment cost. We move processing to Generation IV web clients where possible, embrace
database capabilities, and offer an optimal approach to runtime considerations.
"or flexibility": Projects are similar, but not identical. Developers need the flexibility to use
a different technology, pattern or framework when required. While we don't lock developers
into particular approaches, we certainly provide an optimal experience when following our
recommendations. We ensure that our technology is interface agnostic, gracefully supporting both
mainstream IDEs plus the command line. Of course, we support any reasonable deployment
scenario, and particularly the emerging class of Generation IV web clients.
We believe that Spring Roo today represents a successful embodiment of this mission statement. While
we still have work to do in identified feature areas such as Generation IV web clients, these are easilyachieved future directions upon the existing Roo foundation.
1.3.2.RELEASE
199
1.3.2.RELEASE
200
Roo Resources
specifying the version of Roo that you're running (as can be obtained from the "version" command),
and if you're having trouble with IDE integration, the exact version of the IDE you are using (and,
if an Eclipse-based IDE, the version of AspectJ Development Tools in use). Another good source of
advice on how to ask questions on the forum can be found in Eric Raymond's often-cited essay, "How
to Ask Smart Questions".
If you believe you have found a bug or are experiencing an issue, it is recommended you first log a
message on the forum. This allows other experienced users to comment on whether it appears there
is a problem with Roo or perhaps just needs to be used a different way. Someone will usually offer a
solution or recommend you log a bug report (usually by saying "please log this in Jira"). When you
do log a bug report, please ensure you link to the fully-qualified URI to the forum post. That way
the developer who attempts to solve your bug will have background information. Please also post the
issue tracking link back in thread you started on the forum, as it will help other people cross-reference
the two systems.
D.4. Twitter
Roo Hash Code (please include in your tweets, and also follow for low-volume announcements):
@SpringRoo
Follow the core Roo development team for interesting Roo news and progress (higher volume than
just following @SpringRoo, but only a few Tweets per week): @alankstewart.
Many people who use Roo also use Twitter, including the core Roo development team. If you're a
Twitter user, you're welcome to follow the Roo development team (using the Twitter IDs above) to
receive up-to-the-minute Tweets on Roo activities, usage and events.
The Roo team also monitors Tweets that include @SpringRoo, so if you're Tweeting about Roo, please
remember to include @SpringRoo somewhere in the Tweet. If you like Roo or have found it helpful
on a project, please Tweet about it and help spread the word!
We do request that you use the Community Forums if you have a question or issue with Roo, as
140 characters doesn't allow us to provide in-depth technical support or provide a growing archive of
historical answers that people can search against.
1.3.2.RELEASE
201
Roo Resources
Because open source projects receive numerous enhancement requests, we generally prioritise
enhancements that have patches included, are quick to complete or those which have received a large
number of votes. You can vote for a particular issue by logging into Jira (it's fast, easy and free to
create an account) and click the "vote" link against any issue. Similarly you can monitor the progress
on any issue you're interested in by clicking "watch".
Enhancement requests are easier to complete (and therefore more probable to be actioned) if they
represent fine-grained units of work that include as much detail as possible. Enhancement requests
should describe a specific use case or user story that is trying to be achieved. It is usually helpful to
provide a Roo sample script that can be used to explain the issue. You should also consider whether
a particular enhancement is likely to appeal to most Roo users, and if not, whether perhaps writing it
as an add-on would be a good alternative.
D.9. Other
Please let us know if you believe it would be helpful to list any other resources in this documentation.
1.3.2.RELEASE
202