8

I thought the Spring annotations were supposed to work out of the box in a Grails environment, but I cannot get it to work at all. I also tried the afterProperties method, which did not work either.

Can anyone spot a mistake? Is there some configuration I need to do?

package dashboard

import javax.annotation.PostConstruct

class EmailJobSchedulerService
{
    def grailsApplication

    @PostConstruct
    def init() {
        def cronExpression = grailsApplication.config.emailAt8AmTrigger
        println(cronExpression)
        EmailSubscribersJob.schedule(cronExpression, new HashMap())
    }
}
willcodejavaforfood
  • 43,223
  • 17
  • 81
  • 111
  • That annotation put in place a lot of constraints (see http://docs.oracle.com/javase/7/docs/api/javax/annotation/PostConstruct.html). Do they all apply? – lucke84 Feb 12 '13 at 13:03
  • @lucke84 After changing it to void as per Ian's suggestion I should comply with all the constraints – willcodejavaforfood Feb 12 '13 at 13:09
  • 4
    When do you expect the cronExpression to be printed? On server start? I believe this is called when the first call to any of the service's methods is made and not on server startup. I suggest calling a dummy method in bootstrap just to confirm. – uchamp Feb 12 '13 at 14:14
  • @uchamp I expect it to be called when Spring is finished configuring my beans – willcodejavaforfood Feb 12 '13 at 14:25

2 Answers2

17

Try changing it to

@PostConstruct
void init() {

(i.e. void instead of def). I'm not sure whether Spring specifically enforces this but the specification of @PostConstruct states that among other things "The return type of the method MUST be void".

Edit: uchamp's comment is correct, I just tried the same test and indeed the @PostConstruct annotated method is called only the first time the service bean is used and, not necessarily immediately at startup. You can add

static lazyInit = false

to the service class to force it to be initialized eagerly at startup. This doesn't appear to be documented in the user guide, I deduced it by reading the code.

Note that "used" in the previous paragraph doesn't necessarily mean you have to call a method on it. The service bean will be initialized the first time it is fetched from the application context, either directly or because it has been autowired into another bean that is being initialized. For example, injecting the service into BootStrap using

def emailJobSchedulerService

would be enough to fire the @PostConstruct method, you don't have to actually call any of the service's methods from the BootStrap.init closure. Similarly, if your service were injected into any controllers then the init would fire the first time one of those controllers handled a request (any request, it doesn't have to be an action that calls the service).

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Still nothing. Appreciate the effort though :) – willcodejavaforfood Feb 12 '13 at 12:45
  • 2
    @willcodejavaforfood assuming the `.groovy` file in question is in `grails-app/services` and not `src/groovy` then it _should_ just work. I've used the same trick many times. One thing to note though is that GORM is probably not available at `@PostConstruct` time. If you need to do anything with GORM methods you'll likely have to define a normal non-annotated method and call it from BootStrap. – Ian Roberts Feb 12 '13 at 12:58
  • This is odd. Even created a brand new project only using the command line and @PostConstruct was not called there either. I don't need to use GORM for this, just schedule my job which is not persisted. – willcodejavaforfood Feb 12 '13 at 14:03
  • @willcodejavaforfood after a bit more digging it looks like `static lazyInit = false` is what you're looking for. – Ian Roberts Feb 12 '13 at 14:32
  • That's neat! Didn't know about this option. – uchamp Feb 12 '13 at 14:40
2

Just adding on the answer from @Ian - For some reason i had:

@PostConstruct
private void init() {

This also failed silently and gave strange behavior. Solution was to remove "private":

@PostConstruct
void init() {
Svante
  • 1,069
  • 3
  • 12
  • 28