0.5 Release Notes
30 April 2007The Grails development team has reached another milestone and is pleased to announce the release of version 0.5 of the Grails web-application development framework.Grails is a dynamic web-application framework built in Java and Groovy, leveraging best of breed APIs from the J2EE sphere including Spring, Hibernate and SiteMesh. Grails brings to Java and Groovy developers the joys of convention-based rapid development while allowing them to leverage their existing knowledge and capitalize on the proven and performant APIs Java developers have been using for years.Development has been intense since the release of 0.4.2 at the end of February, tackling over 190 issues in this period. This release has seen exciting contributions from new team members and users and significant functionality enhancements.Thank you to all the team members, patch contributors and users. A lot of hard work has gone into this release - we hope you enjoy using this latest installment of the Grails adventure.New Features
- Custom URL Mappings
- Command objects / form validation
- List & Map support in GORM
- Support for composition in domain class (Hibernate "components")
- Base64 codec
- Dependency resolution with Ivy
- Project metadata and versioning support, smarter scripts and upgrade processes
- Script event hooks
- Automatic addition of log objects to all artefacts
- New Artefact API available to Plugins
Improvements
- Major improvements to artefact reloading
- Improved relationship management methods in GORM
- Cascading validation
- Retrieving multiple objects with Book.getAll(1,2,3)
- Using named HQL parameters in find() methods
- Clean up of some legacy constraints issues
- Performance improvements (40-50% faster)
- Taglib optimisations
- Improvements to scaffolding (sortable columns, pagination of large resultsets, etc.)
- I18N improvements
- Overhauled GSP view loading
- Even greater test coverage of the core Grails code
- Many many bug fixes
Detailed examples
Custom URL Mappings
You can now create a URL mapping class that uses, for those interested, a dynamic builder/metaclass mechanism to map the URI space of your application to your controllers and actions in almost any way you like. You can pull out parts of the URL as variables and even apply constraints to these.On top of this, grails taglibs that produce links are smart and will reverse map controller/action combinations to URLs from the mappings, so links generated within your pages are consistent with your public URL interface defined in your mappings.Example:class MyUrlMappings {
static mappings = {
"/product/$id" {
controller = "product"
action = "show
}
"/$id/$year/$month/$day" {
controller = "blog"
action = "show"
constraints {
year(matches:/d{4}/)
month(matches:/d{2}/)
day(matches:/d{2}/)
}
}
}
}This removes the necessity to use something like Apache's mod_rewrite to produce user-friendly URLs or to abstract your URL space away from your implementation.Documentation
Command Objects / Form validation
Grails has always had domain class constraints, but often a form or request parameters do not relate directly to a domain class. New in 0.5, command objects are automatically created and populate by Grails when the request is received, and validated against database-like constraints, before your action is even called.Example:class LoginController {
def login = { LoginCommand cmd ->
if(cmd.hasErrors()) {
redirect(action:'loginForm')
}
else {
// do something else
}
}
}class LoginCommand {
String username
String password
static constraints = {
username(blank:false, minSize:6)
password(blank:false, minSize:6)
}
}Any Groovy class can be used as a command object, with the standard Grails property binding and validation options. You just specify the typed parameters to the action closure and Grails works out the rest!Documentation
List & Map support in GORM
GORM has been enhanced to support lists of domain objects in a relationship, as opposed to the default Set behaviour, providing ordered lists.// Support for Lists of objects class Author { List books static hasMany = [books:Book] }author.books[0] // get the first book
There is also support for Maps of standard non-domain types:
// Support for Maps of objects class Author { Map books // map of ISBN:book names }def a = new Author() a.books = ["1590597583":"Grails Book"] a.save()
...as well as maps of standard type keys to domain objects:
// If you want a map of domain classes you can do class Book { Map authors static hasMany = [authors:Author] }def a = new Author(name:"Stephen King")def book = new Book() book.authors = [stephen:a] book.save()
Documentation
Support for composition in domain class (Hibernate "components")
By default GORM currently uses table-per-hierarchy mapping of classes to the database, which means that classes in relationships typically are stored in a separate table.You now can use the Hibernate composition mechanism to embed the data from objects that would otherwise be considered relationships, within the main table used for the outer class, using the "embedded" declaration.class Address {
String street
// …
String country
}class Person {
String firstName
String lastName Address homeAddress
Address workAddress static embedded = ['homeAddress', 'workAddress']
}The "embedded" property is set to the list of property names that represent complex properties that should be written into the table directly instead of forming a relationship.Documentation
Base64 codec
Augmenting the existing super-useful codecs supplied in 0.4, we have now added a Base64 codec so that you can now write code such as this anywhere in your Groovy code or GSPs:Your registration code is: user.registrationCode.encodeAsBase64()
Documentation
Dependency resolution with Ivy
We've added support for Ivy dependency resolution for your projects. There are two new targets for this:grails install-ivy
With the above run once per-project, you can then execute:
grails get-dependencies
To update your project's dependencies.
Project metadata and versioning support, smarter scripts and upgrade processes
The days of accidentally running with the wrong Grails version for your project are gone with 0.5 and future versions. Applications have metadata stored in a file (not generally for user editing) that includes the required version of grails, and a version number of your application.Most of the grails targets therefore refuse to run if the grails version you are using in GRAILS_HOME does not match that of the project, so that you never omit to run grails upgrade.Your application's version number is now included in the filename of generated war files. You can set the version number with "grails set-version"
Furthermore, you can now override the name used for your application so that it does not use the parent directory name.Script event hooks
A new event mechanism allows target scripts, even those in plugins and your custom application scripts, to fire and respond to events. By default we have events for artifact and file creation, plugin installation, script shutdown, and progress notifications. This allows, for example, integration with Growl on Mac OS X to provide on-screen notifications when grails tasks complete.
DocumentationAutomatic addition of log objects to all artefacts
Version 0.4 added an implicit "log" object for controllers. We have now expanded this feature to all artefact classes in the application. This means that all domain classes, services, jobs, controllers and so on (all declared artefacts using the artefact API) receive an implicit log object of their own.The logs are named in such a way that you can controll the logging of individual artefacts or the category of artefacts they belong to, or all of your artefacts in the application.DocumentationNew Artefact API available to Plugins
The internal artefact mechanisms have been overhauled to allow plugins to register first-class artefacts of their own that will be managed just like all other grails artefacts, and receive implicit log objects and other features.DocumentationImprovements
Major improvements to artefact reloading
Automatic reloading of modified code at runtime is a major productivity boost, and one of the most enjoyable parts of using Grails versus traditional Java web-application development. In this release we added support for reloading of domain classes, transactional services and Quartz jobs.Improved relationship management methods in GORM
Along with some of our users, we thought that the implicit addXXXX methods in 0.4 were nice but bit clunky when you had multiple relationships of the same type. We've sorted this out for 0.5 and are proud to introduce the minor but important change from addXXXX to addToXXXX methods, where the latter new form takes the name of the property (collection) not the type of the relationship:def a = new Author(name:"Stephen King") .addToBooks(title:"IT") .addToBooks(title:"The Stand") .save()author.removeFromBooks(myBook)
You will also notice we now have the orthogonal removeFromXXXX which manages the bi-directional references if they exist.Documentation



