Typically security and similar cross-cutting concerns are best handled with aspect-oriented programming style which means using interceptors in the Grails environment.
Using interceptors makes total sense because probably Spring Security Core plugin annotations don't suffice for them. Maybe, they need to to check not just whether the user has a role but if the user is trying to read an entity belonging to a tenant which the user has access to.
For exceptional states, there are exceptions in Java. You can move the code into the service and throw exceptions at the points where would you normally return from the controller action:
For almost the whole year, I am working in a Micronaut project written in Java with Groovy tests with Spock. We are using a similar approach: a lot of Runtime exceptions in the service layer to keep controller methods dry and then we combine declarative controller exception handling and in some cases global handling.