Accessing the GrailsApplication and ApplicationContext from domain classes without holders

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
      ...
   }
}

9 Responses to “Accessing the GrailsApplication and ApplicationContext from domain classes without holders”

  1. Dimitris Zavaliadis says:

    Thanks Burt for your nice post, this has been biting me for some time now. However, I’m still not sure how would you go about the following problem:

    I have a UrlMappingsUtils class under /src/groovy which has to use the configuration or the ApplicationContext within a static method. For example, imagine something along the lines of the following:

    import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH

    class UrlMappingsUtils {

    static def backofficeUrlPrefix() {
    return CH.config.backofficeUrlPrefix
    }

    }

    Then, this static method is called within the standard UrlMappings.groovy, for example:

    class UrlMappings {
    static mappings = {

    “/${UrlMappingsUtils.backofficeUrlPrefix()}/catalog/$action?/$id?”(controller: “catalog”)

    }
    }

    This works fine with the ConfigurationHolder, but so far I haven’t been able to change it so that it’s Grails 2.0 “compatible” (i.e. get rid of the deprecated ConfigurationHolder).

    I’ve tried everything to no avail (and, for the life of me, I can’t figure out how to get a reference to the grailApplication in UrlMappings so that e.g. I can pass it to to UrlMappingsUtils as you suggest). Any ideas?

    Many thanks,
    Dimitris Zavaliadis

    • Burt says:

      Dimitris – one simple but rather weird approach would be to create an instance of an arbitrary domain class and get the config from there (“def config = new Book().domainClass.grailsApplication.config”). A better approach that’s a little more work would be to create your own holder class; I described that here: http://burtbeckwith.com/blog/?p=1017

      • miles zarathustra says:

        I’m having the same issue with the inability to create a static bean.

        I appreciate your providing an example of the “create your own holder” approach, but it is a very un-groovy mess of boilerplate.

        I wish there were a better solution that would work in a static context.

        Thanks,
        -= miles =-

  2. Stephane says:

    Thanks Burt for this post.
    I have a question about getDomainClass method on Domain object : is it available in unit test ? I’m trying to use it with grails-2.0.0.rc1.

    Thanks again !

  3. Thomas says:

    I would need access to the config in the

    static mapping = {}

    section to configure ID generation. At that time during startup, the approach described does not work because domainClass/getDomainClass is not yet available.

  4. Fletch says:

    Exactly what I needed – non-deprecated grailsApplication access from a static context in a domain class. Thankyou!

  5. Sargis says:

    Hi what about: Holders.grailsApplication can we use it as I know its not deprecated

  6. Lance Lavandowska says:

    I’m using this approach but my unit test throws an exception “No such property: domainClass for class: RoleComponent”
    on
    new RoleComponent().domainClass.grailsApplication

    I’m using 2.2.2 and have my class in these annotations
    @TestFor(RoleComponent)
    @Mock([Role, RoleComponent])

    Do I need to manually mock the getDomainClass().getGrailsApplication() methods?

    Thanks for all you do Burt.

  7. Ramson says:

    In grails version 2.1.0, when I tried

    new Book().domainClass.grailsApplication

    I got “No such property: domainClass for class Book” Error.

    The ‘Holders’ recommendation found here works well though.

    http://grails.1312388.n4.nabble.com/domainClass-property-won-t-available-in-Unit-td4647827.html

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