Upgrade to Grails 2
There are always some breaking changes with any major version change of a framework. This document will navigate you through the changes you may need to make in order to get an existing 1.3.x application working with Grails 2.0. Some changes will apply to all projects. Others only affect a few projects. The complexity of upgrading an existing application also depends on what plugins are installed, so any plugins that are known to work with Grails 2 are included at the end.
First steps
The very first thing you should do is delete the project's 'target' directory, and if your project working directory isn't specific to a version of Grails, delete that too (it's under a
<grailsVersion>
path by default). Then, with Grails 2 execute:
grails upgrade --force
This will ensure you have the latest versions of the JSP taglib definition files and, most importantly, the latest applicationContext.xml.
The
web.xml
file has also changed, but this only affects projects that have a template
web.xml
in the 'src/templates' directory. If that's the case, work out what changes were made to it, re-run
grails install-templates
, and then apply the changes to the new web descriptor.
If you want to use the new interactive console extensively (and why wouldn't you?) then be prepared to up the heap and permgen space for your application:
export GRAILS_OPTS="-Xmx700m -XX:MaxPermSize=384m"
for example. To fine tune these numbers, you can run something like the JDK jconsole command to see how much memory your application is using when running the interactive console.
Persistence
The persistence layer has seen a lot of change over the last year or two, not least because GORM is now available for multiple data stores, not just SQL via Hibernate. Still, most domain models won't have to change much if at all.
New in-memory database
Many projects probably use the default HSQLDB database for development. Grails 2 has switched to H2 as the default instead, and so if you try to run your application you'll see this warning:
Database driver org.hsqldb.jdbcDriver for HSQLDB not found. Since Grails 2.0 H2 is now the default database. You need to either add the 'org.h2.Driver' class as your database driver and change the connect URL format (for example 'jdbc:h2:mem:devDb') in DataSource.groovy or add HSQLDB as a dependency of your application.
As the message explains, you can fix this in one of two ways. The quickest is to add this line to
BuildConfig.groovy
:
…
grails.project.dependency.resolution = {
…
dependencies {
runtime "hsqldb:hsqldb:1.8.0.10"
…
}
}
The above version of the HSQLDB driver is included with the Grails distribution, so the project doesn't even need to pull it from the internet. If you'd prefer to upgrade to H2, then modify the HSQLDB driver class name and connection URLs in
DataSource.groovy
:
dataSource {
driverClassName = "org.h2.Driver" // In memory database
url = "jdbc:h2:mem:devDb;MVCC=TRUE" // File-based database
//url = "jdbc:h2:prodDb;MVCC=TRUE"
…
}
If you go for this approach, there's no need to add the H2 driver JAR as an explicit dependency as it is included vi the
inherits("global")
directive.
Abstract domain classes
Consider this model:
where the
Person
domain class is declared as abstract. Before Grails 2, this model would result in two separate tables: one for
Employee
and one for
Manager
. This doesn't really make a lot of sense, because the two domain classes share common properties from
Person
, so Grails 2 will now create a single
Person
table that
Employee
and
Manager
use.
If you have existing data based on the old model, this change will break your application. You have a couple of options:
- migrate your data to the new model with a shared table; or
- move the abstract domain class, e.g.
Person
, to the 'src/groovy' directory.
Of these, the latter is much simpler.
Problematic property names
Some domain class property names will cause issues for various reasons:
environment
load
get
list
find
findAll
where
The problem with
environment
is fixed in 2.0.1. The problem with domain class properties that match the names of static GORM methods will be fixed in a future version.
The web layer
Grails 2 introduces quite a few new features to controllers and other parts of the web layer, but few breaking changes. One of the most significant changes is that actions can now be declared as public methods and we recommend you migrate your existing code to this approach if you can. However, this means that if you have public methods in controllers already, they will suddenly be exposed as actions - probably not what you want. Be sure to change those methods to either
private
or
protected
scope.
Scaffolding and error views
Grails 2 introduces some nice HTML5 scaffolding and an updated error view. Both of these work perfectly out of the box for a new project, but not when you upgrade an existing project. The simplest thing to do is create a new Grails 2 project and then copy the relevant files to your existing one:
cp <path to new project>/web-app/css/main.css <path to existing project>/web-app/
cp <path to new project>/grails-app/views/error.gsp <path to existing project>/grails-app/views/
Note If you have customised either file, then the upgrade process is trickier as you have to re-apply your changes to the new files. In fact, it's probably better to rename 'main.css' to something else (such as 'app.css') and use that for your own views. In other words, leave 'main.css' for the scaffolding.
Redirects
In order to allow code to modify the response after issuing a redirect, Grails had to bypass the standard Servlet
sendRedirect()
method. As a side-effect, the
redirect()
is now dependent on the
grails.serverURL
configuration setting. If this doesn't match the URL of your application, redirects will stop working.
The simplest way to avoid this problem is to remove the setting unless you need it. If you need it (usually for production deployments) then the value should already match the URL of your application. This mostly impacts development where old projects often have a legacy value that doesn't work.
Another side-effect is that you can no longer use the
response.isCommitted()
method to determine whether a redirect has taken place. Instead, there is a new
request.isRedirected()
method that you should use -
note that the new method is on
request
rather than
response
!
Content negotiation
Prior to version 2, Grails would factor in the request content type when performing content negotiation. However, the request content type is a bad basis for determining the response content type - that's what the
Accept
header is for! So, Grails 2 ignores it. This may break your usage of
withFormat()
if you depend on selection by request content type.
If you want to do something based on the request content type, then use the
withFormat()
method on the
request
object instead:
request.withFormat {
xml {
// Do something for XML request content
}
json {
// Do something for JSON request content
}
}
AJAX tags + Prototype.js
Grails has packaged Prototype.js by default for a long time. That finally changed with Grails 2 and in fact
no Javascript library is included directly any more. Instead, a new Grails 2 project will automatically have the jQuery
plugin as a dependency.
What this means for existing projects is that if you use the adaptive AJAX tags with Prototype.js, you will need to add the new
Prototype plugin as a dependency.
Installing Resources plugin
The
Resources plugin is a great way of managing static web resources such as CSS and Javascript files. Many pre-2 projects are probably already using it. If that's the case, be warned that Grails 2 is Resources-aware and modifies the behaviour of the
<g:resource>
and
<g:javascript>
tags if the plugin is installed.
All this means in reality is that you should use the
<r:layoutResources>
tags for all your responses, although AJAX responses are a bit of a special case.
We don't really recommend that you include markup and inline Javascript in AJAX responses. However, if you do, then switch to a raw
<script>
tag rather than
<g:javascript>
.
One final thing on Resources: it automatically adds a
/static
URL to your application under which all static resources are served, so if you have URL-based access control rules, be sure to update them as appropriate.
Testing
Grails 2 comes with a much improved unit testing framework, but it's completely incompatible with the old one. The old one is still there, so your existing tests should still run. But if you want to update your test cases, then you will have to migrate them wholesale. In other words, for each test case that you want to migrate, you will probably have to rewrite it using the new annotations.
Plugins
The following plugin versions are known to work with Grails 2:
Plugin | Version | Notes |
---|
resources | 1.1.6 | |
spring-security-core | 1.2.7.1 | |