////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////

=== Upgrade Instructions for Grails and Related Dependencies

To ensure compatibility with Grails 7.0.0, please review the following upgrade instructions carefully.
This guide outlines the necessary steps & warnings to upgrade your Grails project.

==== 1. Java 17 as baseline:

Starting from Grails 7.0.0, Java 17 serves as the baseline requirement for the framework.
When upgrading to Grails 7.0.0, ensure that your project is configured to use Java 17. Updating to Java 17 allows you to take advantage of the latest features, security enhancements, and performance improvements provided by Java 17.

Please make sure to update your project's Java version to 17 before proceeding with the Grails 7.0.0 upgrade.
Doing so will ensure a seamless transition to the latest version of Grails and enable you to enjoy all the benefits that Java 17 has to offer.

==== 2. Groovy 4.0.27 as a baseline:

Grails 7.0.0 adopts Groovy 4.0.27 as it's baseline requirement.
Several changes in Groovy 4 can affect your application.
Notable changes include:

1. https://issues.apache.org/jira/browse/GROOVY-10621[GROOVY-10621] - Primitive booleans will no longer generate the form of isProperty & getProperty.
They will only generate isProperty().
For Grails Domain objects, grails sometimes generates these properties.
It is advisable to switch to the new form of the property.
2. https://issues.apache.org/jira/browse/GROOVY-5169[GROOVY-5169] & https://issues.apache.org/jira/browse/GROOVY-10449[GROOVY-10449] - Fields with a public modifier were not returned with MetaClassImpl#getProperties() in groovy 3, but are now.

Some older libraries may include an older version of groovy, but still be compatible with Groovy 4. One example is GPars.
In your gradle file, you can force a dependency upgrade via this code:

[source,groovy]
.build.gradle
----
  configurations.configureEach {
      resolutionStrategy.eachDependency { DependencyResolveDetails details ->
          if (details.requested.group == 'org.codehaus.groovy') {
              details.useTarget(group: 'org.apache.groovy', name: details.requested.name, version: '4.0.27')
          }
      }
  }
----

==== 3. Unified Project Version

Grails 7.0.0 moved to a mono repository.
As part of this move, all projects that make up a grails release now have a common version.
Setting `grailsVersion` in `gradle.properties` is the proper way to specify a set of dependencies that are compatible with each other for a given Grails release.
Please remove older properties such as `gormVersion` & `grailsGradlePluginVersion` and exclusively use this property going forward.

.gradle.properties
[,,subs="attributes"]
----
grailsVersion=7.0.0
----

==== 4. Unified Bill of Materials

Previously Grails did not have a single Bill of Materials (BOM).
Instead it had a `micronaut-bom` and a `spring-bom`.
With the removal of Micronaut from the Grails, the `micronaut-bom` is no longer needed.
Instead, we can have a single bom that inherits from the `spring-bom`.

Grails 7.0.0 introduces a BOM that includes all the dependencies required for a Grails application.
This BOM is available in the `org.apache.grails:grails-bom` artifact.
The BOM is automatically applied when a Grails Gradle plugin is applied via the Spring Dependency Management plugin.
For projects that do not use a Grails Gradle plugin, you can apply the BOM via a https://docs.gradle.org/current/userguide/java_platform_plugin.html#sec:java_platform_consumption[Gradle Platform]:

[source,groovy]
.build.gradle
----
dependencies {
    implementation platform("org.apache.grails:grails-bom:${grailsVersion}")
}
----

Because all Grails projects will apply the Grails Gradle plugin, the BOM is automatically applied.
You can override a version in the BOM by setting the associated Gradle property.
The possible gradle properties are generated as part of this documentation.
Please see xref:../ref/Versions/Grails BOM.adoc[Grails BOM Dependencies] for a quick reference.

==== 5. Coordinate Changes

Grails has transitioned to the Apache Software Foundation (ASF).
As a result, the group ID for Grails artifacts has changed to `org.apache.grails`.
This change applies to all Grails packages, including core plugins and core dependencies, maintained by the Grails team.
When upgrading to Grails 7.0.0, ensure that you update your build configuration to use the new group ID.

There is a https://github.com/apache/grails-core/blob/7.0.x/RENAME.md[RENAME.md] in the grails-core repository that maps previous coordinate names to new names.
Additionally, there is a script to aid in the updating of Grails projects to the new coordinates.
The script is located in the `etc/bin` directory of the https://github.com/apache/grails-core/tree/7.0.x/etc/bin[grails-core] repository and can be run as follows:

```shell
  ./rename_gradle_artifacts.sh -l my/project/location
```

This script will scan any gradle file and attempt to update both exclusions & dependencies to the new coordinates.

==== 6. Gradle Changes:

One of the major changes in Grails 7.0.0 is the modernization of it's build system. As a side effect of this modernization, the Grails build is fully parallel & https://docs.gradle.org/current/userguide/task_configuration_avoidance.html[lazy]. Moreover, most tasks have been enhanced to be cacheable. When updating to Grails 7.0.0, there may be required updates to various tasks we distribute since the inputs of those tasks have changed to support lazy configuration.

===== 6.1. Gradle Plugin Changes
As part of the cacheable task changes, some tasks have slightly new behaviors:

- FindMainTask can now fail for non-plugins: If an Application class is not found & the project has a Grails gradle plugin applied, the FindMainTask will now fail.
- FindMainTask is now cacheable - restarting with bootRun should not force a recompile of the application if no changes have been made.
- Configuration tasks have been added to customize compileGroovy tasks. These tasks allow for proper metadata being passed to the Groovy compiler to ensure the AST transformations know if code is a Grails Plugin or a Grails Application. In the event these tasks do not run or are caching incorrectly, you may observe incorrect UrlMapping resolution. Please report any instances of this happening so it can be addressed.
- `groovyVersion` is now `groovy.version` to match upstream Spring BOM property names. If you still define groovyVersion to override the groovy version & use the Spring Dependency Management plugin, you will need to change this property to `groovy.version` in your `gradle.properties` file.
- While the Spring Dependency Management plugin is still used by default, it can now be disabled by setting the property `springDependencyManagement` on the `grails` extension.

===== 6.2. Upgrading Gradle:

It is recommended to set your gradle version to a version of 8.14 or higher:

[,console,subs="attributes"]
----
./gradlew wrapper --gradle-version 8.14
----

This command will download the specified Gradle version and update the Gradle wrapper settings in your project.

===== 6.3. Check Gradle Version:

After the command finishes, you can verify that the Gradle version has been updated by checking the `gradle-wrapper.properties` file located in the `gradle/wrapper` directory.
The `distributionUrl` in the file should now point to the specified Gradle version's distribution:

[,,subs="attributes"]
----
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip
----

===== 6.4. Removed Gradle Plugins

The `grails-doc` plugin has been removed. If you wish to continue to generate the guide documentation, you can use the PublishGuideTask offered by `grails-docs-core`.

==== 7. Reproducible Builds:

The ASF strongly encourages https://reproducible-builds.org/[reproducible builds] as part of it's security requirements.
We have begun making the Grails build reproducible - that is, if you build with the same settings as the GitHub action the produced artifacts should be identical.
We have starting addressing reproducible builds under the ticket https://github.com/apache/grails-core/issues/14679[#14679].

A side effect of making our builds reproducible is that Grails applications can also now be reproducible.
The benefits of reproducible builds are well documented, but for Grails applications, some of the side effects include:

1. Improved build times - since the build is reproducible, Gradle can cache the results of the build and reuse them in future builds.
2. Minimizing rebuilds - if the build is reproducible, Gradle can avoid unnecessary rebuilds of tasks that have not changed.
3. Improved security - reproducible builds can help to ensure that the build process is not tampered with, and that the resulting artifacts are exactly what was intended.

To make your local build reproducible, you'll want to set the environment variable `SOURCE_DATE_EPOCH` to a fixed date.
For Grails, we set this value to the last commit in git via the bash command: `SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)`

==== 8. Spring 6.2.6:

Grails 7.0.0 is built on the Spring Framework, version 6.2.6. If your project uses Spring-specific features, refer to the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x[Upgrading to Spring 6 guide].

This update introduces enhancements and fixes to the Spring Framework, providing you with the latest improvements in dependency injection, web frameworks, and other Spring-related functionalities.

==== 9. Spring Boot 3.5.0:

Grails 6 used Spring Boot 2.7. Grails 7.0.0 updates this to Spring Boot 3.5.0. For more information, consult the release notes for previous Spring Boot releases:
1. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.5-Release-Notes[Spring Boot 3.5 Release Notes]
2. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[Spring Boot 3.4 Release Notes]
3. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[Spring Boot 3.3 Release Notes]
4. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[Spring Boot 3.2 Release Notes]
5. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[Spring Boot 3.1 Release Notes]
6. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.4-Release-Notes[Spring Boot 3.0 Release Notes]

==== 10. Upgrading Your Project:

In addition to the coordinate changes, the version updates, and the build updates, to upgrade your project it is advised to use an application generator and compare it to your existing project.
The preferred app generator for Grails is https://start.grails.org/[start.grails.org].
Please note that several previously required gradle configurations have been integrated into the Grails Gradle Plugins as defaults.
Compare a freshly generated application to your application and apply any associated changes.

===== 10.1 Building the Project:

After comparing to a generated build & updating your gradle files, you can now build your Grails project using the updated Gradle version:

```console
./gradlew build
```

This will initiate the build process with the new Gradle version.

==== 11. Grails CLI

Both the legacy `grails-shell-cli` and `grails-forge-cli` are now included with Grails 7. Please see the xref:../guide/gettingStarted#downloadingAndInstalling[Downloading & Installing] section of this guide for important background on how to use the Grails CLI commands.

==== 12. Breaking changes

Grails 7.0.0 introduces several breaking changes that may require updates to your application.

===== 12.1

Due to the significant changes in Grails 7, all prior Grails Plugins will need updated to work with Grails 7. For plugins in the https://github.com/grails-plugins/[Grails Plugins] GitHub organization, the Grails Core team is updating them as time permits and when requested.
If there is a plugin that you require updating, please reach out via https://github.com/apache/grails-core/issues[ticket] to see if we can help.

===== 12.2 javax -> Jakarta

Spring has switched from javax to https://jakarta.ee/[jakarta] packages.
Please consult the Spring upgrade guides for the impacts of this change.

Gradle Javax-to-Jakarta EE migration plugins, such as the https://github.com/nebula-plugins/gradle-jakartaee-migration-plugin?tab=readme-ov-file#configuring-the-plugin[gradle-jakartaee-migration-plugin], provide transforms and dependency substitutions to ease the migration from Java EE (`javax.`) to Jakarta EE (`jakarta.`). These plugins can help mitigate upgrade challenges with older dependencies that still use `javax.` until they are updated or replaced with alternative solutions.

To apply and configure the `gradle-jakartaee-migration-plugin` in your `build.gradle`, you can use the following snippet:

[source,groovy]
.build.gradle
----
plugins {
    id 'com.netflix.nebula.jakartaee-migration' version '0.24.0'
}

jakartaeeMigration {
    migrate()
}
----

===== 12.3 Removed libraries/classes
- The `grails-web-fileupload` library, including its sole class `ContentLengthAwareCommonsMultipartResolver`, has been removed. This change was necessitated by the removal of the superclass `CommonsMultipartResolver` in Spring 6. The `ContentLengthAwareCommonsMultipartResolver` was originally introduced to address a bug in Safari back in 2007, but it is likely no longer needed. Spring has transitioned away from `CommonsMultipartResolver` and now recommends using the built-in support for multipart uploads provided by servlet containers. For more information on handling file uploads in Spring Boot, please refer to the relevant sections of the https://docs.spring.io/spring-boot/how-to/spring-mvc.html#howto.spring-mvc.multipart-file-uploads[Spring Boot documentation] and the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#web-applications-1[Spring Framework 6 upgrade guide].
- `org.grails.spring.beans.factory.OptimizedAutowireCapableBeanFactory` was previously deprecated and is now removed.
- The following deprecated classes were removed, please use the suggested replacement:

1. `grails.core.GrailsTagLibClass` -> `grails.core.gsp.GrailsTagLibClass`
2. `org.grails.core.artefact.TagLibArtefactHandler` -> `org.grails.core.artefact.gsp.TagLibArtefactHandler`
3. `org.grails.core.DefaultGrailsTagLibClass` -> `org.grails.core.gsp.DefaultGrailsTagLibClass`
4. `org.grails.plugins.CodecsGrailsPlugin` -> `org.grails.plugins.codecs.CodecsGrailsPlugin`

===== 12.4 Micronaut in Grails is now supported via the Micronaut Spring Boot Starter
- This change was made based on community input: https://github.com/orgs/grails/discussions/13517
- The removal of Micronaut enabled simplification of the Grails codebase and the return of Live Reload via https://github.com/HotswapProjects/HotswapAgent
- The Micronaut Parent Context is no longer in Grails by default.
- The following dependencies are no longer included in Grails or grails-bom: io.micronaut:micronaut-\*, io.micronaut.cache:micronaut-cache-core, io.micronaut.groovy:micronaut-runtime-groovy and io.micronaut.spring:micronaut-spring-*
- Micronaut can be added via the Micronaut Spring Boot Starter: https://micronaut-projects.github.io/micronaut-spring/latest/guide/#springBootStarter.
- Using Micronaut Parent Context: https://micronaut-projects.github.io/micronaut-spring/latest/guide/#springParentContext
- Using a Bean Post Processor: https://micronaut-projects.github.io/micronaut-spring/latest/guide/#beanPostProcessor

===== 12.5 hibernate-ehcache

The `org.hibernate:hibernate-ehcache` library is no longer provided by the `org.apache.grails:grails-hibernate5` plugin. If
your application depends on `hibernate-ehcache`, you must now add it explicitly to your project dependencies.

Since `hibernate-ehcache` brings in a conflicting `javax` version of `org.hibernate:hibernate-core`, it is
recommended to exclude `hibernate-core` from the `hibernate-ehcache` dependency to avoid conflicts:

[source,groovy]
.build.gradle
----
dependencies {
    implementation 'org.hibernate:hibernate-ehcache:5.6.15.Final', {
        // exclude javax variant of hibernate-core
        exclude group: 'org.hibernate', module: 'hibernate-core'
    }
    runtimeOnly 'org.jboss.spec.javax.transaction:jboss-transaction-api_1.3_spec:2.0.0.Final', {
        // required for hibernate-ehcache to work with javax variant of hibernate-core excluded
    }
}
----

===== 12.6 H2

The test database H2 is stricter about reserved keywords.
If you use H2 in your application, please take a look at this https://github.com/grails/grails-data-hibernate5/pull/910/commits/c8de45df204966ccc228b46b94beeb2142ae0f59[pull request] for examples of these new restrictions.

===== 12.7 Removal of Test Dependencies from Production Classpath

Prior versions of Grails included test dependencies on the production classpath.
These are now removed in Grails 7. If you still need them, you can add them to your `implementation` configuration in your build.gradle file.

===== 12.8 Jar Artifact name changes

Jar artifacts produced by Grails Plugins will no longer have the suffix `-plain`.
Please see ticket https://github.com/apache/grails-gradle-plugin/pull/347[#347] for details.

===== 12.9 Java 20+ Date Formatting Changes

In Java 20+, https://cldr.unicode.org/downloads/cldr-42[Unicode CLDR42] was implemented which changed the space character preceding the period (AM or PM) in formatted date/time text from a standard space (" ") to a narrow non-breaking space (NNBSP: "\u202F"). Additionally, when using the LONG or FULL timeStyle with dateStyle, the date and time separator has changed from ' at ' to ', '. IE. January 5, 1941, 8:00:00 AM UTC vs. January 5, 1941 at 8:00:00 AM UTC

===== 12.10 Container runtime environment is now required for standard Geb functional and integration tests

The https://github.com/apache/grails-core/tree/HEAD/grails-geb#readme[Grails Geb Plugin] has received a significant update, introducing test fixtures that enable ubiquitous containerized browser testing.

This new approach is now the recommended way to write functional tests in Grails, but it *requires a container runtime environment*.

The previous method using WebDriver binaries remains supported for backward compatibility, although matching driver and browser versions can be challenging.

===== 12.11 Asset Pipeline

The asset pipeline has a new https://github.com/wondrify/asset-pipeline[home]. Version 5.0.12 and forward is compatible with Grails 7.x.

===== 12.12 API Changes

As part of any major release, APIs can change.  For Grails 7.0, the list of renamed APIs follows:

* GrailsClassUtils#isMatchBetweenPrimativeAndWrapperTypes -> GrailsClassUtils#isMatchBetweenPrimitiveAndWrapperTypes

====== 12.13 Layout Configuration

There are several changes related to layout related configuration:

Package Changes:
* grails.web.sitemesh -> org.apache.grails.web.layout
* org.grails.web.sitemesh -> org.apache.grails.views.gsp.layout

Notable Class Moves:
* org.grails.web.servlet.view.GrailsLayoutViewResolver -> org.grails.web.servlet.view.EmbeddedGrailsLayoutViewResolver
* org.grails.web.servlet.view.SitemeshLayoutViewResolver -> org.grails.web.servlet.view.GrailsLayoutViewResolver
* org.grails.web.sitemesh.GrailsLayoutView -> org.apache.grails.web.layout.EmbeddedGrailsLayoutView
* org.grails.web.sitemesh.SitemeshLayoutView -> org.apache.grails.web.layout.GrailsLayoutView

Property Changes:
* grails.sitemesh.default.layout -> grails.views.layout.default
* grails.sitemesh.enable.nongsp -> grails.views.layout.enable.nongsp

Tag namespace changes:
* sitemesh -> grailsLayout

====== Key Features

By extending your test classes with `ContainerGebSpec`, your tests will automatically leverage a containerized browser provided by https://www.testcontainers.org[Testcontainers]. This setup eliminates the need for managing browser versions and ensures consistent test environments.

====== Requirements

To use `ContainerGebSpec`, ensure that you have a compatible container runtime installed. Supported options include:

- **Docker Desktop**
- **OrbStack** (macOS only)
- **Rancher Desktop**
- **Podman Desktop**
- **Colima** (macOS and Linux)

====== How It Works

Once a compatible container runtime is installed, no additional configuration is needed. Simply extend your test classes with `ContainerGebSpec` (instead of `GebSpec`), and the following will happen:

1. A container will be started automatically when you run your integration tests.
2. The container will be configured to launch a browser capable of accessing your application under test.

With this setup, you gain the benefits of containerized testing, such as isolation, reproducibility, and reduced setup complexity.

===== 12.10 Tomcat 10.1.42 introduced limits for part count and header size in multipart/form-data requests

These limits can be customized using `server.tomcat.max-part-count` and `server.tomcat.max-part-header-size` respectively.

`server.tomcat.max-part-count` default is 10
`server.tomcat.max-part-header-size` defalt is 512B

https://docs.spring.io/spring-boot/appendix/application-properties/index.html#application-properties.server.server.tomcat.max-part-count[Spring Boot Common Application Properties]
