I did a bunch of reasonably large applications wit...
# questions
j
I did a bunch of reasonably large applications with Grails 2 a long while back, and although most have now been upgraded to Grails 6 and all the new stuff I've done uses Grails 6 (although I will start using 7 very soon), I feel I've not taken nearly as much advantage as I might have done of the capabilities provided by the newer versions. One thing I've been looking at in the last couple of days, which I've never used before, is Traits. In an application I'm working on at the moment, I'm moving away from using standard SMTP email (for which I generally use the Mail plugin) to using an email provider via an API. As email will need to be sent from various parts of the application and I don't want to repeat myself, I want to have an email component I can call from anywhere (as with the Mail plugin). I would naturally think of a service class for this, which could be used from controllers and other services, Quartz jobs, whatever. But what about a Trait for this instead? I could then even use it from a domain class method should I need to (not that I ever would, I think). To make sense the Trait would have to be able to use configuration from my application.groovy file. so I would want to implement GrailsApplicationAware in it. I then implement this trait in a service class, in which 'grailsApplication' is injected. But when I go to compile I get an error like this:
Task :compileGroovy startup failed: /root/src/borderbus/grails-app/controllers/borderbus/AdminController.groovy: 11: The return type of java.lang.Object getGrailsApplication() in borderbus.AdminController is incompatible with grails.core.GrailsApplication in grails.web.api.WebAttributes . At [11:1] @ line 11, column 1. class AdminController implements BrevoTrait { ^ 1 error
This presumably means there's a conflict between the getGrailsApplication() method from two different sources, the trait and the service. Am I doing this right? How can I get around this problem without overcomplicating things? And is a Trait a natural fit for this, or is there a better way? I presume I could create my own plugin but it's not something I've ever done before and I imagine it might be more cumbersome than is ideal.
Just thought maybe that implementing WebAttributes in the Trait would give me access to the GrailsApplication and avoid this hiccup. I'll give it a try? Having said that I'm thinking that maybe using a Trait for this wouldn't be necessary anyway, as I could maybe just use a class in /src?
j
Traits are a superpower of Groovy, since you can implement multiple Traits and the trait includes the implementation, unlike interfaces. It allows your code to be far DRYer. For email sending (such as via SendGrid's API), I would put that in a service and inject that service into your controllers or other services. All of my Domains implement a common trait. For me that is mostly about configuring Audit Logging, but it could be anything and they could implement a mix of multiple traits.
g
From an architectural point of view I would implement a service that can be injected wherever is needed. Traits implement multiple inheritance, I would not wire the email sending into the class hierarchy to keep the design modular and decoupled.
j
Thanks. As it happens, shortly after posting, I decided on using a service myself after all. An alternative was a Spring component, but I decided that with that I'd just be creating what is effectively much the same as a service anyway, just without the useful naming convention. I'll explore the use of traits elsewhere.
👍 1
👍🏼 1