Create your own Grails holder class

I mentioned in an earlier post that using Grails *Holder classes should be avoided, and showed how to access the GrailsApplication, ApplicationContext, etc. from domain classes. But there are still cases where you need access to these objects and dependency injection and the approach I described aren’t sufficient. When all else fails you can always create your own holder class.

The reason this works in your application but not in Grails is that the static fields in your application are only accessed within your application. By using shared jars, multiple applications share static state held by shared classes, but this isn’t a problem for your code.

Since everything is reachable from the ApplicationContext and it’s easy to access, we’ll create a holder for that and expose the other objects from there.

Create a class called ApplicationContextHolder that implements ApplicationContextAware:

package com.yourcompany.yourapp

import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware

@Singleton
class ApplicationContextHolder implements ApplicationContextAware {

   private ApplicationContext ctx

   void setApplicationContext(ApplicationContext applicationContext) {
       ctx = applicationContext
   }

   static ApplicationContext getApplicationContext() {
      getInstance().ctx
   }
}

and register it in resources.groovy so the ApplicationContext is injected (using the factoryMethod attribute since the class is a singleton):

import com.yourcompany.yourapp.ApplicationContextHolder

beans = {
   applicationContextHolder(ApplicationContextHolder) { bean ->
      bean.factoryMethod = 'getInstance'
   }
}

Now you can use the ApplicationContext from anywhere to access Spring beans. We can go further though, adding utility methods to expose other classes held by holders:

static Object getBean(String name) {
   getApplicationContext().getBean(name)
}

static GrailsApplication getGrailsApplication() {
   getBean('grailsApplication')
}

static ConfigObject getConfig() {
   getGrailsApplication().config
}

static ServletContext getServletContext() {
   getBean('servletContext')
}

static GrailsPluginManager getPluginManager() {
   getBean('pluginManager')
}

You can also add the ability to register mock beans for unit tests; here’s the complete class:

package com.yourcompany.yourapp

import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import javax.servlet.ServletContext

import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware

@Singleton
class ApplicationContextHolder implements ApplicationContextAware {

   private ApplicationContext ctx

   private static final Map<String, Object> TEST_BEANS = [:]

   void setApplicationContext(ApplicationContext applicationContext) {
       ctx = applicationContext
   }

   static ApplicationContext getApplicationContext() {
      getInstance().ctx
   }

   static Object getBean(String name) {
      TEST_BEANS[name] ?: getApplicationContext().getBean(name)
   }

   static GrailsApplication getGrailsApplication() {
      getBean('grailsApplication')
   }

   static ConfigObject getConfig() {
      getGrailsApplication().config
   }

   static ServletContext getServletContext() {
      getBean('servletContext')
   }

   static GrailsPluginManager getPluginManager() {
      getBean('pluginManager')
   }

   // For testing
   static void registerTestBean(String name, bean) {
      TEST_BEANS[name] = bean
   }

   // For testing
   static void unregisterTestBeans() {
      TEST_BEANS.clear()
   }
}

Note that the servletContext and pluginManager beans are available in a running application but not the Grails console.

11 Responses to “Create your own Grails holder class”

  1. Nick Vaidyanathan says:

    An earlier comment on a post contextualized this by giving a specific use case: accessing a static string for URL mapping. While it is probably unreasonable to ask for an exhaustive set of use cases, posts like this may be improved by early consideration and guidance on “when would I use this?”

  2. Trygve Amundsen says:

    Why not let grails create-app create the ApplicationContextHolder?

  3. Amad says:

    Burt,

    I tried creating ApplicationContextHolder.groovy under src/groovy, but the method setApplicationContext is never called. Its declared in resources.groovy. I am using 2.0.0.RC1, any thoughts what could be going wrong here?

    Thanks

    • Amad says:

      Correction – It does get set, however I am trying to read configurations in one my job triggers to establish repeat interval, and at that point, there is no grailsApplication, hence NULL config. It use to work fine, but now ConfigurationHolder gone, what is the suggested way to handle this use-case?

      • Ben says:

        I have the same question. I have a quartz job and need to store the cron expression in my config file. I am trying to set it like this:

        static triggers = {
        cron name: ‘cronTrigger’, startDelay: 0, cronExpression: ACH.config.batch.cron.expression.validateDelegates
        }

        I get this error:
        Cannot invoke method getBean() on null object

        In my ApplicationContextHolder, getApplicationContext() is returning null. Anyone have a suggestion?

  4. murray says:

    Can you use this in the _Events.groovy file? I am having problems getting the configuration.

  5. murray says:

    Asked the grails user mailing list. config is accessible without needing any of the wiring above.

  6. Fabrizio says:

    Hi Burt, thanks for this post.

    I tried to use your solution but I’m getting the following error:
    “Cannot invoke method getBean() on null object”.
    The error is triggered because the private variable “private ApplicationContext ctx” is null. I can’t understand when and how to set that up for the instance?

    • Chris M says:

      I get exactly the same.

      • Chris M says:

        What happens is that setApplicationContext is called long after getApplicationContext() is called from the DataSource.groovy class. It’s to get a database name out of message.properties, but that’s not important. So how can one get the setter to be called first? And won’t having the connection to the database ready so late – if it has to wait for the setApplicationContext – cause problems?

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.