1 Introduction - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith, Lari Hotari
Version: 2.5.1
Table of Contents
1 Introduction
Java web development as it stands today is dramatically more complicated than it needs to be. Most modern web frameworks in the Java space are over complicated and don't embrace the Don't Repeat Yourself (DRY) principles.Dynamic frameworks like Rails, Django and TurboGears helped pave the way to a more modern way of thinking about web applications. Grails builds on these concepts and dramatically reduces the complexity of building web applications on the Java platform. What makes it different, however, is that it does so by building on already established Java technologies like Spring and Hibernate.Grails is a full stack framework and attempts to solve as many pieces of the web development puzzle through the core technology and its associated plugins. Included out the box are things like:- An easy to use Object Relational Mapping (ORM) layer built on Hibernate
- An expressive view technology called Groovy Server Pages (GSP)
- A controller layer built on Spring MVC
- A command line scripting environment built on the Groovy-powered Gant
- An embedded Tomcat container which is configured for on the fly reloading
- Dependency injection with the inbuilt Spring container
- Support for internationalization (i18n) built on Spring's core MessageSource concept
- A transactional service layer built on Spring's transaction abstraction
1.1 What's new in Grails 2.5?
Grails 2.5.x is a small release that brings Grails up-to-date with the latest third-party dependencies including:- Groovy 2.4.x
- Spring 4.1.x
- Spring Loaded 1.2.4
1.2 What's new in Grails 2.4?
Groovy 2.3
Grails 2.4 comes with Groovy 2.3 which includes many new features and enhancements.For more information on Groovy 2.3, see the comprehensive release notes.Spring 4.0
Grails 2.4 comes with Spring 4.0.4 which includes many new features and enhancements. See the Spring documentation.Hibernate 4.3
Grails 2.4 now uses Hibernate 4.3.5 by default (Hibernate 3 is still available as an optional install).Standalone GORM and GSP
GORM and GSP can now be used outside of Grails. See the following guides / examples for more information:The Asset-Pipeline replaces Resources to serve static assets.
The asset-pipeline provides a new, easier to manage, faster means of managing your JavaScript, CSS, and images, while also bringing compiled client languages in to the fray as first-class citizens (e.g. CoffeeScript, LESS, SASS).All your assets should now live in thegrails-app/assets
subfolders. Three folders are made for you by default:
- javascript
- stylesheets
- images
//= require jquery //= require_self //= require file_a //= require_tree .console.log('some javascript');
<asset:javascript src="application.js"/> <asset:stylesheet href="application.css"/> <asset:image src="grails_logo.png" height="60" />
Static Compilation
Groovy is a dynamically dispatched, dynamically typed language by default but also has great support for static type checking and static compilation. See these notes on Groovy static compilation. In general, Grails supports Groovy's static compilation but there are a lot of special situations which are common in a Grails app which cannot be statically compiled. For example, if a method marked with@CompileStatic
contains code which invokes a GORM dynamic finder the code will not compile because the Groovy compiler cannot verify that the dynamic finder is valid. Grails 2.4 improves on this by allowing code to be statically compiled and still do things like invoke GORM dynamic finders.The grails.compiler.GrailsCompileStatic annotation behaves much like the groovy.transform.CompileStatic annotation and provides special handling to recognize Grails specific constructs.The following controller is marked with @GrailsCompileStatic
. All of the code that can be statically compiled will be statically compiled. When the compiler encounters code which can not be statically validated, normally that would result in a compile error. The Grails compiler will allow certain things to be considered valid and dynamically dispatch those instructions.// grails-app/controllers/com/demo/PersonController.groovy package com.demoimport grails.compiler.GrailsCompileStatic@GrailsCompileStatic class PersonController { def showKids() { def kids = Person.findAllByAgeLessThan(16) // … } }
import grails.compiler.GrailsCompileStatic import groovy.transform.TypeCheckingMode@GrailsCompileStatic class SomeClass { def update() { // this method will be statically compiled } @GrailsCompileStatic(TypeCheckingMode.SKIP) def save() { // this method will not be statically compiled } def delete() { // this method will be statically compiled } }
More Advanced Subqueries in GORM
The support for subqueries has been extended. You can now usein
with nested subqueries:def results = Person.where { firstName in where { age < 18 }.firstName }.list()
def results = Person.withCriteria {
notIn "firstName", Person.where { age < 18 }.firstName
}
def results = Person.where { age > where { age > 18 }.avg('age') }
def employees = Employee.where {
region.continent in ['APAC', "EMEA"]
}.id()def results = Sale.where {
employee in employees && total > 100000
}.employee.list()
def query = Employee.where {
def em1 = Employee
exists Sale.where {
def s1 = Sale
def em2 = employee
return em2.id == em1.id
}.id()
}
def results = query.list()
GORM for Hibernate in Unit tests
It is no longer necessary to create integration tests in order to test GORM interactions with Hibernate. You can now instead useHibernateTestMixin
:import grails.test.mixin.TestMixin import grails.test.mixin.gorm.Domain import grails.test.mixin.hibernate.HibernateTestMixin import spock.lang.Specification @Domain(Person) @TestMixin(HibernateTestMixin) class PersonSpec extends Specification { void "Test count people"() { expect: "Test execute Hibernate count query" Person.count() == 0 sessionFactory != null transactionManager != null session != null } }
dependencies {
test "org.grails:grails-datastore-test-support:1.0-grails-2.4"
}
plugins { runtime ':hibernate4:4.3.5.4' }
Views For Namespaced Controllers
The views for namespaced controllers may now be defined in thegrails-app/views/<namespace name>/<controller name>/
directory. See the Models And Views section for more details.Improved Programmatic Transactions
Transaction attributes may now be specified when invokingwithTransaction
.// the keys in the Map must correspond to properties // of org.springframework.transaction.support.DefaultTransactionDefinitionAccount.withTransaction([propagationBehavior: TransactionDefinition.PROPAGATION_REQUIRES_NEW, isolationLevel: TransactionDefinition.ISOLATION_REPEATABLE_READ]) { // … }
New Maven Plugin
The Maven plugin has been rewritten to use Aether for dependency resolution and can now be used with both Grails 2.3.x and Grails 2.4.x without releasing a new version of the plugin.This means that the Maven plugin version number is no longer tied to the version number of Grails and new releases of the Maven plugin will not come out with each new Grails release. Instead, users can continue to use the 2.4.0 version of the plugin for any version of Grails going forward.Unit Testing improvements
There is a Grails "unit testing runtime" that is based on the previous TestMixin based solution. It now separates the TestMixin classes and the actual runtime that handles the lifecycle of the Grails unit testing runtime. State of the runtime is not kept in static fields of the TestMixin classes anymore. The Groovy AST transformation behind the TestMixin annotation integrates to JUnit and Spock test classes by adding JUnit Rule fields to the class. In the previous solution, Before/BeforeClass and After/AfterClass annotations on AST added mix-in methods were used for the integration.Some of the main features:- The programming model remains the same for unit testing of Grails applications
- Setup/teardown method ordering is now deterministic because the integration is now using a single JUnit Rule field and the test runtime uses eventing internally to setup and teardown resources
- There are doWithSpring and doWithConfig callbacks for unit tests - these callback methods get called before the grailsApplication instance in the unit test runtime gets initialized.
- It's possible to register a Spock Mock as a bean to the application context of the Grails unit test runtime application - you can replace a collaborator bean with a mock
- It's possible to reuse a single application context for several test classes and control that so that tests can be made faster when required
- The Grails unit testing runtime has an event-based plugin architecture. It's possible to add new test runtime "features" with new test runtime plugin classes. The test runtime plugin API is due to change. Changes will be made based on feedback from the Grails community. The main interfaces of the API are currently documented in the javadocs: TestPlugin, TestEventInterceptor and TestEvent. Custom test plugins are currently limited since there isn't a solution for scanning for available test plugins. It's now possible to add custom test plugins in a static initialization block of a test class by calling TestRuntimeFactory.addPluginClass .
Improved Unit Testing Support For allowedMethods
The allowedMethods property is now respected in unit tests.// grails-app/controllers/com/demo/DemoController.groovypackage com.democlass DemoController { static allowedMethods = [save: 'POST', update: 'PUT', delete: 'DELETE'] def save() {
render 'Save was successful!'
} // …
}
// test/unit/com/demo/DemoControllerSpec.groovy package com.demoimport grails.test.mixin.TestFor import spock.lang.Specification import static javax.servlet.http.HttpServletResponse.*@TestFor(DemoController) class DemoControllerSpec extends Specification { void "test a valid request method"() { when: request.method = 'POST' controller.save() then: response.status == SC_OK response.text == 'Save was successful!' } void "test an invalid request method"() { when: request.method = 'DELETE' controller.save() then: response.status == SC_METHOD_NOT_ALLOWED } }
1.3 What's new in Grails 2.3?
Improved Dependency Management
The default dependency resolution engine used by Grails has been changed to Aether, the dependency resolution engine used by Maven. Which engine you use can be configured inBuildConfig
:grails.project.dependency.resolver = "maven" // or ivy
Data Binder
Grails 2.3 includes a new data binding mechanism which is more flexible and easier to maintain than the data binder used in previous versions. The new data binder includes numerous enhancements including:- Custom date formats on a per field basis using BindingFormat
- User defined data converters using ValueConverter
- User defined formatted data converters using BindingFormat and FormattedValueConverter
- Custom binding on a per class basis using BindUsing
- Custom binding on a per field basis using BindUsing
- By default all blank and empty Strings will be converted to null during data binding (configurable)
true
to the grails.databinding.useSpringBinder
property in grails-app/conf/Config.groovy
. Note that the legacy binder does not support any of the new features provided by the new data binder.Binding Request Body To Command Objects
If a request is made to a controller action which accepts a command object and the request includes a body, the body will be parsed and used to do data binding to the command object. This simplifies use cases where a request includes a JSON or XML body (for example) that can be bound to a command object. See the Command Objects documentation for more details.Domain Classes As Command Objects
When a domain class is used as a command object and there is anid
request parameter, the framework will retrieve the instance of the domain class from the database using the id
request parameter. See the Command Objects documentation for more details.Forked Execution
All major commands can now be forked into a separate JVM, thus isolating the build path from the runtime / test paths. Forked execution can be controlled via theBuildConfig
:grails.project.fork = [ test: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256, daemon:true], // configure settings for the test-app JVM run: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256], // configure settings for the run-app JVM war: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256], // configure settings for the run-war JVM console: [maxMemory: 768, minMemory: 64, debug: false, maxPerm: 256]// configure settings for the Console UI JVM ]
Test Runner Daemon
To speed up testing when using forked execution a new daemon will start-up in the background to run tests when using interactive mode. You can restart the daemon with therestart-daemon
command from interactive mode:$ grails> restart-daemon
Server-Side REST Improvements
Grails' REST support has been significantly improved with the addition of the following features:- Rich REST URL Mapping support with supports for resource mappings, singular resource mappings, nested resources, versioning and more
- New extensible response rendering and binding APIs
- Support for HAL, Atom and Hypermedia (HATEAOS)
- Scaffolding for REST controllers
New Scaffolding 2.0 Plugin
Grails' Scaffolding feature has been split into a separate plugin. Version 2.0 of the plugin includes support for generating REST controllers, Async controllers, and Spock unit tests.URL Mappings May Specify A Redirect
URL Mappings may now specify that a redirect should be triggered when the mapping matches an incoming request:class UrlMappings { static mappings = { "/viewBooks"(redirect: '/books/list') "/viewAuthors"(redirect: [controller: 'author', action: 'list']) "/viewPublishers"(redirect: [controller: 'publisher', action: 'list', permanent: true]) // … } }
Async support
Grails 2.3 features new Asynchronous Programming APIs that allow for asynchronous processing of requests and integrate seamlessly with GORM. Example:import static grails.async.Promises.* … def index() { tasks books: Book.async.list(), totalBooks: Book.async.count(), otherValue: { // do hard work } }
Encoding / Escaping Improvements
Grails 2.3 features dedicated support for Cross Site Scripting (XSS) prevention, including :- Defaulting to HTML escaping all GSP expressions and scriptlets
- Context sensitive encoding switching for tags
- Double encoding prevention
- Optional automatic encoding of all data in a GSP page not considered safe
Hibernate 3 and 4 support
The GORM for Hibernate 3 support for Grails has been extracted into a separate project, allowing new support for Hibernate 4 as a separate plugin.Controller Exception Handling
Controllers may define exception handler methods which will automatically be invoked any time an action in that controller throws an exception.// grails-app/controllers/demo/DemoController.groovy package democlass DemoController { def someAction() { // do some work } def handleSQLException(SQLException e) { render 'A SQLException Was Handled' } def handleBatchUpdateException(BatchUpdateException e) { redirect controller: 'logging', action: 'batchProblem' } def handleNumberFormatException(NumberFormatException nfe) { [problemDescription: 'A Number Was Invalid'] } }
Namespaced Controllers
Controllers may now be defined in a namespace which allows for multiple controllers to be defined with the same name in different packages.// grails-app/controllers/com/app/reporting/AdminController.groovy package com.app.reportingclass AdminController { static namespace = 'reports' // … }
// grails-app/controllers/com/app/security/AdminController.groovy package com.app.securityclass AdminController { static namespace = 'users' // … }
// grails-app/conf/UrlMappings.groovy class UrlMappings { static mappings = { '/userAdmin' { controller = 'admin' namespace = 'users' } '/reportAdmin' { controller = 'admin' namespace = 'reports' } "/$namespace/$controller/$action?"() } }
<g:link controller="admin" namespace="reports">Click For Report Admin</g:link> <g:link controller="admin" namespace="users">Click For User Admin</g:link>
Command Line
Thecreate-app
command will now by default generate the command line grailsw wrapper for newly created applications. The --skip-wrapper
switch may be used to prevent the wrapper from being generated.grails create-app appname --skip-wrapper
1.4 What's new in Grails 2.2?
Namespace Support
Grails 2.2 includes improved support for managing naming conflicts between artifacts provided by an application and its plugins.Bean names for Service artifacts provided by a plugin are now prefixed with the plugin name. For example, if a Service namedcom.publishing.AuthorService
is provided by
a plugin named PublishingUtilities
and another Service named com.bookutils.AuthorService
is provided by a plugin named BookUtilities
, the bean names for those services
will be publishingUtilitiesAuthorService
and bookUtilitiesAuthorService
respectively. If a plugin provides a Service that does not have a name which conflicts with any
other Service, then a bean alias will automatically be created that does not contain the prefix and the alias will refer to the bean referenced by the prefixed name. Service
artifacts provided directly by the application will have no prefix added to the relevant bean name. See the dependency injection and services docs.Domain classes provided by a plugin will have their default database table name prefixed with the plugin name if the grails.gorm.table.prefix.enabled
config property is
set to true
. For example, if the PublishingUtilities
plugin provides a domain class named Book
, the default table name for that domain class will be
PUBLISHING_UTILITIES_BOOK
if the grails.gorm.table.prefix.enabled
config property is set to true
.URL Mappings may now include a plugin
attribute to indicate that the controller referenced in the mapping is provided by a particular plugin.static mappings = { // requests to /bookAuthors will be handled by the // AuthorController provided by the BookUtilities plugin "/bookAuthors" { controller = 'author' plugin = 'bookUtilities' } // requests to /publishingAuthors will be handled by the // AuthorController provided by the Publishing plugin "/publishingAuthors" { controller = 'author' plugin = 'publishing' } }
<g:link controller="user" plugin="springSecurity">Manage Users</g:link>
class DemoController { def index() { redirect controller: 'user', action: 'list', plugin: 'springSecurity' } }
Forked Tomcat Execution
Grails 2.2 supports forked JVM execution of the Tomcat container in development mode. This has several benefits including:- Reduced memory consumption, since the Grails build system can exit
- Isolation of the build classpath from the runtime classpath
- The ability to deploy other Grails/Spring applications in parallel without conflicting dependencies
SQL Projections In Criteria Queries
Grails 2.2 adds new functionality to criteria queries to provide access to Hibernate's SQL projection API.// Use SQL projections to retrieve the perimeter and area of all of the Box instances… def c = Box.createCriteria()def results = c.list { projections { sqlProjection '(2 * (width + height)) as perimeter, (width * height) as area', ['perimeter', 'area'], [INTEGER, INTEGER] } }
Groovy 2
Grails 2.2 ships with Groovy 2.0, which has a bunch of new features itself.1.5 What's new in Grails 2.1?
Maven Improvements / Multi Module Build Support
Grails' Maven support has been improved in a number of significant ways. Firstly it is now possible to specify plugins within yourpom.xml
file:<dependency> <groupId>org.grails.plugins</groupId> <artifactId>hibernate</artifactId> <version>2.1.0</version> <type>zip</type> <scope>compile</scope> </dependency>
create-multi-project-build
script which features initial support for Maven (Gradle coming in a future release). This script can be run from a parent directory containing Grails applications and plugins and it will generate a Maven multi-module build.Enabling Maven in a project has been made easier with the inclusion of the create-pom
command:grails create-app myapp
cd myapp
grails create-pom com.mycompany
mvn package
grails create-app myapp grails create-plugin plugin-a grails create-plugin plugin-b grails create-multi-project-build com.mycompany:parent:1.0-SNAPSHOT mvn install
Grails Wrapper
The Grails Wrapper allows a Grails application to build without having to install Grails and configure a GRAILS_HOME environment variable. The wrapper includes a small shell script and a couple of small bootstrap jar files that typically would be checked in to source code control along with the rest of the project. The first time the wrapper is executed it will download and configure a Grails installation. This wrapper makes it more simple to setup a development environment, configure CI and manage upgrades to future versions of Grails. When the application is upgraded to the next version of Grails, the wrapper is updated and checked in to the source code control system and the next time developers update their workspace and run the wrapper, they will automatically be using the correct version of Grails.See the Wrapper Documentation for more details.Debug Option
Thegrails
command now supports a -debug
option which will startup the remote debug agent. This behavior used to be provided by the grails-debug
command. grails-debug
is still available but is deprecated and may be removed from a future release.grails -debug run-app
Grails Command Aliases
Thealias
command may be used to define aliases for grails commands.The following command creates an alias named rit
(short for "run integration tests"):grails alias rit test-app integration:
Cache Plugin
Grails 2.1 installs the cache plugin by default. This plugin provides powerful and easy to use cache functionality to applications and plugins. The main plugin provides basic map backed caching support. For more robust caching options one of the implementation plugins should be installed and configured. See the cache-redis docs and the cache-ehcache docs for details.See the main plugin documentation for details on how to configure and use the plugin.New GORM Methods
In Grails 2.1.1 domain classes now have static methods namedfirst
and last
to retrieve the first and last instances from the datastore. See the first and last documentation for details.
1.6 What's new in Grails 2.0?
This section covers the new features that are present in 2.0 and is broken down into sections covering the build system, core APIs, the web tier, persistence enhancements and improvements in testing. Note there are many more small enhancements and improvements, these sections just cover some of the highlights.1.6.1 Development Environment Features
Interactive Mode and Console Enhancements
Grails 2.0 features brand new console output that is more concise and user friendly to consume. An example of the new output when running tests can be seen below:In general Grails makes its best effort to display update information on a single line and only present the information that is crucial. This means that while in previous versions of Grails the war command produced many lines of output, in Grails 2.0 only 1 line of output is produced:In addition simply typing 'grails' at the command line activates the new interactive mode which features TAB completion, command history and keeps the JVM running to ensure commands execute much quicker than otherwiseFor more information on the new features of the console refer to the section of the user guide that covers the console and interactive mode.Reloading Agent
Grails 2.0 reloading mechanism no longer uses class loaders, but instead uses a JVM agent to reload changes to class files. This results in greatly improved reliability when reloading changes and also ensures that the class files stored in disk remain consistent with the class files loaded in memory, which reduces the need to run the clean command.New Test Report and Documentation Templates
There are new templates for displaying test results that are clearer and more user friendly than the previous reports:In addition, the Grails documentation engine has received a facelift with a new template for presenting Grails application and plugin documentation:See the section on the documentation engine for more usage info.Use a TOC for Project Docs
The old documentation engine relied on you putting section numbers into the gdoc filenames. Although convenient, this effectively made it difficult to restructure your user guide by inserting new chapters and sections. In addition, any such restructuring or renaming of section titles resulted in breaking changes to the URLs.You can now use logical names for your gdoc files and define the structure and section titles in a YAML table-of-contents file, as described in the section on the documentation engine. The logical names appear in the URLs, so as long as you don't change those, your URLs will always remain the same no matter how much restructuring or changing of titles you do.Grails 2.0 even provides a migrate-docs command to aid you in migrating existing gdoc user guides.Enhanced Error Reporting and Diagnosis
Error reporting and problem diagnosis has been greatly improved with a new errors view that analyses stack traces and recursively displays problem areas in your code:In addition stack trace filtering has been further enhanced to display only relevant trace information:Line | Method
->> 9 | getValue in Book.groovy
- - - - - - - - - - - - - - - - - - - - - - - - -
| 7 | getBookValue in BookService.groovy
| 886 | runTask . . in ThreadPoolExecutor.java
| 908 | run in ''
^ 662 | run . . . . in Thread.java
H2 Database and Console
Grails 2.0 now uses the H2 database instead of HSQLDB, and enables the H2 database console in development mode (at the URI /dbconsole) so that the in-memory database can be easily queried from the browser:Plugin Usage Tracking
To enhance community awareness of the most popular plugins an opt-in plugin usage tracking system has been included where users can participate in providing feedback to the plugin community on which plugins are most popular.This will help drive the roadmap and increase support of key plugins while reducing the need to support older or less popular plugins thus helping plugin development teams focus their efforts.Dependency Resolution Improvements
There are numerous improvements to dependency resolution handling via Ivy including:- Grails now makes a best effort to cache the previous resolve and avoid resolving again unless you change
BuildConfig.groovy
. - Plugins dependencies now appear in the dependency report generated by
grails dependency-report
- Plugins published with the release plugin now publish their transitive plugin dependencies in the generated POM which are later resolved.
- It is now possible to customize the ivy cache directory via
BuildConfig.groovy
grails.project.dependency.resolution = {
cacheDir "target/ivy-cache"
}
- You can change the ivy cache directory for all projects via
settings.groovy
grails.dependency.cache.dir = "${userHome}/.ivy2/cache"
- It is now possible to completely disable resolution from inherited repositories (repositories defined by other plugins):
grails.project.dependency.resolution = { repositories {
inherits false // Whether to inherit repository definitions from plugins
…
}
…
}
- It is now possible to easily disable checksum validation errors:
grails.project.dependency.resolution = {
checksums false // whether to verify checksums or not
}
1.6.2 Core Features
Binary Plugins
Grails plugins can now be packaged as JAR files and published to standard maven repositories. This even works for GSP and static resources (with resources plugin 1.0.1). See the section on Binary plugins for more information.Groovy 1.8
Grails 2.0 comes with Groovy 1.8 which includes many new features and enhancementsSpring 3.1 Profile Support
Grails' existing environment support has been bridged into the Spring 3.1 profile support. For example when running with a custom Grails environment called "production", a Spring profile of "production" is activated so that you can use Spring's bean configuration APIs to configure beans for a specific profile.1.6.3 Web Features
Controller Actions as Methods
It is now possible to define controller actions as methods instead of using closures as in previous versions of Grails. In fact this is now the preferred way of expressing an action. For example:// action as a method def index() {} // action as a closure def index = {}
Binding Primitive Method Action Arguments
It is now possible to bind form parameters to action arguments where the name of the form element matches the argument name. For example given the following form:<g:form name="myForm" action="save"> <input name="name" /> <input name="age" /> </g:form>
def save(String name, int age) { // remaining }
Static Resource Abstraction
A new static resource abstraction is included that allows declarative handling of JavaScript, CSS and image resources including automatic ordering, compression, caching and gzip handling.Servlet 3.0 Async Features
Grails now supports Servlet 3.0 including the Asynchronous programming model defined by the specification:def index() { def ctx = startAsync() ctx.start { new Book(title:"The Stand").save() render template:"books", model:[books:Book.list()] ctx.complete() } }
Link Generation API
A general purposeLinkGenerator
class is now available that is usable anywhere within a Grails application and not just within the context of a controller. For example if you need to generate links in a service or an asynchronous background job outside the scope of a request:LinkGenerator grailsLinkGeneratordef generateLink() { grailsLinkGenerator.link(controller:"book", action:"list") }
Page Rendering API
Like theLinkGenerator
the new PageRenderer
can be used to render GSP pages outside the scope of a web request, such as in a scheduled job or web service. The PageRenderer
class features a very similar API to the render
method found within controllers:grails.gsp.PageRenderer groovyPageRenderervoid welcomeUser(User user) {
def contents = groovyPageRenderer.render(view:"/emails/welcomeLetter", model:[user: user])
sendEmail {
to user.email
body contents
}
}
PageRenderer
service also allows you to pre-process GSPs into HTML templates:new File("/path/to/welcome.html").withWriter { w -> groovyPageRenderer.renderTo(view:"/page/content", w) }
Filter Exclusions
Filters may now express controller, action and uri exclusions to offer more options for expressing to which requests a particular filter should be applied.filter1(actionExclude: 'log*') { before = { // … } } filter2(controllerExclude: 'auth') { before = { // … } }filter3(uriExclude: '/secure*') { before = { // … } }
Performance Improvements
Performance of GSP page rendering has once again been improved by optimizing the GSP compiler to inline method calls where possible.HTML5 Scaffolding
There is a new HTML5-based scaffolding UI:jQuery by Default
The jQuery plugin is now the default JavaScript library installed into a Grails application. For backwards compatibility a Prototype plugin is available. Refer to the documentation on the Prototype plugin for installation instructions.Easy Date Parsing
A newdate
method has been added to the params
object to allow easy, null-safe parsing of dates:def val = params.date('myDate', 'dd-MM-yyyy')// or a list for formats
def val = params.date('myDate', ['yyyy-MM-dd', 'yyyyMMdd', 'yyMMdd'])// or the format read from messages.properties via the key 'date.myDate.format'
def val = params.date('myDate')
Customizable URL Formats
The default URL Mapping mechanism supports camel case names in the URLs. The default URL for accessing an action namedaddNumbers
in a controller named MathHelperController
would be something like /mathHelper/addNumbers
. Grails allows for the customization of this pattern and provides an implementation which replaces the camel case convention with a hyphenated convention that would support URLs like /math-helper/add-numbers
. To enable hyphenated URLs assign a value of "hyphenated" to the grails.web.url.converter
property in grails-app/conf/Config.groovy
.// grails-app/conf/Config.groovygrails.web.url.converter = 'hyphenated'
grails.web.UrlConverter.BEAN_NAME
. If Grails finds a bean in the context with that name, it will be used as the default converter and there is no need to assign a value to the grails.web.url.converter
config property.// src/groovy/com/myapplication/MyUrlConverterImpl.groovypackage com.myapplicationclass MyUrlConverterImpl implements grails.web.UrlConverter { String toUrlElement(String propertyOrClassName) { // return some representation of a property or class name that should be used in URLs… } }
// grails-app/conf/spring/resources.groovybeans = {
"${grails.web.UrlConverter.BEAN_NAME}"(com.myapplication.MyUrlConverterImpl)
}
Web Flow input and output
It is now possible to provide input arguments when calling a subflow. Flows can also return output values that can be used in a calling flow.1.6.4 Persistence Features
The GORM API
The GORM API has been formalized into a set of classes (GormStaticApi
, GormInstanceApi
and GormValidationApi
) that get statically wired into every domain class at the byte code level. The result is better code completion for IDEs, better integration with Java and the potential for more GORM implementations for other types of data stores.Detached Criteria and Where Queries
Grails 2.0 features support for DetachedCriteria which are criteria queries that are not associated with any session or connection and thus can be more easily reused and composed:def criteria = new DetachedCriteria(Person).build { eq 'lastName', 'Simpson' } def results = criteria.list(max:4, sort:"firstName")
where
method and DSL has been introduced to greatly reduce the complexity of criteria queries:def query = Person.where { (lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9) } def results = query.list(sort:"firstName")
New findOrCreate and findOrSave Methods
Domain classes have support for the findOrCreateWhere, findOrSaveWhere, findOrCreateBy and findOrSaveBy query methods which behave just like findWhere and findBy methods except that they should never return null. If a matching instance cannot be found in the database then a new instance is created, populated with values represented in the query parameters and returned. In the case of findOrSaveWhere and findOrSaveBy, the instance is saved before being returned.def book = Book.findOrCreateWhere(author: 'Douglas Adams', title: "The Hitchhiker's Guide To The Galaxy")
def book = Book.findOrSaveWhere(author: 'Daniel Suarez', title: 'Daemon')
def book = Book.findOrCreateByAuthorAndTitle('Daniel Suarez', 'Daemon')
def book = Book.findOrSaveByAuthorAndTitle('Daniel Suarez', 'Daemon')
Abstract Inheritance
GORM now supports abstract inheritance trees which means you can define queries and associations linking to abstract classes:abstract class Media { String title … } class Book extends Media { } class Album extends Media {} class Account { static hasMany = [purchasedMedia:Media] }..def allMedia = Media.list()
Multiple Data Sources Support
It is now possible to define multiple datasources inDataSource.groovy
and declare one or more datasources a particular domain uses by default:class ZipCode { String code static mapping = { datasource 'ZIP_CODES' } }
def zipCode = ZipCode.auditing.get(42)
Database Migrations
A new database migration plugin has been designed and built for Grails 2.0 allowing you to apply migrations to your database, rollback changes and diff your domain model with the current state of the database.Database Reverse Engineering
A new database reverse engineering plugin has been designed and built for Grails 2.0 that allows you to generate a domain model from an existing database schema.Hibernate 3.6
Grails 2.0 is now built on Hibernate 3.6Bag Collections
You can now use Hibernate Bags for mapped collections to avoid the memory and performance issues of loading large collections to enforceSet
uniqueness or List
order.For more information see the section on Sets, Lists and Maps in the user guide.
1.6.5 Testing Features
New Unit Testing Console Output
Test output from the test-app command has been improved:New Unit Testing API
There is a new unit testing API based on mixins that supports JUnit 3, 4 and Spock style tests (with Spock 0.6 and above). Example:import grails.test.mixin.TestFor@TestFor(SimpleController) class SimpleControllerTests { void testIndex() { controller.home() assert view == "/simple/homePage" assert model.title == "Hello World" } }