My Grails app has the following Spring bean defined in spring/resources.groovy
calendarService(CalendarService) { bean ->
bean.initMethod = "init"
}
This method looks something like:
class CalendarService {
void init() {
User.findByEmail("foo#doo.com")
}
}
When I call the dynamic finder findByEmail I get a MissingMethodException. My guess is that I'm trying to call this method too early, i.e. before the domain classes have had the dynamic finders added to their metaclass. One solution would be to call CalendarService.init() myself from Bootstrap.init, rather than instructing Spring to call it, but is there a better solution?
Thanks,
Don
You're right, as described in this post, if you need the dynamic methods you'd better go with BootStrap.groovy
BootStrap {
def calendarService
def init() {
calendarService.init()
}
}
The following works without any config in resources.groovy
class CalendarService {
#PostConstruct
private void init() {
User.findByEmail("foo#doo.com")
}
}
Related
I have a custom annotation:
#Target(AnnotationTarget.FUNCTION)
#Retention(AnnotationRetention.RUNTIME)
#MustBeDocumented
annotation class Listener
Used like this:
#Service
class MyService {
#Listener
fun onNewThing(thing: Thing) {
...
}
}
In another service, every time something happen, I want to call each function annotated with #Listener and with a parameter of type Thing.
How can I do it without looping through all the beans in the context and checking all the methods?
You can use the following:
Set<Method> methodsAnnotatedWith = new Reflections("com.example.spring.aop.api", new MethodAnnotationsScanner()).getMethodsAnnotatedWith(BusinessFunction.class);
you can use org.reflections of java :
Set<Method> allMethods = new Reflections().getMethodsAnnotatedWith(yourAnnotation.class);
for (Method m : allMethods) {
if (m.isAnnotationPresent(yourAnnotation.class)) {
//YOUR LOGIC
}
}
I'm trying to use kotlin in my java8 spring project.
I'm doing it by replacing classes (java->kotlin) one by one.
One of my class in Finder:
Finder.java has such structure:
#Compoment
class Finder {
private SomeObject someObject;
Finder() {
someObject = new SomeObject();
}
public void doSomething() { //aspect looks here
someObject.do();
}
}
I've replaced it by Finder.kt
#Compoment
open public class Finder {
private val someObject : SomeObject
constructor() {
someObject = SomeObject()
}
public fun doSomething() { //aspect looks here
someObject.do() //NPE here
}
}
While debuggind, I've found, that constuctor was called, someObject was created when Finder instance was creating. But FinderEnhancerBySpring generated class instance was autowired to Detector instance. It was not initiliazed, so i've got NPE when I try to access to someObject.
Also Finder class has other autowired fields (to simplify code I haven't wrote it here), they were not initiliazed also.
UPD: I've found the aspect on the one of Finder's method. When I deleted it, type the autowired instance became Finder (not FinderEnhancerBySpring) and fully initiliazed.
What can be wrong here?
(0.13.1514 - kotlin version)
All kotlin methods are final (speaking java) by default, so I've to allow overide it with open keyword:
public open fun doSomething() { //aspect looks here
someObject.do()
}
I have a situation in a Controller where I'm surrounding pieces of code in if(Environment.Current == Environment.PRODUCTION) blocks because the block of code is calling methodA in restService that makes a REST call to a URL that is only available when the app is deployed onto a specific production server. However doing so means that area of code is unreachable when running tests, which makes me a bit uncomfortable.
In the Development environment I'm not concerned with making the call to methodA as I'm stubbing out what the methodA would return and passing it on to the next Controller, so changing the if statement to if(Environment.Current != Environment.DEVELOPMENT) allows me to test the code better and not have to make calls to places I can't reach during dev.
Ideally though I would like to try and inject a Service into a Controller dependent on the grails environment; so I could have two Services like this:
class RestService {
def methodA() {
// go do a REST call
}
}
and
class FakeRestService() {
def methodA() {
// return some stubbed response
}
}
and in my Controller restService would be an instance of FakeRestService in DEVELOPMENT and TEST environments, and an instance of RestService in PRODUCTION
class SearchController {
def restService
def index() {
restService.methodA()
}
I'm a bit stumped on how I could achieve this in a 'Grailsy'/Spring way. I've been looking into creating some sort of Service Factory which would return an instance of either RestService or FakeRestService dependent on the environment, but it would be nice if I could define what Service to inject into restService in config or something similar.
Any advice would be great!
You can add an alias for the bean name in resources.groovy when environment is TEST.
import grails.util.Environment
beans = {
if ( Environment.current == Environment.TEST ) {
springConfig.addAlias 'restService', 'fakeRestService'
}
}
RuntimeSpringConfiguration is available in resources.groovy by getSpringConfig().
Here is a more Grails-y version of dmahapatro's answer:
import grails.util.Environment
beans = {
Environment.executeForCurrentEnvironment {
environments {
development {
springConfig.addAlias 'restService', 'fakeRestService'
}
}
}
}
I have code like this...
#Validateable
class RecipientsCommand {
...
EmailService emailService
void getEmailEligibleRecipients(Long accountId){
emailService.loadEligibleEmail(accountId)
}
}
resource.groovy
imports com.test.commands.RecipientsCommand
beans = {
recipientsCommand(RecipientsCommand){bean -> bean.autowire = true}
}
But the service is still always null when I call
new RecipientCommand()
Since the Command Object seems to be an interface between the views and the controller I am creating it, filling it and passing it to the view. Then I am using it to parse and save data. If I change to...
EmailService emailService = new EmailService()
Everything works fine.
The auto wiring only happens when Grails creates the instance for you. You can't just new RecipientCommand() and expect Spring to be involved in that. If you retrieve the recipientsCommand bean from the Spring application context it will be auto wired and if the RecipientCommand is created by the framework and passed as an argument to your controller action, that will also be auto wired. invoking the new RecipientCommand() constructor will result in a new instance being created which is not auto wired.
EDIT:
Examples...
class SomeController {
def someAction(RecipientCommand co) {
// co will already be auto wired
// this approach does NOT require you to have defined the
// recipientsCommand bean in resources.groovy
}
}
class SomeOtherController {
def someAction() {
// rc will be autowired
// this approach requires you to have defined the
// recipientsCommand bean in resources.groovy
def rc = grailsApplication.mainContext.getBean('recipientsCommand')
}
}
class AnotherSomeOtherController {
def recipientsCommand
def someAction() {
// recipientsCommand will be auto wired
// this approach requires you to have defined the
// recipientsCommand bean in resources.groovy
}
}
class YetAnotherController {
def someAction() {
// rc will not be autowired
def rc = new RecipientCommand()
}
}
I hope that helps.
From my controller I would like to dynamically select a service based on a parameter.
Currently I have a base service and some other services that extent this base service. Based on the parameter I call a class that does creates a bean name based on the param and eventually calls the following:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class Resolver {
def ctx
def getBean(String beanName) {
if(!ctx) {
ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
}
return ctx."${beanName}"
}
}
This returns the service I want. However I feel rather dirty doing it this way. Does anyone have a better way to handle getting a service (or any other bean) based on some parameter?
Thank you.
ctx."${beanName}" is added to the ApplicationContext metaclass so you can do stuff like def userService = ctx.userService. It's just a shortcut for ctx.getBean('userService') so you could change your code to
return ctx.getBean(beanName)
and it would be the same, but less magical.
Since you're calling this from a controller or a service, I'd skip the ServletContextHolder stuff and get the context by dependency-injecting the grailsApplication bean (def grailsApplication) and getting it via def ctx = grailsApplication.mainContext. Then pass it into this helper class (remember the big paradigm of Spring is dependency injection, not old-school dependency-pulling) and then it would be simply
class Resolver {
def getBean(ctx, String beanName) {
ctx.getBean(beanName)
}
}
But then it's so simple that I wouldn't bother with the helper class at all :)