Archive for November 12th, 2011

Accessing the GrailsApplication and ApplicationContext from domain classes without holders

Saturday, November 12th, 2011

The various holder classes in Grails (ApplicationHolder, ConfigurationHolder, etc.) are now deprecated and the plan was to remove them at some point since static variables cause problems. One example is deploying multiple Grails applications with the --nojars option, using jar files in the server’s shared classpath. If a class with a static field is loaded by the shared classloader, its value is shared by all callers. Kaboom.

We’re working on a fix but it doesn’t look like it’ll be ready for 2.0 final, so it’s still best to avoid their use. In practice this isn’t really that much of a problem since you can use dependency injection to inject the GrailsApplication into any artifact (controllers, services, Quartz jobs, etc.) with def grailsApplication. From there you can get the configuration (grailsApplication.config) and the ApplicationContext (grailsApplication.mainContext). From there you can get any Spring bean, including the ServletContext (registered as the "servletContext" bean).

Dependency injection isn’t an option for regular classes in src/groovy or src/java, but they don’t exist in isolation. They have to be called from somewhere, and that’s most likely going to be an artifact that can use dependency injection. So instead of auto-injecting into your Groovy class, just pass the application, config, or context (or specific beans) to the class when you call it.

I described a way to add a getGrailsApplication method (both static and instance) to the MetaClass of your domain classes in an answer to this StackOverflow question, and it’s still a good option. One caveat – adding a getFoo instance method allows you to call it like it’s a property (thing.foo) but that doesn’t work with static methods. You have to use the getter syntax: Thing.getFoo().

But it turns out this is all possible in 2.0 without changes. There’s a new getDomainClass instance method in domain classes (it returns the GrailsDomainClass artifact API class), and from there you can access the GrailsApplication with its getGrailsApplication method. So if you need access to the configuration, GrailsApplication, or ApplicationContext from a static method, you can reach everything from a new instance of your domain class:

class Book {
   ...
   static someMethod() {
      def grailsApplication = new Book().domainClass.grailsApplication
      def ctx = grailsApplication.mainContext
      def config = grailsApplication.config
      def fooService = ctx.fooService
      ...
   }
}

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