Goodbye Grails, Hello Micronaut #6: Domain Classes
This is the sixth post in a series that will guide you through the migration from Grails to Micronaut. This guide requires your application to be based on Grails 4.x or later.
Domain classes are usually the essential part of any Grails application, therefore the most difficult part to migrate. First of all, we need to migrate every database-related calls to use Data Services instead of any instance or static magic methods and properties.
We can very easily create the data service for the domain class Vehicle
we were mentioning earlier:
This service was already used in the controller in the previous step.
Finding GORM Method using VCS
The most difficult part is to find all usages of the GORM instance and static API.
First, find all the usages of the given entity. The easiest way is to commit all your work to the VCS and let your IDE do the difficult part of finding references. Select one of your entities and move into a different package. I'm usually simply adding .legacy
at the end of the current package name so for example, the Vehicle
domain class will in hello
package any longer but it will be located in hello.legacy
.
Don't forget to move the data service as well.
Now visit the list of the VCS-changed files. The list should show all the classes referring to the specific domain class.
Then you need to replace all the instance and static GORM method calls in these files. For example, change Vehicle.get(id)
to vehicleDataService.findById(id)
. You can either mock the vehicleDataService
in your tests or you can use this article to use the real implementation against the test datastore:
Let's summarise the steps required for each domain class:
- Commit all your changes into VCS
- Move the domain class into a different package such as
original.legacy
- Create a data service for the given domain or move the existing one into the same package
- Review all VCS-changed files
- Replace GORM methods with data service calls
- Back to step 1 unless you migrate all the domain classes
Finding GORM Methods at the Compile Time
Once you complete the steps above, there might still be some well-hidden calls to the GORM instance and static methods. You can use Groovy Code Check for GORM to find these statements:
compileOnly 'com.agorapulse:groovy-code-checks-gorm:0.9.0'
This library is very strict and it will create compilation failures wherever it finds any GORM-related method. This is very useful for indirect usages such as user.vehicle.save()
where the GORM methods are not called directly on the entity object but a reference one.
Yet another set of compilation issues can be triggered by changing the convention.groovy
Enterprise Groovy configuration file.
If you comment out or remove the checking extensions related to GORM then you should get compilation errors wherever you use any GORM magic.
Extracting Domain Classes into a Library
Let's extract the domain classes into the separate subproject to allow modularization of the other parts of the application. There is a dedicated article that can help you achieve this:
If you have applied Kordamp layout you simply create a new folder under libs
such as hello-data
containing hello-data.gradle
build file.
You will also need to declare Grails Central repository in the root build.gradle
file for all projects:
allprojects {
repositories {
mavenCentral()
maven { url 'https://repo.grails.org/grails/core/' }
}
}
And add two now properties into root gradle.properties
file:
gorm.hibernate.version = 7.0.5
micronautVersion = 1.3.7
We will also need a fake Grails plugin descriptor in src/main/groovy
directory:
Next, create folders grails-app/domains
and grails-app/services
within the new data library.
Then add the new library as a dependency of your Grails application in hello.gradle
:
implementation project(':hello-data')
If you are using IntelliJ IDEA you should be able to simply move the packages containing the domain entities into the new library. Select the original package and select Refactor / Move Package or Directory … option from the top menu (default shortcut F6).
Then select Move directory … to another source root
And select grails-app/domain
source folder as the destination:
Now revisit every domain in the new data library and add grails.gorm.annotation.Entity
annotation.
Last but not least, move the related GORM data services into the grails-app/services
folder so all the domain classes' related code is now within its own library.
Extracting Test Data into Library
As a next step, you should create another library that will hold the test data to ensure you can use them from everywhere.
Create a new folder hello-data-test-data
containing a new build file hello-data-test-data.gradle
.
Move the test data classes such as HelloDataSets
into src/main/groovy
.
Move the test data such as vehicle.json
into src/main/resources
.
Move the tests for the data sets such as HelloDataSetsSpec
into src/test/groovy
to keep the data sets properly tested.
Don't forget to add the dependency to the new test data library into your application's build file hello.gradle
testCompile project(':hello-data-test-data')
Having the domain classes extracted, we can also extract the services into a separate library in the next step.
Table of Contents
- Multiproject
- Configuration
- Static Compilation
- Datasets
- Marshalling
- Domain Classes
- Services
- Controllers
- Micronaut Application
- Micronaut Data