1.0-RC1 Release Notes

Last updated by admin 4 years ago

Grails 1.0-RC1 Release Notes

16th of October 2007

The Grails development team has reached another milestone and is pleased to announce the release of version 1.0-RC1 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 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.

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

  • GORM features ORM DSL for advanced Mappings
  • Support for easy to use Filters
  • Tag Library Improvements - Namespaces, body variables, page scope, improved <g:set> tag and more
  • Controllers Improvements - Multi-dimensional params object, data binding retains type conversion errors
  • URL Mapping Improvements - Mapping response codes, mapping directly onto views and more
  • GORM Improvements - Pessimistic locking support, session flushing control
  • Config Improvements - Support for JNDI data sources, property placeholders and flexible config locations

New from the Plug-in community

The Grails team are not the only ones who have been busy. During the development of Grails 1.0-RC1 the following plug-ins have emerged:

  • Liquibase and Dbmigrate - Two different plug-ins that provide database migration and versioning features
  • Dynamic Javascript - A plug-in that provides a JavaScript DSL similar to RJS
  • Maven Tools for Grails - A plug-in that integrates Grails with Maven 2
  • I18n Templates - A plug-in that provides internationalization (i18n) features to Grails' scaffolding capability

New Features

ORM DSL

Grails 1.0 RC1 introduces an Object Relational Mapping (ORM) Domain Specific Language (DSL) that reduces the need to fallback to traditional Hibernate mapping. The DSL allows customization of the following aspects:

  • Table and column names
  • Inheritance strategy
  • Second-level cache configuration
  • Id generation strategy
  • Composide Id support
  • Eager/Lazy loading
  • Database indices
  • Custom Hibernate user types
Example:
class Person {
  String firstName
  static hasMany = [addresses:Address]
  static mapping = {
      table 'people'
      version false
      id column:'person_id'
      columns {
          firstName column:'First_Name'
          addresses lazy:false
      }
  }
}
class Address {
  String street
  String postCode
}

Refer to the full documentation here.

Filters

Grails has up until now supported interceptors that can be used within controllers. Filters however offer a more powerful way of defining cross cutting concerns.

Filters can be applied to an entire controller, only specific actions or entire URI spaces. Example:

class SecurityFilters {
   def filters = {
       loginCheck(controller:'*', action:'*') {
           before = {
              if(!session.user && !actionName.equals('login')) {
                  redirect(action:'login')
                  return false
               }
           }

} } }

Refer to the full documentation here.

Tag Library Improvements

Tags have gotten an injection of life with numerous new features listed below

Full support for namespaces

Tags can be placed within a given name space and then invoked either as methods or as tags:

// tag code
class FormatTagLib {
    static namespace = 'fmt'
    def dateFormat = { attrs ->
         out << new java.text.SimpleDateFormat(attrs.format).format(attrs.value)
    }
}
// gsp code
<fmt:dateFormat format="dd-MM-yyyy" value="${new Date()}" />
// or as a method
${fmt.dateFormat(format:'dd-MM-yyyy',value:new Date())}

Body variables

Tags can now also pass variables to the body of a tag (previously you could only pass the default "it" variable) using named parameters when invoking the body:

// tag code
def repeat = { attrs, body ->
   def count = attrs.times.toInteger()
   count.times {
       body(num:it)
   }
}

// gsp code <g:repeat times="10">Number: ${num}</g:repeat>

Improved support for scopes

There is a new {{pageScope}} variable that can be used inside tag libraries to store variables within page scope. And the <g:set> tag has been updated to allow the definition of the scope:

<g:set var="foo" value="${new Date()}" scope="page" />
<g:set var="bar" value="${new Date()-7}" scope="session" />

Controller Improvements

Multi-D params

The Grails params object (which is a map of request parameters) is now multi-dimensional. For example if you have a form that submits multiple parameters separated by a ".":

<g:textField name="book.title" value="The Stand" />
<g:textField name="author.name" value="Stephen King" />

You can obtain only the params for the "book" using array de-reference style syntax:

params["book"]
This aids in data binding when dealing with multiple domain classes:

def book = new Book(params["book"])
def author = new Author(params["author"])
or
def book = new Book(title:params["book"]?.title)

Data binding and type conversion errors

Grails now full leverages Spring's data binding capability by retaining type conversion errors and the original value sent my the user:

def site = new Site(url:"bad_url")

assert site.hasErrors() assert "bad_url" == site.errors.getFieldError("url")

URL Mapping Improvements

Custom URL mappings have been made more powerful with support for mapping response codes, views, and double wildcards in the mapping.

Response Codes & Error Handling

You can now define mappings onto response codes to deal with HTTP errors. Example:

class UrlMappings {
  static mappings = {
     "500"(controller:"errors", action:"serverError")
     "404"(controller:"errors", action:"notFound")
     "403"(controller:"errors", action:"forbidden")
  }
}

Mapping URLs onto views

If you don't need a controller and action you can map a URL directly onto a view. Some examples:

static mappings = {
      "/"(view:"/index")  // map the root URL
      "/help"(controller:"site",view:"help") // to a view for a controller
  }

Double Wildcards

You can now define a double wildcard that allows you to map variable length URLs to controllers and views:

static mappings = {
      // will match /product/MacBook and /product/Apple/MacBook
      "/products/**"(controller:"product")  
  }

If you need to capture the value of the remaining path as a request param you can use a variable:

static mappings = {
      "/products/$path**"(controller:"product", action:"show")  
  }
  // then in the action
  def show = {
      def path = params.path
      render path // prints "MacBook" or "Apple/MacBook" 
  }

GORM Improvements

Pessimistic Locking

By default GORM domain classes are configured for optimistic locking. You can now use pessimistic locking to get SQL "SELECT … FOR UPDATE" functionality:

def book = Book.get(1)

book.lock() book.title = "The Stand" book.save()

Session flushing control

Normally Grails controls when and how the session is flushed, however if you need fine grained control over Hibernate session flushing you can now control when the session is flushed with saves and deletes:

def book = Book.get(1)
book.save(flush:true)
// or book.delete(flush:true)

Config Improvements

JNDI Data Sources

Grails now has improved support for JNDI data sources via a {{jndiName}} property in the DataSource definition:

dataSource {
    jndiName = "java:comp/env/myDataSource"
}

Flexible Config Locations

You can now define multiple internal and external config locations:

grails.config.locations = [ "classpath:${appName}-config.properties",
                             "classpath:${appName}-config.groovy",
                             "file:${userHome}/.grails/${appName}-config.properties",
                             "file:${userHome}/.grails/${appName}-config.groovy"]

Grails also now supports property place holder configuration for Spring on properties defined in Config.groovy as well as property "override" configuration using a specials {{beans}} scope in Config.groovy:

beans {
   myService.someProperty = "foo"
}