jdaugherty
05/18/2026, 3:16 PMuser
05/18/2026, 3:25 PMuser
05/19/2026, 9:00 AMg:meta / Metadata.current ? My app uses this to access some configuration values like info.app.version . Access using grailsApplication.config.getProperty('info.app.version') works as expected whereas Metadata.current.getApplicationVersion() yields @info.app.version@user
05/19/2026, 9:03 AMuser
05/19/2026, 9:07 AMPlugin [scaffolding:7.0.11] may not be compatible with this application as the application Grails version is less than the plugin requires. Plugin is compatible with Grails version 7.0.0-SNAPSHOT > * but app is @info.app.grailsVersion@
errors on startup...jdaugherty
05/19/2026, 10:31 AMpablo.pazos
05/19/2026, 7:41 PMuser
05/20/2026, 12:28 PMuser
05/20/2026, 12:29 PMsbglasius
05/20/2026, 1:00 PMsbglasius
05/20/2026, 1:00 PMuser
05/20/2026, 7:03 PMgopichand
05/22/2026, 4:06 PMmuser
05/26/2026, 4:56 PMafterUpdate, etc.) are too coupled to the domain and can't easily access services.
• Interceptors require duplication when you have multiple controller layers (e.g. backoffice + API).
• grails-events plugin with async subscribers requires withNewSession, which reads data before the original transaction commits — leading to stale/inconsistent reads.
• The withNewSession + TransactionSynchronizationManager.afterCommit workaround works but is verbose and fragile.
The recommended approach — centralising logic in a Service — works well, but only if the Service is the sole entry point for state changes. The moment a domain object changes its own state directly, there's no clean way to hook into that and trigger cross-domain logic.
How Other Frameworks Handle It
Laravel solves this natively with Model Observers and $afterCommit = true on listeners, making post-commit cross-domain logic straightforward and readable.
Spring Boot (without Grails) solves it with @TransactionalEventListener(phase = AFTER_COMMIT) and AbstractAggregateRoot, which lets the domain register events that are automatically published on save() — clean, explicit, and transaction-aware.
The Irony
Grails runs on Spring Boot, so @TransactionalEventListener is available and works well. However, AbstractAggregateRoot doesn't compose cleanly with GORM's class hierarchy, which blocks the most elegant part of the pattern — having the domain register its own events.
The workaround is to drop GORM and use Spring Data JPA directly within Grails, which gives you the full Spring pattern and eliminates withNewSession issues — but at the cost of losing GORM's dynamic finders, scaffolding, and DSL.
The Question
Has Grails 7 addressed this gap natively? Is there a recommended pattern for post-commit cross-domain logic that works cleanly with GORM, without requiring manual session management or losing the Active Record conveniences?
Would love to hear how others are handling this in production projects.user
05/28/2026, 6:26 PMgrails test-app SomeIntegrationSpec --integration --stacktrace
the compilation fails during :web:compileGroovy with several unable to resolve class errors for existing domain classes.
Stacktrace excerpt:
<=========----> 76% EXECUTING [26s]
> :web:compileGroovy
startup failed:
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/accesstoken/CustomerApiAccessTokenController.groovy: 18: unable to resolve class com.example.domain.criticalaction.CriticalActionGroup
@ line 18, column 1.
import com.example.domain.criticalaction.CriticalActionGroup
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/backoffice/AuthorizationTokenAdminController.groovy: 6: unable to resolve class com.example.domain.criticalaction.CriticalActionGroup
@ line 6, column 1.
import com.example.domain.criticalaction.CriticalActionGroup
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/backoffice/childaccountconfig/ChildAccountParameterController.groovy: 11: unable to resolve class com.example.domain.criticalaction.CustomerCriticalActionConfig
@ line 11, column 1.
import com.example.domain.criticalaction.CustomerCriticalActionConfig
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/checkout/PixAutomaticRecurringCheckoutLimitChangeRequestController.groovy: 8: unable to resolve class com.example.domain.criticalaction.CriticalActionGroup
@ line 8, column 1.
import com.example.domain.criticalaction.CriticalActionGroup
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/config/CriticalActionConfigController.groovy: 11: unable to resolve class com.example.domain.criticalaction.CustomerCriticalActionConfig
@ line 11, column 1.
import com.example.domain.criticalaction.CustomerCriticalActionConfig
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/customerexternalauthorization/CustomerExternalAuthorizationRequestConfigController.groovy: 8: unable to resolve class com.example.domain.criticalaction.CriticalActionGroup
@ line 8, column 1.
import com.example.domain.criticalaction.CriticalActionGroup
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/pix/PixAddressKeyController.groovy: 6: unable to resolve class com.example.domain.criticalaction.CriticalActionGroup
@ line 6, column 1.
import com.example.domain.criticalaction.CriticalActionGroup
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/pix/PixAddressKeyController.groovy: 7: unable to resolve class com.example.domain.criticalaction.CustomerCriticalActionConfig
@ line 7, column 1.
import com.example.domain.criticalaction.CustomerCriticalActionConfig
^
/Users/***/Documents/project/web/grails-app/controllers/com/example/controller/pix/PixAuthorizedDeviceController.groovy: 5: unable to resolve class com.example.domain.criticalaction.CriticalActionGroup
@ line 5, column 1.
import com.example.domain.criticalaction.CriticalActionGroup
^
> Task :web:compileGroovy FAILED
18 actionable tasks: 1 executed, 17 up-to-date
<-------------> 0% WAITING
> IDLE
ternal.DefaultWorkerServer.execute(DefaultWorkerServer.java:47)
at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:46)
at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:36)
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:98)
at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:36)
at org.gradle.workers.internal.IsolatedClassloaderWorker.execute(IsolatedClassloaderWorker.java:54)
at org.gradle.workers.internal.WorkerDaemonServer.execute(WorkerDaemonServer.java:56)
at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:118)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
... 3 more
The classes do exist in the project and everything works correctly on Linux environments.
Has anyone experienced something similar?jdaugherty
05/28/2026, 7:20 PMsbglasius
05/28/2026, 9:05 PMuser
05/31/2026, 8:05 AMTest, Test1, etc.)
â—¦ Module 2 (uses domain classes from Module 1)
In a GSP page, I have something like:
test1 class is a Foreign Key(FK) in test class
<g:each in="${testList}" var="test">
<option value="${test.id}">
${test?.test1?.name}
</option>
</g:each>
After migrating to Grails 7, the page throws the following error:
No datastore session found. Call Datastore.connect(..) before calling Datastore.getCurrentSession()
Interestingly, if I access the association in the controller before rendering the GSP, or if I convert the data to DTOs/maps and pass that to the view, the page works correctly.
My questions are:
1. Has datastore session handling during GSP rendering changed in Grails 7 compared to Grails 6?
2. Is there a recommended global solution for this issue instead of manually initializing associations or creating DTOs for every page?
3. Has anyone faced similar issues in multi-module Grails 7 applications using MongoDB references?
Any suggestions or best practices would be greatly appreciated.jdaugherty
05/31/2026, 1:09 PMrss
06/04/2026, 6:24 PMuser
06/04/2026, 9:43 PMrss
06/07/2026, 5:44 PMuser
06/09/2026, 7:59 AMclass Entity {
String name
static belongsTo = [other: Other]
}
class Other {
String name
}
And a GORM data service with a derived finder over taht association:
@Service(Entity)
class EntityDataService {
List<Entity> findAllByOther(Other other)
}
This fails at compile time with:
Cannot implement finder for non-existent property [other] of class [com.demo.Entity]A dynamic Entity.findAllByOther(other) works fine, so I'd expect t he @Service codegen to resolve it too. I am using Grails 5.2.4
user
06/09/2026, 1:06 PMuser
06/10/2026, 9:09 PMuser
06/30/2026, 9:35 AMgradle.properties in your projects? I enabled dependabot for gradle but it apparently does not manage gradle.properties correctly. I hacked a GitHub workflow to check Maven central for new version of Grails and make a decision based on curl/grep/tr output. I would like to have something working for other version I've specified in gradle.properties , do you know if there is something? My AI is suggesting to move from `gradle.properties`to libs.versions.toml but I'm unsure this is a good option.user
06/30/2026, 9:35 AMgaolei
07/08/2026, 6:46 PMDave
07/11/2026, 11:14 AMrss
07/13/2026, 1:24 PM