Last updated by 5 years ago

Page: 1.1-beta3 Release Notes, Version:9

Grails 1.1 Beta 3 Release Notes

XXX of January 2009

Grails 1.1 Beta 3 is not out yet, this page is just a placeholder

SpringSource and the Grails development team are pleased to announce the 1.1 beta 2 release of the Grails web application development framework.

Grails is a dynamic web application framework built on Java and Groovy, leveraging best of breed APIs from the Java EE 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.

Further information about the release can be obtained using the links below:

New features in 1.1 are described below.

New Features

GORM

Standalone GORM

Grails 1.1 comes with support for using GORM outside of Grails using Spring namespace configuration to setup the necessary Hibernate SessionFactory:

<gorm:sessionFactory base-package="org.grails.samples" 
                     data-source-ref="dataSource"
	             message-source-ref="messageSource">
   <property name="hibernateProperties">
        <util:map>
             <entry key="hibernate.hbm2ddl.auto" value="update"/>
         </util:map>
   </property>
</gorm:sessionFactory>

This example will scan the "org.grails.samples" package. Each GORM entity needs to be marked with the grails.persistence.Entity annotation:

@Entity
class Book {
    String title
}

See the Spring MVC petclinic example in GRAILS_HOME/samples/petclinic-mvc for more info.

Better GORM events

Previously, GORM supported beforeInsert, beforeUpdate and beforeDelete events, now there is afterInsert, afterUpdate and afterDelete to complete the picture

Persistence of Collections of Basic Types

GORM now supports persisting basic types like String, Integer and so on using a join table:

class Person {
   static hasMany = [nicknames:String]
}

Persistence of Collections of Enum Types

GORM now supports persisting collections of enum types:

enum VehicleStatus { OFF, IDLING, ACCELERATING, DECELARATING }
class Truck {
   static hasMany = [statuses:VehicleStatus]
}

Read-Only Access to Objects

Persistent instances can now be loaded in a read-only state using the read method:

def book = Book.read(1)

Default Sort Order

Associations can now be sorted using a default sort order declared at the class level:

class Book {
  String title
  static mapping = {
     sort "title"
  }
}

Or at the association level:

class Author {
    static hasMany = [books:Book]
    static mapping = {
              books sort:"title"
    }
}

Batch Fetching

GORM now supports configuring batch fetching (an optimization of lazy loading) using the ORM DSL at the class level:

class Book {
  String title
  static mapping = {
     batchSize 15
  }
}

Or at the association level:

class Author {
    static hasMany = [books:Book]
    static mapping = {
              books batchSize:15
    }
}

Improvements to Dynamic Finders

There is a new InList suffix that can be used with dynamic finders:

def groovyBooks = Book.findByAuthorInList(['Dierk Koenig', 'Graeme Rocher'])

Dynamic finders can also now use the query cache:

def books = Book.findByTitle("Groovy in Action", [cache:true] )

And upgrade to a pessimistic lock:

def books = Book.findByTitle("Groovy in Action", [lock:true] )

Legacy Mapping for Unidirectional One-to-manys

Unidirectional One-to-many associations can use the joinTable argument to alter the way they map to the underlying database:

class Book {
 String title
 static belongsTo = Author
 static hasMany = [authors:Author]

static mapping = { authors joinTable:[name:"mm_author_books", key:'mm_book_id' ] } } class Author { String name static hasMany = [books:Book] static mapping = { books joinTable:[name:"mm_author_books", key:'mm_author_id'] } }

Enhanced Enum Support

Enum types can now specify a getId() method that GORM will call to persist the state of an enum. This an alternative to using either the Enum name or the ordinal value to persist an enums state.

enum Country {
   AUSTRIA('at'),
   UNITED_STATES('us'),
   GERMANY('de');

final String id

Country(String id) { this.id = id } }

Plugins

Global Plugins

Plugins can now be installed globally for all applications:

grails install-plugin webtest -global

Multiple Plugin Repositories

Grails now supports the ability to configure multiple plugin repositories by providing a USER_HOME/.grails/settings.groovy file or a grails-app/conf/BuildConfig.groovy file that contains the configured repository details:

grails.plugin.repos.discovery.myRepository="http://svn.codehaus.org/grails/trunk/grails-test-plugin-repo" 
grails.plugin.repos.distribution.myRepository="https://svn.codehaus.org/grails/trunk/grails-test-plugin-repo"

The Grails plugin discovery commands like list-plugin and install-plugin will then automatically work against all configured repositories. To release a plugin to a specific repository you can use the repository argument:

grails release-plugin -repository=myRepository

Automatic Transitive Plugin Resolution

Plugins no longer need to be checked into SVN and will automatically be installed via a plugins metadata when the application is first loaded.

In addition, plugin dependencies are now resolved transitively.

Plugin Scopes and Environments

Plugins can now be scoped using either the environment or predefined build scopes:

def environments = ['dev', 'test']
def scopes = [excludes:'war']

The plugins will only load in those environments and will not be packaged into the WAR file. This allows "development-only" plugins to not be packaged for production use.

Modular Application Development with Plugins

An application can now load plugins from anywhere on the file system, even if they have not been installed. Simply add the location of the (unpacked) plugin to you BuildConfig.groovy file:

// Useful to test plugins you are developing.
grails.plugin.location.jsecurity = "/home/dilbert/dev/plugins/grails-jsecurity"

// Useful for modular applications where all plugins and // applications are in the same directory. grails.plugin.location.'grails-ui' = "../grails-grails-ui"

This is particularly useful in two cases:

  1. You are developing a plugin and want to test it in a real application without packaging and installing it first.
  2. You have split an application into a set of plugins and an application, all in the same "super-project" directory.

Testing

The Test Framework

The new test framework, available as a plugin for the 1.0.x series, is now integrated in Grails 1.1.

The testing framework adds the capability to mock the behavior of all common types including controllers, domain class, tag libraries and url mappings allowing for shorter, fast running unit tests.

class SongTests extends grails.test.GrailsUnitTestCase {

void testMinimumDuration() { mockDomain(Song) def song = new Song(duration: 0) assertFalse 'validation should have failed', song.validate() assertEquals "min", song.errors.duration } }

Data Binding

Data Binding a Subset of Properties

It is now simpler to bind data to a subset of properties. Previously you could use the syntax:

person.properties = params

Which would bind all the incoming request parameters to the person. If you didn't want that behavior you could use the bindData method. Now you can bind to a subset of properties using the subscript operator:

person.properties["firstName","lastName"] = params

And access a subset of the domain classes properties using the same syntax:

person.properties["firstName","lastName"].each { println it }

Data Binding for Collection Types

Grails now supports data binding to collections types including lists, sets and maps.

<g:textField name="books[0].title" value="the Stand" />
<g:textField name="books[1].title" value="the Shining" />
<g:textField name="books[2].title" value="Red Madder" />

Grails will auto-instantiate domain instances at the given indices and the necessary values will be populated in the association.

Scaffolding

Templates and Dynamic Scaffolding

Dynamic scaffolding now uses the templates that can be installed via the install-templates command.

Support for more association types

Scaffolding now supports many-to-many and unidirectional one-to-many associations.

Controllers

Handling of Duplicate Submits

Grails now features built in support for handling duplicate form submissions using the "Synchronizer Token Pattern". First you declare a token in a form:

<g:form useToken="true">

Then using the new withForm method you can detect duplicate or invalid requests:

withForm {
   // good request
}.invalidToken {
   // bad request
}

Forwarding Requests

You can now forward a request as an alternative to redirecting with the new forward method:

forward controller:"home", action:"index"

Groovy Server Pages

JSP Tag library support in JSP

GSP now supports the ability to re-use JSP tag libraries:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatNumber value="${10}" pattern=".00"/>

JSP tags can also be called as methods like normal GSP tags:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
${fmt.formatNumber(value:10, pattern:".00")}

Template Namespace

There is now a specialized namespace for using templates. So given a template called _tableRow.gsp:

<tr>
    <td class="prop">${label}</td>
    <td class="value">${value}</td>
</tr>

It can now be called using the tmpl namespace as follows:

<tmpl:tableRow label="one" value="two" />

Server Side Includes

There is a new <g:include> tag that can be used to include the response of another controller, action or view inside the current view:

<g:include controller="book" action="list"></g:include>

This can also be used from a controller or another tag library:

def content = include(controller:"book", action:"list")

Performance Improvements

GSPs now render an order of maginitude faster than they used to do resulting in an overall performance boost for Grails applications.

Project Infrastructure

Maven integration

Grails 1.1 comes with an associated Maven plugin and archetype that allows you to build your Grails project easily using Maven. Follow the instructions here and either use the archetype to create a new Grails project, or run:

mvn grails:create-pom
to create a Maven POM for an existing project.

Ant + Ivy Integration

Grails now creates an Ant build.xml and corresponding ivy.xml file for each project allowing you to build a Grails project on any build server that supports Ant (like CruiseControl and Hudson) without needing Grails installed on the target server.

Spring Namespace Support in BeanBuilder

Grails' Spring DSL has been extended to include access to the Spring namespace APIs allowing you to easily use Spring advanced AOP support (among other things):

beans = {
   xmlns aop:"http://www.springframework.org/schema/aop"

fred(Person) { name = "Fred" age = 45 } birthdayCardSenderAspect(BirthdayCardSender)

aop { config("proxy-target-class":true) { aspect( id:"sendBirthdayCard",ref:"birthdayCardSenderAspect" ) { after method:"onBirthday", pointcut: "execution(void ..Person.birthday()) and this(person)" } } } }

Environment and Metadata API

There is a new API to access the current Environment:

import grails.util.Environment

...

switch(Environment.current) { case Environment.DEVELOPMENT: configureForDevelopment() break case Environment.PRODUCTION: configureForProduction() break }

There is also a new class for easily accessing application meta-data:

def metadata = grails.util.Metadata.current
println metadata.applicationName
println metadata.applicationVersion

Log4j DSL

A new Log4j DSL is available that replaces the old way of configuring Log4j:

log4j = {
    error  'org.codehaus.groovy.grails.web.servlet',  //  controllers
	       'org.codehaus.groovy.grails.web.pages' //  GSP

warn 'org.mortbay.log' }

Full documentation for the Log4j DSL is available in the user guide.

Flexible Build Configuration

A new grails-app/conf/BuildConfig.groovy file is available that allows you to configure different aspects of the Grails build including output paths and servers used for resolution of plugins:

grails.work.dir="/tmp/work"
grails.plugins.dir="/usr/local/grails/plugins"
grails.project.test.reports.dir="/usr/local/grails/test-reports"

Non-interactive mode

Grails now supports a --non-interactive flag at the command line that can be passed in order to disable any user prompts:

grails run-app --non-interactive

This is useful for continuous integration servers.

Encrypted Data Sources

DataSource passwords can now be encrypted using a supplied codec class:

dataSource {
       username = "foo"
       password = "438uodf9s872398783r"
       passwordEncryptionCodec="my.company.encryption.BlowfishCodec"
}

The supplied codec uses Grails' existing codec mechanism

Upgrade notes

Grails 1.1 has a number of changes, but should be mostly backwards compatible with 1.0.x series applications. If you have issues please report them. The following is a list of known issues that need to be considered when upgrading

  • Plugins are now stored in your USER_HOME directory. You will need to re-install your plugins or run:
grails -Dgrails.plugins.dir=./plugins run-app
  • Enums are now mapped onto the database with String values instead of ordinals by default
  • jsession id is now disabled by default. See GRAILS-3364
  • GSP whitespace handling has been changed for the better, you may have more whitespace than before. See GRAILS-3277
  • The The grails.testing.reports.destDir config option has been replaced by grails.project.test.reports.dir
  • PreInit.groovy is now BuildConfig.groovy
  • The allowedMethods property in a controller should now be marked static. Non static version is deprecated but still works and will result in messages on the console.