Upgrading Grails Applications

Learn how to upgrade a Grails application

Version: 1.0.0.BUILD-SNAPSHOT

Table of Contents

1 Comparing Versions

Grails Profiles encapsulate the project commands, templates and plugins that are designed to work for a given profile. When you don’t specify a profile, the web profile is used.

The easiest way to see changes made to fresh new app for a given profile between Grails versions is to use the next Github Repositories to generate a diff.

Application Profile

web

rest-api

angularjs

angular

react

webpack

web-jboss7-versions

Plugin Profile

plugin

rest-api-plugin

web-plugin

2 Upgrading

2.1 Upgrading to Grails 4

Grails 4 is still under development.

Bump up Grails Version

You will need to upgrade your Grails version defined in gradle.properties.

Grails 3 app’s gradle.properties

gradle.properties
...
grailsVersion=3.3.8
...

Grails 4 app’s gradle.properties

gradle.properties
...
grailsVersion=4.0.0.RC2
...

Bump up GORM Version

If you were using GORM, you will need to update the version defined in gradle.properties.

Grails 3 app’s gradle.properties

gradle.properties
...
gormVersion=6.1.10.RELEASE
...

Grails 4 app’s gradle.properties

gradle.properties
...
gormVersion=7.0.0.BUILD-SNAPSHOT
...

Spring 5 and Spring Boot 2.1

Grails 4.0 is built on Spring 5 and Spring Boot 2.1. See the migration guide and release notes if you are using Spring specific features.

Hibernate 5.4 and GORM 7.x

Grails 4.x supports a minimum version of Hibernate 5.4 and GORM 7.x. Several changes have been made to GORM to support the newer version of Hibernate and simplify GORM itself.

The details of these changes are covered in the GORM upgrade documentation.

Spring Boot 2.1 Actuator

Please check the Spring Boot Actuator documentation since it has changed substantially from Spring Boot 1.5 the version Grails 3.x used.

If you had configuration such as:

grails-app/conf/application.yml - Grails 3.3.x
endpoints:
    enabled: false
    jmx:
        enabled: true
        unique-names: true

replace it with:

grails-app/conf/application.yml - Grails 4.x
spring:
    jmx:
        unique-names: true
management:
    endpoints:
        enabled-by-default: false

Spring Boot Developer Tools

Grails 4 applications include Spring Boot Developer Tools dependencies in the build.gradle build script. If you are migrating a Grails 3.x app, please include the next set of dependencies:

build.gradle
.
..
...
configurations {
    developmentOnly
    runtimeClasspath {
        extendsFrom developmentOnly
    }
}

dependencies {
        developmentOnly("org.springframework.boot:spring-boot-devtools")
        ...
        ..
}
...
..
.

You can use Spring Developer Tools in combination with a browser extension such as the Chrome LiveReload extension to get automatic browser refresh when you change anything in your Grails application.

Spring Boot Gradle Plugin Changes

Grails 4 is built on top of Spring Boot 2.1. Grails 3 apps were built on top of Spring Boot 1.x.

Your Grails 3 app’s build.gradle may have such configuration:

buid.gradle
bootRun {
    addResources = true
    ...
}

Grails 4 apps are built on top of Spring Boot 2.1. Starting from Spring Boot 2.0, the addResources property no longer exists. Instead, you need to set the sourceResources property to the source set that you want to use. Typically that’s sourceSets.main. This is described in the Spring Boot Gradle plugin’s documentation.

Your Grails 4 app’s build.gradle can be configured:

buid.gradle
bootRun {
        sourceResources sourceSets.main
    ...
}

Building executable jars for Grails Plugins

The bootRepackage task has been replaced with bootJar and bootWar tasks for building executable jars and wars respectively. Both tasks extend their equivalent standard Gradle jar or war task, giving you access to all of the usual configuration options and behaviour.

If you had configuration such as:

buid.gradle | Grails 3
// enable if you wish to package this plugin as a standalone application
bootRepackage.enabled = false

replace it with:

buid.gradle | Grails 4
// enable if you wish to package this plugin as a standalone application
bootJar.enabled = false

Upgrading to Gradle 5

Grails 3 apps by default used Gradle 3.5. Grails 4 apps use Gradle 5.

To upgrade to Gradle 5 execute:

./gradlew wrapper --gradle-version 5.0

If you customized your app’s build, other migrations may be necessary. Please check Gradle Upgrading your build documentation.

Upgrade Hibernate

If you were using GORM for Hibernate implementation in your Grails 3 app, you will need to upgrade to Hibernate 5.3.

A Grails 3 build.gradle such as:

build.gradle
dependencies {
...
  compile "org.grails.plugins:hibernate5"
  compile "org.hibernate:hibernate-core:5.1.5.Final"
}

will be in Grails 4:

build.gradle
dependencies {
...
  compile "org.grails.plugins:hibernate5"
  compile "org.hibernate:hibernate-core:5.4.0.Final"
}

Migrating to Geb 2.3

Geb 1.1.x (a JDK 1.7 compatible version) was the version shipped by default with Grails 3. Grails 4 is no longer compatible with Java 1.7. You should migrate to Geb 2.3.

In Grails 3, if your build.gradle looks like:

build.gradle
dependencies {
 testCompile "org.grails.plugins:geb:1.1.2"
 testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
 testRuntime "net.sourceforge.htmlunit:htmlunit:2.18"
}

In Grails 4, you should replace it with:

build.gradle
buildscript {
    repositories {
       ...
    }
    dependencies {
        ...
        classpath "gradle.plugin.com.github.erdi.webdriver-binaries:webdriver-binaries-gradle-plugin:$webdriverBinariesVersion" (1)
    }
}
...
..

repositories {
  ...
}

apply plugin:"idea"
...
...
apply plugin:"com.energizedwork.webdriver-binaries" (1)


dependencies {
...
    testCompile "org.grails.plugins:geb" (4)
    testRuntime "org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion"  (5)
    testRuntime "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion" (5)
    testRuntime "org.seleniumhq.selenium:selenium-safari-driver:$seleniumSafariDriverVersion" (5)

    testCompile "org.seleniumhq.selenium:selenium-remote-driver:$seleniumVersion" (5)
    testCompile "org.seleniumhq.selenium:selenium-api:$seleniumVersion" (5)
    testCompile "org.seleniumhq.selenium:selenium-support:$seleniumVersion" (5)
}

webdriverBinaries {
    chromedriver "$chromeDriverVersion" (2)
    geckodriver "$geckodriverVersion" (3)
}

tasks.withType(Test) {
    systemProperty "geb.env", System.getProperty('geb.env')
    systemProperty "geb.build.reportsDir", reporting.file("geb/integrationTest")
    systemProperty "webdriver.chrome.driver", System.getProperty('webdriver.chrome.driver')
    systemProperty "webdriver.gecko.driver", System.getProperty('webdriver.gecko.driver')
}
gradle.properties
gebVersion=2.3.1
seleniumVersion=3.14.0
webdriverBinariesVersion=2.1
chromeDriverVersion=2.46.0 (2)
geckodriverVersion=0.24.0 (3)
seleniumSafariDriverVersion=3.14.0
1 Includes Webdriver binaries Gradle plugin.
2 Set the appropriate Webdriver for Chrome version.
3 Set the appropriate Webdriver for Firefox version.
4 Includes the Grails Geb Plugin dependency which has a transitive dependency to geb-spock. This is the dependency necessary to work with Geb and Spock.
5 Selenium and different driver dependencies.

Create also a Geb Configuration file at src/integration-test/resources/GebConfig.groovy.

src/integration-test/resources/GebConfig.groovy
import org.openqa.selenium.chrome.ChromeDriver
import org.openqa.selenium.chrome.ChromeOptions
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxOptions
import org.openqa.selenium.safari.SafariDriver

environments {

    // You need to configure in Safari -> Develop -> Allowed Remote Automation
    safari {
        driver = { new SafariDriver() }
    }

    // run via “./gradlew -Dgeb.env=chrome iT”
    chrome {
        driver = { new ChromeDriver() }
    }

    // run via “./gradlew -Dgeb.env=chromeHeadless iT”
    chromeHeadless {
        driver = {
            ChromeOptions o = new ChromeOptions()
            o.addArguments('headless')
            new ChromeDriver(o)
        }
    }

    // run via “./gradlew -Dgeb.env=firefoxHeadless iT”
    firefoxHeadless {
        driver = {
            FirefoxOptions o = new FirefoxOptions()
            o.addArguments('-headless')
            new FirefoxDriver(o)
        }
    }

    // run via “./gradlew -Dgeb.env=firefox iT”
    firefox {
        driver = { new FirefoxDriver() }
    }
}

Deprecated classes

The next classes, which were deprecated, have been removed in Grails 4. Please, check the next list to find a suitable replacement:

Removed Class

Alternative

org.grails.datastore.gorm.validation.constraints.UniqueConstraint

org.grails.datastore.gorm.validation.constraints.builtin.UniqueConstraint

grails.util.BuildScope

grails.transaction.GrailsTransactionTemplate

grails.gorm.transactions.GrailsTransactionTemplate

org.grails.transaction.transform.RollbackTransform

org.grails.datastore.gorm.transactions.transform.RollbackTransform

grails.transaction.NotTransactional

grails.gorm.transactions.NotTransactional

grails.transaction.Rollback

grails.gorm.transactions.Rollback

grails.transaction.Transactional

grails.gorm.transactions.Transactional

org.grails.config.FlatConfig

org.grails.core.metaclass.MetaClassEnhancer

Use traits instead.

org.grails.core.util.ClassPropertyFetcher

org.grails.datastore.mapping.reflect.ClassPropertyFetcher

org.grails.transaction.transform.TransactionalTransform

org.grails.datastore.gorm.transactions.transform.TransactionalTransform

grails.core.ComponentCapableDomainClass

grails.core.GrailsDomainClassProperty

Use the org.grails.datastore.mapping.model.MappingContext API instead

org.grails.core.DefaultGrailsDomainClassProperty

org.grails.core.MetaGrailsDomainClassProperty

org.grails.core.support.GrailsDomainConfigurationUtil

Use the org.grails.datastore.mapping.model.MappingContext and org.grails.datastore.mapping.model.MappingFactory APIs instead

org.grails.plugins.domain.DomainClassPluginSupport

org.grails.plugins.domain.support.GormApiSupport

org.grails.plugins.domain.support.GrailsDomainClassCleaner

Handled by org.grails.datastore.mapping.model.MappingContext now

grails.validation.AbstractConstraint

Use org.grails.datastore.gorm.validation.constraints.AbstractConstraint instead

grails.validation.AbstractVetoingConstraint

 org.grails.datastore.gorm.validation.constraints.AbstractVetoingConstraint

grails.validation.CascadingValidator

grails.gorm.validation.CascadingValidator

grails.validation.ConstrainedProperty

grails.gorm.validation.ConstrainedProperty

grails.validation.Constraint

grails.gorm.validation.Constraint

grails.validation.ConstraintFactory

org.grails.datastore.gorm.validation.constraints.factory.ConstraintFactory

grails.validation.VetoingConstraint

grails.gorm.validation.VetoingConstraint

grails.validation.ConstraintException

org.grails.validation.BlankConstraint

org.grails.datastore.gorm.validation.constraints.BlankConstraint

org.grails.validation.ConstrainedPropertyBuilder

org.grails.datastore.gorm.validation.constraints.builder.ConstrainedPropertyBuilder

org.grails.validation.ConstraintDelegate

org.grails.validation.ConstraintsEvaluatorFactoryBean

org.grails.datastore.gorm.validation.constraints.eval.ConstraintsEvaluator

org.grails.validation.CreditCardConstraint

org.grails.datastore.gorm.validation.constraints.CreditCardConstraint

org.grails.validation.DefaultConstraintEvaluator

org.grails.datastore.gorm.validation.constraints.eval.DefaultConstraintEvaluator

org.grails.validation.DomainClassPropertyComparator

org.grails.validation.EmailConstraint

org.grails.datastore.gorm.validation.constraints.EmailConstraint

org.grails.validation.GrailsDomainClassValidator

grails.gorm.validation.PersistentEntityValidator

org.grails.validation.InListConstraint

org.grails.datastore.gorm.validation.constraints.InListConstraint

org.grails.validation.MatchesConstraint

org.grails.datastore.gorm.validation.constraints.MatchesConstraint

org.grails.validation.MaxConstraint

org.grails.datastore.gorm.validation.constraints.MaxConstraint

org.grails.validation.MaxSizeConstraint

org.grails.datastore.gorm.validation.constraints.MaxSizeConstraint

org.grails.validation.MinConstraint

org.grails.datastore.gorm.validation.constraints.MinConstraint

org.grails.validation.MinSizeConstraint

org.grails.datastore.gorm.validation.constraints.MinSizeConstraint

org.grails.validation.NotEqualConstraint

org.grails.datastore.gorm.validation.constraints.NotEqualConstraint

org.grails.validation.NullableConstraint

org.grails.datastore.gorm.validation.constraints.NullableConstraint

org.grails.validation.RangeConstraint

org.grails.datastore.gorm.validation.constraints.RangeConstraint

org.grails.validation.ScaleConstraint

org.grails.datastore.gorm.validation.constraints.ScaleConstraint

org.grails.validation.SizeConstraint

org.grails.datastore.gorm.validation.constraints.SizeConstraint

org.grails.validation.UrlConstraint

org.grails.datastore.gorm.validation.constraints.UrlConstraint

org.grails.validation.ValidatorConstraint

org.grails.datastore.gorm.validation.constraints.ValidatorConstraint

org.grails.validation.routines.DomainValidator

Replaced by newer version of commons-validation

org.grails.validation.routines.InetAddressValidator

Replaced by newer version of commons-validation

org.grails.validation.routines.RegexValidator

Replaced by newer version of commons-validation

org.grails.validation.routines.ResultPair

Replaced by newer version of commons-validation

org.grails.validation.routines.UrlValidator

Replaced by newer version of commons-validation

grails.web.JSONBuilder

groovy.json.StreamingJsonBuilder

Grails-Java8

For those who have added a dependency on the grails-java8 plugin, all you should need to do is simply remove the dependency. All of the classes in the plugin have been moved out to their respective projects.

If the configuration option

2.2 Upgrading to Grails 3.3

Grails 3.3 includes several changes to dependencies and Event publishing that may require changes to your application if you are upgrading from Grails 3.2.x.

For information on upgrading from versions of Grails prior to Grails 3.2.x, see the Grails 3.2.x documentation on upgrading

GORM 6.1 Upgrade

GORM 6.1 includes changes that may require you to change your application.

GORM Async Now Optional

Notably grails-datastore-gorm-async is now optional and if you use the task method of GORM you will need to manually implement the AsyncEntity trait.

Domain Autowiring Disabled

Domain class autowiring is disabled by default due to its impact on performance. You can re-enable autowiring for all domains using the Default Mapping setting:

grails-app/conf/application.groovy
grails.gorm.default.mapping = {
        autowire true
}

You can turn it on only for one domain class:

grails-app/domain/demo/Book.groovy
class Book {
    BookService bookService

    String name

    static mapping {
       autowire true
    }
    ...
    ..
    .
}

Flush Mode now COMMIT by Default

The default flush mode has been change to COMMIT due to the impact the previous flush mode AUTO has on read performance. You can switch back to AUTO use the hibernate.flush.mode setting in application.yml

TransactionManager Chaining for Multiple Data Sources Disabled by Default

In previous versions of Grails for multiple data sources a best effort transaction chain was used to attempt to manage a transaction across all configured data sources.

As of Grails 3.3 this is disabled as it caused confusion since it isn’t a true XA implementation and also impacts performance as for every transaction you have a transaction for each data source bound regardless if that is the actual requirement.

If your application depends on this feature you can re-enable it with the following configuration:

grails:
  transaction:
    chainedTransactionManager:
      enabled: true
      blacklistPattern: '.*'

Tomcat JDBC

GORM 6.1 and above now supports multiple connection pool options, so the tomcat-jdbc dependency is now optional. If you are upgrading you may need to add it (or another pool implementation) to your build.gradle:

build.gradle
runtime 'org.apache.tomcat:tomcat-jdbc'

@TestMixin, @TestFor etc. Deprecated

Since Grails 3.3, the Grails Testing Support Framework is used for all unit tests. The new testing framework is much simpler and provides a set of traits that improve readability, debugging and code completion. An example hello world test can be seen below:

import spock.lang.Specification
import grails.testing.web.controllers.ControllerUnitTest

class HelloControllerTests extends Specification implements ControllerUnitTest<HelloController> {

    void "Test message action"() {
        when:"The message action is invoked"
        controller.message()

        then:"Hello is returned"
        response.text == 'Hello'
    }
}

For more information on writing tests with Grails Testing Support see the dedicated documentation.

To simplify upgrades you can can still use the previous AST transformation based framework by adding the following dependency to your Grails application:

build.gradle
testCompile "org.grails:grails-test-mixins:3.3.0"

Default Logger Name

In previous versions of Grails, if you did not specify a logger in the controller, service, etc, a log variable was injected for you. The naming convention of that logger was grails.app.${artefactType}.package.class. For example:

grails.app.controllers.foo.bar.MyController

To make the logger names more intuitive as well as to increase consistency between custom code, plugin dependencies, and third party libraries, the grails.app.${artefactType} convention was removed. The same class as above will now be referenced the same way as any standard class. The way the log variable gets injected was also changed to defer to the Slf4j transformation. That means it is no longer necessary to check if (log.isDebugEnabled()).

The downside of this change is that it isn’t immediately simple to set up the same logging configuration for all controllers, for example. We think this can be solved with a package naming strategy that represents what your requirements are.

Dependency Alterations

In an effort to trim the size of the produced WAR file by Grails several dependencies are no longer resolved transtively including:

  • commons-lang

  • gson

  • aspectjweaver

  • aspectjrt

  • ehcache

If you are upgrading and have referenced any of these dependencies in your application you may need to alter your build to reference them.

Spring Boot 1.5.x

Spring Boot 1.5.x removes a number of deprecated classes, notably all of the classes within the org.springframework.boot.context.embedded package.

If your application is referencing any of the classes within this package you will need to alter your imports to use org.springframework.boot.web.servlet instead.

Reactor 2.x Deprecated and Removed

Since Reactor 2.x is no longer being maintained and a new EventBus abstraction has been implemented, Reactor 2.x and all its dependencies have been removed.

A compatibility layer has been provided to allow classes compiled with the previous version that uses Reactor to run, however all plugins and application code should be re-compiled and direct references to Reactor 2.x should be removed.

Externalized Plugins

Several plugins and libraries have been separated from Grails core into standalone projects. The following table summarizes the previous artefact id, the new artefact id and the location of the new sources:

Table 1. Externalized Plugins
Previous Artefact ID New Artefact ID Sources

org.grails:grails-plugin-gsp

org.grails.plugins:gsp

https://github.com/grails/grails-gsp

org.grails:grails-plugin-converters

org.grails.plugins:converters

https://github.com/grails-plugins/grails-plugin-converters

org.grails:grails-plugin-async

org.grails.plugins:async

https://github.com/grails/grails-async

org.grails:grails-plugin-events

org.grails.plugins:events

https://github.com/grails/grails-async

org.grails:grails-plugin-testing

org.grails:grails-test-mixins

https://github.com/grails-plugins/grails-test-mixin-plugin

New Cache Plugin

The Cache plugin has been re-written to no longer use Spring proxies but AST transformations instead.

This improves startup and runtime performance, however one caveat is controller action response caching is no longer supported.

Grails Domain Class API Deprecated

The legacy classes that represent domain classes and their properties have been deprecated in favor of the mapping context API.

The reason for this is to avoid duplicate parsing of the same class data between GORM and Grails and reduce overall startup time.

The internal implementation of the methods in those classes now delegates to the mapping context. Due to that change, information about your domain classes is not available until the application context is available.

In previous versions of Grails it was possible to access GrailsDomainClass instances and inspect the GrailsDomainClassProperty properties inside of the doWithSpring method in a plugin, for example.

If you have code that follows that example, an error will be thrown that looks like "The method …​ cannot be accessed before GORM has initialized". The solution is to move any logic that executes before the context is available to somewhere else that executes after the context is available.

All code that uses the GrailsDomainClass or GrailsDomainClassProperty classes should be re-written to use the mapping context api.

To get started, inject the grailsDomainClassMappingContext bean. See the api documentation for more information on the MappingContext, PersistentEntity (GrailsDomainClass), and PersistentProperty (GrailsDomainClassProperty).

The following table summarizes the deprecations:

Table 2. Deprecated Grails Domain Class API
Deprecated Class or Interface Replacement

GrailsDomainClass

PersistentEntity

GrailsDomainClassProperty

PersistentProperty

The GrailsDomainClassProperty interface had many more methods to evaluate the type of the property such as isOneToOne, isOneToMany etc. and while PersistentProperty does not provide direct equivalents you can use instanceof as a replacement using one of the subclasses found in the org.grails.datastore.mapping.model.types package.

The following table summarizes this:

Table 3. Deprecated GrailsDomainClassProperty method replacements
Deprecated Class or Interface Replacement

isAssociation()

property instanceof Association

isOneToOne()

property instanceof OneToOne

isManyToOne()

property instanceof ManyToOne

isEmbedded()

property instanceof Embedded

isManyToMany()

property instanceof ManyToMany

isBasicCollectionType()

property instanceof Basic

Grails Validator and ConstrainedProperty API Deprecated

Grails' previous validation API (part of the grails.validation package) has been externalized into a separate project not part of the grails-datastore-gorm-validation dependency.

This means that some interfaces previously part of Grails core are deprecated and the replacment in the external project should be used, including:

Table 4. Deprecated Grails Validator Classes
Deprecated Class or Interface Replacement

GrailsDomainClassValidator

PersistentEntityValidator

CascadingValidator

CascadingValidator

ConstrainedProperty

ConstrainedProperty

Constraint

Constraint

AbstractConstraint

AbstractConstraint

Generally all classes within the org.grails.validation package are now deprecated.

To register a custom constraint you should now use the ConstraintRegistry interface instead.

The default ValidatorRegistry implements the ConstraintRegistry interface and can be autowired into any controller or service by declaring the following property:

ValidatorRegistry gormValidatorRegistry
...
gormValidatorRegistry.addConstraint(MyConstraint)

Grails' Transactional AST Transforms Deprecated

The transaction management AST transforms that shipped as part of Grails have been ported to GORM and improved to make it possible to use them outside of Grails.

With this in mind Grails' versions of @Transactional and @Rollback found within the grails.transaction package have been deprecated in favour of GORMs versions. You should change your imports to use the GORM version instead of the Grails version.

The following table summarizes the deprecated classes and their replacements:

Table 5. Deprecated Grails Transaction Transforms
Deprecated Class or Interface Replacement

grails.transaction.Transactional

grails.gorm.transactions.Transactional

grails.transaction.Rollback

grails.gorm.transactions.Rollback

grails.transaction.NotTransactional

grails.gorm.transactions.NotTransactional

Spring Proxies for Services No Longer Supported

Earlier versions of Grails supported the use of Spring proxies for transaction management, but this support was disabled by default in Grails 3.2.x and developers encouraged to use the @Transactional AST transforms instead.

In Grails 3.3 the support for Spring proxies has been dropped completely and you must use Grails' AST transforms.

If you wish to continue to use Spring proxies for transaction management you will have to configure them manually use the appropriate Spring configuration.

Datasource Plugin Refactor

In previous versions of Grails and GORM the multiple data sources support relied on Grails' data sources plugin. The logic for configuring multiple data sources has moved to GORM and as a result of major changes to the dataSources plugin, beans for the lazy and unproxied representation of a dataSource are no longer available.

The beans include:

  • dataSourceUnproxied

  • dataSourceLazy

If you are referencing these beans you will need to remove these references and unwrap the single dataSource proxy manually.

Task Groups

Several tasks have had their groups changed to better reflect their purpose. If you’re having trouble finding a task, look through the different groups.

Legacy JSON Builder Option Removed

In a previous version of Grails, the JSON builder used by default for rendering JSON inline was changed. The previous behavior of using converters to build the JSON was able to be re-enabled by setting grails.json.legacy.builder to true. In Grails 3.3 that setting has been removed and it is no longer possible to use the legacy converter API to render JSON inline via the render method.

2.3 Upgrading from Grails 3.2

If you are upgrading from Grails 3.2 there are a few items to take into consideration.

Legacy Converters API Separated From Core

Since the addition of json views, the previous way to convert objects to JSON has been considered legacy. In Grails 3.3 the code to support the legacy converters has been moved out of core and into a separate plugin. That means that by default, code that uses grails.converters.JSON or grails.converters.XML will no longer work by default.

Common usages of this feature are render(book as JSON).

If your codebase uses the legacy converters it is encouraged to convert the functionality to use JSON views, however you can add a dependency in your code to allow current usages of the converters to work again.

build.gradle
    compile "org.grails.plugins:grails-plugin-converters"
The support to build JSON directly from the render method no longer supports the old API and any code that used it will need to be converted to use the groovy.json.StreamingJsonBuilder syntax.

The support for rendering with the previous API was disabled by default in 3.1 and was able be re-enabled with the grails.json.legacy.builder: true setting. That setting has been removed in Grails 3.3.

2.4 Upgrading from Grails 3.1

If you are upgrading from Grails 3.1 there are a few items to take into consideration.

Use WebPromises instead of Promises in Controllers

In versions of Grails prior to 3.2, grails.async.Promises used to allow the use of render and other controller methods, however this was unsafe as the request thread may have finished prior to the task executing leading to unexpected errors.

You should now instead use grails.async.web.WebPromises within a controller.

Deprecated Classes and Methods Removed

Classes and methods deprecated in Grails 3.0.x have been removed in Grails 3.2. This includes all classes in the org.codehaus.groovy.grails package. If your application or plugin uses deprecated classes they should be updated to use non-deprecated replacements.

Slf4j Now Default

The log property injected at compile time into all classes is now an Slf4j Logger instance and not an instance of the Commons Logging Log class.

This should be a simple upgrade for most use cases, however this change does have some implications, for example it is no longer possible to pass non-string types to the log method. Example:

log.info "this works"
Double notAString = 9.2
log.info notAString

The latter call to the info method will throw an exception as it is not a String.

Instead you should use Slf4j’s formatting anchors to log. The advantage is the toString() method is not called unless the message will be logged.

log.info "{}", 9.2D
log.debug "Key: {}, Value: {}", key, value
log.error "{}", exception.message, exception

See the Slf4j FAQ for more information.

Spring 4.3

Grails 3.2 comes with Spring 4.3 which no longer supports Hibernate 3 and hence Grails 3.2 no longer supports Hibernate 3 either and you will need to upgrade to Hibernate 4 or above.

Spring Boot 1.4

Spring Boot 1.4, through its dependency management mechanism, enforces the upgrade for many dependencies. You should review your dependencies following the upgrade to ensure the new versions are compatible with your application.

Spring Boot 1.4 also deprecates many testing annotations (such as WebIntegrationTest).

See the Spring Boot 1.4 release notes for more information on the changes required at the Boot level.

Hibernate 4 Usage

Related to Spring Boot 1.4, one important change is that Hibernate 5 is now the default version, so if you have declared a dependency on the hibernate4 plugin in Grails such as:

compile "org.grails.plugins:hibernate4"

This will not be enough to ensure that Hibernate 4 is used. You must instead also directly declare the Hibernate 4 dependencies:

dependencies {
    compile "org.grails.plugins:hibernate4"
    compile "org.hibernate:hibernate-core:4.3.10.Final"
    compile "org.hibernate:hibernate-ehcache:4.3.10.Final"
}

GORM 6 Configuration Model

In preparation for Hibernate 5.2 support the previous "SessionFactoryBean" notion has been removed. Now if you wish to customize SessionFactory creation you should instead register a custom org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory in Spring.

HibernateTestMixin Dependency Changes

The grails-datastore-test-support dependency has been removed and the HibernateTestMixin class integrated directly into the plugin, so if you receive a resolve error remove the following dependency from your build.gradle:

dependencies {
    testCompile "org.grails:grails-datastore-test-support"
}

application.groovy Changes

An improvement was added to make groovy configuration behave like yml configuration when it comes to the CLI. Previously, configuration values in application.groovy were not available to commands like grails create-controller. A side effect of this change causes an exception when those commands are executed if the configuration relies on classes in the runtime.

Error occurred running Grails CLI: startup failed:
script14738267015581837265078.groovy: 13: unable to resolve class com.foo.Bar

The solution is to create a separate file called runtime.groovy in grails-app/conf. That file will not be parsed by the CLI and will only be included at runtime.

Stop using the default namespace

Using the default package in places like UrlMappings.groovy, BootStrap.groovy or in a taglib can cause that code to fail or not execute at all when packaged in a JAR or WAR file. Make sure all Groovy/Java files start with the package statement and move any affected files to the respective folder. For example, change:

class UrlMappings {

    static mappings = {

    ...

to:

package myapp

class UrlMappings {

    static mappings = {

    ...

and move the file from grails-app/controllers/UrlMappings.groovy into .grails-app/controllers/myapp/UrlMappings.groovy

2.5 Upgrading from Grails 3.0

Generally to upgrade an application from Grails 3.0 you can simply modify the version of Grails in gradle.properties.

There are however some differences to Grails 3.0.x that are documented below.

GORM 5 Upgrade

Grails 3.1 ships with GORM 5, which is a near complete rewrite of GORM ontop of Groovy traits and is not binary compatible with the previous version of GORM.

If you receive an error such as:

Caused by: java.lang.ClassNotFoundException: org.grails.datastore.gorm.GormEntity$Trait$FieldHelper
    ... 8 more

You are using a plugin or class that was compiled with a previous version of GORM and these will need to be recompiled to be Grails 3.1 and GORM 5 compatible.

Hibernate Plugin

For the GORM 5 release the hibernate plugin has been renamed to hibernate4 (and there are hibernate3 and hibernate5 versions too). You should change your build.gradle to reflect that:

compile 'org.grails.plugins:hibernate4'

Static Resources Path

The default path for static resources resolved from src/main/resources/public has been changed to be nested under the static/* pattern instead of directly under the root of the application. For example a link in GSP pages such as:

${g.resource(dir:'files', file:'mydoc.pdf')}

Will produce a URI such as /static/files/mydoc.pdf instead of /files/mydoc.pdf. If you wish to revert to the previous behavior you can configure this in application.yml:

grails:
    resources:
        pattern: '/**'

Filters Plugin Removed

The Filters plugin was replaced by Interceptors in Grails 3.0.x, although the plugin was still present. In Grails 3.1.x the Filters plugin has been removed. If you still wish to use the filters plugin you can add a dependency on the previous version provided by Grails 3.0.x. For example:

compile 'org.grails:grails-plugin-filters:3.0.12'

You would also need to move the filters to any other source directory (e.g. grails-app/controllers) as grails-app/conf is not considered a source directory anymore.

Spring Transactional Proxies

Because the grails.transactional.Transactional transform already provides the ability to create transactional services without the need for proxies, traditional support for transactional proxies has been disabled by default for new applications.

This means that if you have any services that use the transactional property and not the Transactional annotation they should be altered. For example the following service:

class FooService {
    static transactional = true
}

Becomes:

import grails.transaction.Transactional

@Transactional
class FooService {

}

In addition because in previous versions of a Grails transactional defaulted to true any services that do not declare transactional should be altered too.

If you wish to adopt the new behavior then transctional proxies can be disabled with the following configuration:

grails:
    spring:
        transactionManagement:
            proxies: false

JSON Converter changes

The default JSON converter no longer includes the class property by default. This can be re-enable with the following configuration:

grails:
    converters:
        domain:
            include:
                class: true

In addition the default JSON converter will no longer render the id property if it is null.

JSON Builder Groovy Alignment

The class grails.web.JSONBuilder has been deprecated and replaced with groovy.json.StreamingJsonBuilder, the default JSON builder within Groovy. This avoids confusion with the differences between JSON builders and better aligns with Groovy’s core libraries.

This also means that any render blocks that rendered JSON will need to be updated to use the groovy.json.StreamingJsonBuilder syntax. For example the following code:

render(contentType:"application/json") {
    title = "The Stand"
}

Should instead be written as:

render(contentType:"application/json") {
    title "The Stand"
}

If you are upgrading and prefer to continue to use the previous implementation then you can re-enable the deprecated JSONBuilder with the following configuration:

grails:
    json:
        legacy:
            builder: true

JSON Views Replace JSON Converters

With the addition of JSON views the previous API for using JSON converters is largely discouraged in favour of views. The converters plugin will in the future be separated into an external plugin and JSON views phased in to replace it. The JSON converter API is not deprecated, however JSON views provide a more fully featured, elegant API that is superior to writing JSON converters and/or marshallers.

Spring Boot 1.3 and Spring 4.2

Grails 3.1 ships with upgraded third party libraries that may require changes. See the Spring Boot upgrade notes for information.

Unlike Spring Boot 1.2, Spring Boot 1.3 no longer uses the Gradle Application Plugin so if you relied on any behavior the application plugin then the plugin will need to be re-applied to your build.gradle.

Spring Boot 1.3 also uses Spring Security 4.x by default, so if you project depends on Spring Security 3.x you have to force a downgrade. For example:

compile 'org.springframework.security:spring-security-core:3.2.9.RELEASE'
compile 'org.springframework.security:spring-security-web:3.2.9.RELEASE'

Gradle run task no longer available by default

Because the Gradle run task for application startup was provided by the Gradle Application Plugin (see above), it is no longer available by default. If you use Gradle to start up your application, use the bootRun task instead, or re-apply the Application plugin in your build.gradle.

Note: If you don’t have need of the Gradle Application plugin’s features, but have custom Gradle tasks or IDE configurations that depend on run, you can supply your own run task that depends on bootRun in your build.gradle:

task run(dependsOn: ['bootRun'])

Resource annotation defaults to JSON instead of XML

The Resource annotation applied to domain classes defaults to XML in Grails 3.0.x, but in Grails 3.1.x and above it defaults to JSON.

If you use this annotation with the expecation of produces XML responses as the default you can modify the definition as follows:

import grails.rest.*

@Resource(formats=['xml', 'json'])
class MyDomainClass {}

This will restore the Grails 3.0.x behavior.

Geb and HTMLUnit 2.18

If you use Geb with HTMLUnit (something that is not recommended, as a more native driver such as PhantomJS is recommended) you will need to upgrade your dependencies in build.grade:

testRuntime 'org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1'
    testRuntime 'net.sourceforge.htmlunit:htmlunit:2.18'

Note that there are also some changes in behavior in HTMLUnit 2.18 that may cause issues in existing tests including:

  • Expressions that evaluate the title (Example $('title')) now return blank and should be replaced with just title

  • If you return plain text in a response without surrounding HTML tags, these are no longer regarded as valid responses and should be wrapped in the required tags.

application.groovy Changes (3.1.11+)

An improvement was added to make groovy configuration behave like yml configuration when it comes to the CLI. Previously, configuration values in application.groovy were not available to commands like grails create-controller. A side effect of this change causes an exception when those commands are executed if the configuration relies on classes in the runtime.

Error occurred running Grails CLI: startup failed:
script14738267015581837265078.groovy: 13: unable to resolve class com.foo.Bar

The solution is to create a separate file called runtime.groovy in grails-app/conf. That file will not be parsed by the CLI and will only be included at runtime.

2.6 Upgrading from Grails 2.x

Grails 3.0 is a complete ground up rewrite of Grails and introduces new concepts and components for many parts of the framework.

When upgrading an application or plugin from Grails 3.0 there are many areas to consider including:

The best approach to take when upgrading a plugin or application (and if your application is using several plugins the plugins will need upgrading first) is to create a new Grails 3.0 application of the same name and copy the source files into the correct locations in the new application.

Removal of before and after interceptors

Before and after interceptors were removed. So all beforeInterceptor and afterInterceptor need to be replaced by Stand alone interceptors.

File Location Differences

The location of certain files have changed or been replaced with other files in Grails 3.0. The following table lists old default locations and their respective new locations:

Old Location New Location Description

grails-app/conf/BuildConfig.groovy

build.gradle

Build time configuration is now defined in a Gradle build file

grails-app/conf/Config.groovy

grails-app/conf/application.groovy

Renamed for consistency with Spring Boot

grails-app/conf/UrlMappings.groovy

grails-app/controllers/UrlMappings.groovy

Moved since grails-app/conf is not a source directory anymore

grails-app/conf/BootStrap.groovy

grails-app/init/BootStrap.groovy

Moved since grails-app/conf is not a source directory anymore

scripts

src/main/scripts

Moved for consistency with Gradle

src/groovy

src/main/groovy

Moved for consistency with Gradle

src/java

src/main/groovy (yes, groovy!)

Moved for consistency with Gradle

test/unit

src/test/groovy

Moved for consistency with Gradle

test/integration

src/integration-test/groovy

Moved for consistency with Gradle

web-app

src/main/webapp or src/main/resources/

Moved for consistency with Gradle

\*GrailsPlugin.groovy

src/main/groovy

The plugin descriptor moved to a source directory

src/main/resources/public is recommended as src/main/webapp only gets included in WAR packaging but not in JAR packaging.

It is recommended to merge Java source files from src/java into src/main/groovy. You can create a src/main/java directory if you want to and it will be used but it is generally better to combine the folders. (The Groovy and Java sources compile together.)

For plugins the plugin descriptor (a Groovy file ending with "GrailsPlugin") which was previously located in the root of the plugin directory should be moved to the src/main/groovy directory under an appropriate package.

New Files Not Present in Grails 2.x

The reason it is best to create a new application and copy your original sources to it is because there are a number of new files that are not present in Grails 2.x by default. These include:

File Description

build.gradle

The Gradle build descriptor located in the root of the project

gradle.properties

Properties file defining the Grails and Gradle versions

grails-app/conf/logback.groovy

Logging previously defined in Config.groovy is now defined using Logback

grails-app/conf/application.yml

Configuration can now also be defined using YAML

grails-app/init/PACKAGE_PATH/Application.groovy

The Application class used By Spring Boot to start the application

Files Not Present in Grails 3.x

Some files that were previously created by Grails 2.x are no longer created. These have either been removed or an appropriate replacement added. The following table lists files no longer in use:

File Description

application.properties

The application version is now defined in build.gradle. The application name defaults to the directory name which can be overridden by creating a settings.gradle file and setting the rootProject.name property

grails-app/conf/DataSource.groovy

Merged together into application.yml

lib

Dependency resolution should be used to resolve JAR files

web-app/WEB-INF/applicationContext.xml

Removed. Beans can be defined in grails-app/conf/spring/resources.groovy

src/templates/war/web.xml

Grails 3.0 no longer requires web.xml. Customizations can be done via Spring

web-app/WEB-INF/sitemesh.xml

Removed. Sitemesh filter no longer present.

web-app/WEB-INF/tld

Removed. Can be restored in src/main/webapp or src/main/resources/WEB-INF

This guide takes you through the fundamentals of upgrading a Grails 2.x application or plugins to Grails 3.x.

2.6.1 Upgrading Plugins

To upgrade a Grails 2.x plugin to Grails 3.x you need to make a number of different changes. This documentation will outline the steps that were taken to upgrade the Quartz plugin to Grails 3, each individual plugin may differ.

Step 1 - Create a new Grails 3 plugin

The first step is to create a new Grails 3 plugin using the command line:

$ grails create-plugin quartz

This will create a Grails 3 plugin in the quartz directory.

Step 2 - Copy sources from the original Grails 2 plugin

The next step is to copy the sources from the original Grails 2 plugin to the Grails 3 plugin:

# first the sources
cp -rf ../quartz-2.x/src/groovy/ src/main/groovy
cp -rf ../quartz-2.x/src/java/ src/main/groovy
cp -rf ../quartz-2.x/grails-app/ grails-app
cp -rf ../quartz-2.x/QuartzGrailsPlugin.groovy src/main/groovy/grails/plugins/quartz

# then the tests
cp -rf ../quartz-2.x/test/unit/* src/test/groovy
mkdir -p src/integration-test/groovy
cp -rf ../quartz-2.x/test/integration/* src/integration-test/groovy

# then templates / other resources
cp -rf ../quartz-2.x/src/templates/ src/main/templates

Step 3 - Alter the plugin descriptor

You will need to add a package declaration to the plugin descriptor. In this case QuartzGrailsPlugin is modified as follows:

// add package declaration
package grails.plugins.quartz
...
class QuartzGrailsPlugin extends Plugin {
 ...
}

In addition you should remove the version property from the descriptor as this is now defined in build.gradle.

Step 4 - Update the Gradle build with required dependencies

The repositories and dependencies defined in grails-app/conf/BuildConfig.groovy of the original Grails 2.x plugin will need to be defined in build.gradle of the new Grails 3.x plugin:

compile("org.quartz-scheduler:quartz:2.2.1") {
    exclude group: 'slf4j-api', module: 'c3p0'
  }

It is recommended to use the latest stable, Grails 3+ compatible version of plugins. (Grails 2.x plugin versions will not work.)

Step 5 - Modify Package Imports

In Grails 3.x all internal APIs can be found in the org.grails package and public facing APIs in the grails package. The org.codehaus.groovy.grails package no longer exists.

All package declaration in sources should be modified for the new location of the respective classes. Example org.codehaus.groovy.grails.commons.GrailsApplication is now grails.core.GrailsApplication.

Step 5 - Migrate Plugin Specific Config to application.yml

Some plugins define a default configuration file. For example the Quartz plugin defines a file called grails-app/conf/DefaultQuartzConfig.groovy. In Grails 3.x this default configuration can be migrated to grails-app/conf/application.yml and it will automatically be loaded by Grails without requiring manual configuration merging.

Step 6 - Update plugin exclusions

Old plugins may have a pluginExcludes property defined that lists the patterns for any files that should not be included in the plugin package. This is normally used to exclude artifacts such as domain classes that are used in the plugin’s integration tests. You generally don’t want these polluting the target application.

This property is no longer sufficient in Grails 3, and nor can you use source paths. Instead, you must specify patterns that match the paths of the compiled classes. For example, imagine you have some test domain classes in the grails-app/domain/plugin/tests directory. You should first change the pluginExcludes value to

def pluginExcludes = ["plugin/test/**"]

and then add this block to the build file:

jar {
    exclude "plugin/test/**"
}

The easiest way to ensure these patterns work effectively is to put all your non-packaged class into a distinct Java package so that there is a clean separation between the main plugin classes and the rest.

Step 7 - Register ArtefactHandler Definitions

In Grails 3.x ArtefactHandler definitions written in Java need to be declared in a file called src/main/resources/META-INF/grails.factories since these need to be known at compile time.

If the ArtefactHandler is written in Groovy this step can be skipped as Grails will automatically create the grails.factories file during compilation.

The Quartz plugin requires the following definition to register the ArtrefactHandler:

grails.core.ArtefactHandler=grails.plugins.quartz.JobArtefactHandler

Step 8 - Migrate Code Generation Scripts

Many plugins previously defined command line scripts in Gant. In Grails 3.x command line scripts have been replaced by two new features: Code generation scripts and Gradle tasks.

If your script is doing simple code generation then for many cases a code generation script can replace an old Gant script.

The create-job script provided by the Quartz plugin in Grails 2.x was defined in scripts/CreateJob.groovy as:

includeTargets << grailsScript("_GrailsCreateArtifacts")

target(createJob: "Creates a new Quartz scheduled job") {
    depends(checkVersion, parseArguments)

    def type = "Job"
    promptForName(type: type)

    for (name in argsMap.params) {
        name = purgeRedundantArtifactSuffix(name, type)
        createArtifact(name: name, suffix: type, type: type, path: "grails-app/jobs")
        createUnitTest(name: name, suffix: type)
    }
}

setDefaultTarget 'createJob'

A replacement Grails 3.x compatible script can be created using the create-script command:

$ grails create-script create-job

Which creates a new script called src/main/scripts/create-job.groovy. Using the new code generation API it is simple to implement:

description("Creates a new Quartz scheduled job") {
    usage "grails create-job <<JOB NAME>>"
    argument name:'Job Name', description:"The name of the job"
}

model = model( args[0] )
render  template:"Job.groovy",
        destination: file( "grails-app/jobs/$model.packagePath/${model.simpleName}Job.groovy"),
        model: model

Please refer to the documentation on Creating Custom Scripts for more information.

Migrating More Complex Scripts Using Gradle Tasks

Using the old Grails 2.x build system it was relatively common to spin up Grails inside the command line. In Grails 3.x it is not possible to load a Grails application within a code generation script created by the create-script command.

Instead a new mechanism specific to plugins exists via the create-command command. The create-command command will create a new ApplicationCommand, for example the following command will execute a query:

import grails.dev.commands.*
import javax.sql.*
import groovy.sql.*
import org.springframework.beans.factory.annotation.*

class RunQueryCommand implements ApplicationCommand {

  @Autowired
  DataSource dataSource

  boolean handle(ExecutionContext ctx) {
      def sql = new Sql(dataSource)
      println sql.executeQuery("select * from foo")
      return true
  }
}

With this command in place once the plugin is installed into your local Maven cache you can add the plugin to both the build classpath and the runtime classpath of the application’s build.gradle file:

buildscript {
  ...
  dependencies {
    classpath "org.grails.plugins:myplugin:0.1-SNAPSHOT"
  }
}
...
dependencies {
  runtime "org.grails.plugins:myplugin:0.1-SNAPSHOT"
}

Grails will automatically create a Gradle task called runQuery and a command named run-query so both the following examples will execute the command:

$ grails run-query
$ gradle runQuery

Step 8 - Delete Files that were migrated or no longer used

You should now delete and cleanup the project of any files no longer required by Grails 3.x (BuildConfig.groovy, Config.groovy, DataSource.groovy etc.)

2.6.2 Upgrading Applications

Upgrading applications to Grails 3.x will require that you upgrade all plugins the application uses first, hence you should follow the steps in the previous section to first upgrade your plugins.

Step 1 - Create a New Application

Once the plugins are Grails 3.x compatible you can upgrade the application. To upgrade an application it is again best to create a new Grails 3 application using the "web" profile:

$ grails create-app myapp
$ cd myapp

Step 2 - Migrate Sources

The next step is to copy the sources from the original Grails 2 application to the Grails 3 application:

# first the sources
cp -rf ../old_app/src/groovy/ src/main/groovy
cp -rf ../old_app/src/java/ src/main/groovy
cp -rf ../old_app/grails-app/ grails-app

# then the tests
cp -rf ../old_app/test/unit/ src/test/groovy
mkdir -p src/integration-test/groovy
cp -rf ../old_app/test/integration/ src/integration-test/groovy

Step 3 - Update the Gradle build with required dependencies

The repositories and dependencies defined in grails-app/conf/BuildConfig.groovy of the original Grails 2.x application will need to be defined in build.gradle of the new Grails 3.x application.

Step 4 - Modify Package Imports

In Grails 3.x all internal APIs can be found in the org.grails package and public facing APIs in the grails package. The org.codehaus.groovy.grails package no longer exists.

All package declaration in sources should be modified for the new location of the respective classes. Example org.codehaus.groovy.grails.commons.GrailsApplication is now grails.core.GrailsApplication.

Step 5 - Migrate Configuration

The configuration of the application will need to be migrated, this can normally be done by simply renaming grails-app/conf/Config.groovy to grails-app/conf/application.groovy and merging the content of grails-app/conf/DataSource.groovy into grails-app/conf/application.groovy.

Note however that Log4j has been replaced by grails-app/conf/logback.groovy for logging, so any logging configuration in grails-app/conf/Config.groovy should be migrated to logback format.

Step 6 - Migrate web.xml Modifications to Spring

If you have a modified web.xml template then you will need to migrate this to Spring as Grails 3.x does not use a web.xml (although it is still possible to have on in src/main/webapp/WEB-INF/web.xml).

New servlets and filters can be registered as Spring beans or with ServletRegistrationBean and FilterRegistrationBean respectively.

Step 7 - Migrate Static Assets not handled by Asset Pipeline

If you have static assets in your web-app directory of your Grails 2.x application such as HTML files, TLDs etc. these need to be moved. For public assets such as static HTML pages and so on these should go in src/main/resources/public.

TLD descriptors and non public assets should go in src/main/resources/WEB-INF.

As noted earlier, src/main/webapp folder can also be used for this purpose but it is not recommended.

Step 8 - Migrate Tests

Once the package names are corrected unit tests will continue to run, however any tests that extend the deprecated and removed JUnit 3 hierarchy will need to be migrated to Spock or JUnit 4.

Integration tests will need to be annotated with the Integration annotation and should not extend GroovyTestCase or any JUnit 3 super class.

2.6.3 General Changes to be aware of when migrating apps

There are other miscellaneous changes between Grails 2.x and Grails 3.x that it may help to be aware of when migrating your applications and plugins. Minor changes may be required.

Domain classes

The Constraints section of a Domain Class (or other validateable object) looks like this:

static constraints = {
  name nullable: true, blank: false
  myField nullable: true
  another unique: true
}

In Grails 2.x, fields with no constraints could be declared in the Constraints block, as a method call with no arguments. Example (NB. the following syntax is no longer supported):

static constraints = {
  name nullable: true, blank: false
  mySimpleProperty()                  // <- A field that has no constraints. This syntax is not supported in Grails 3.
  anotherProperty unique: true
}

A different syntax has to be used in Grails 3. Either remove the field declaration from the constraints block (if there are no constraints to specify for it), or to keep the field placeholder, pass an empty map argument: \[:\] instead of ().

Replacement code for Grails 3.x:

static constraints = {
  name nullable: true, blank: false
  mySimpleProperty [:]                // <- Empty map argument instead of ()
  anotherProperty unique: true
}

If such declarations have not yet been changed then a log message like this emits on startup:

ORM Mapping Invalid: Specified config option <<mySimpleProperty>> does not exist for class [example.MyDomainClass]

Multi-project builds (Grails 2.x inline plugins)

If your project had inline plugins in Grails 2.x, contains ASTs, or if your project is composed of several modules or related applications then you may decide to restructure your project as a Gradle multi-project build.

Sample multi-project structure:

+ example
    + example-app   <-- Main app
    + example-core  <-- Shared code plugin
    + example-ast   <-- AST transformations plugin

How to configure this is documented in the Plugins section under the heading 'Inline Plugins in Grails 3.0'.

Migrating from Grails 2.x to Grails 3.1+

During the progress of migrating code from Grails 2.4 to Grails 3.1+, your project (and the plugins that your project depends on) will be moving to GORM 5 (or higher) and other newer library versions. You might also wish to familiarise yourself with the differences mentioned in the section Upgrading from Grails 3.0.

AST Transformations

If your application contains AST transformations, please be aware that for these to be applied to your application code, they must now be contained within a plugin. (In Grails 2.x it was possible to pre-compile AST transformations then apply them to your application code by hooking into compile events in _Events.groovy. This is no longer possible. Move your AST Transformation classes and associated annotations into a plugin for this purpose.)

There are two AST patterns on which you can base migration of your AST transformer code:

  • Groovy way: Use Groovy AST transformation annotations.

  • Grails way: Use Grails AST transformer annotations.

Groovy AST transformations
  • Import org.codehaus.groovy.transform.GroovyASTTransformation

  • Annotate your transformation class with GroovyASTTransformation(phase=CompilePhase.CANONICALIZATION)

  • A useful example app can be found here: grails3ast

Grails AST transformations
  • Import grails.compiler.ast.AstTransformer

  • Annotate your transformation class with AstTransformer

  • Implement applicable interfaces, particularly if you are transforming Artefacts, e.g. implements GrailsArtefactClassInjector, AnnotatedClassInjector

  • Your Transformer class must reside in a package under org.grails.compiler, otherwise it will not be detected. Example: org.grails.compiler.myapp

  • Examples can be found in the Grails source code

  • Example reference: ControllerActionTransformer.java

Deployment to containers

Grails uses Spring Boot to embed a Tomcat or Jetty instance by default. To build a war file for deployment to a container you will need to make a simple change to build.gradle (so that a container is not embedded).

If you deploy to a Tomcat 7 container then there is an additional step. Grails 3 is built against Tomcat 8 APIs by default. You will need to change the target Tomcat version in the build to 7.

There are standalone deployment options available.

Refer to the Deployment guide for further details.

Multiple datasources

If your application uses multiple datasources, then be aware that the way these are declared in application.yml or application.groovy (previously DataSources.groovy) has changed.

If there is more than one DataSource in an application there is now a dataSources { …​ } configuration block to contain them all. Previously, multiple dataSource declarations were used, with an underscore and suffix on the additional datasources, e.g. dataSource_lookup { …​ }.

Please refer to the user guide section on Multiple Datasources for examples.

Improvements to dependency injection

In your Grails 2.x app you may have used Spring @Autowired in a few situations, such as dependency injection into certain base classes, and for typed field dependency injection. For example:

@Autowired
org.quartz.Scheduler quartzScheduler

Grails now has support for dependency injection into typed fields in addition to untyped def fields, following the usual Grails conventions of field name matching the bean property name. Example:

GrailsApplication grailsApplication

You may find that @Autowired no longer works as it did previously in your code on artefacts or base classes, in certain scenarios, resulting in NULL for these fields. Changing these to a simple typed Grails dependency following the Grails naming convention and removing @Autowired should resolve this.