Injecting Grails Config Properties Into Services

One of the things I really like about looking at other engineer's code is that I pick up tips and tricks that I might never have thought of doing before. This only improves my own skillset. Recently, I started doing a small bit of work for a new client with an established Grails application. The team is made up of some really good engineers so I've been scraping the code base for goodies that I can add to my own toolbox.

One such goodie I discovered was injecting config properties into services. First, I'll show how I have been doing this up to this point, which is perfectly valid, by the way.

Let's say we have a service class that is going to do some work on a file. For this, we need to store some paths for the working directories.

stamping.file.path="/some/path/to/files/dir"  
stamping.file.work.path="/some/path/to/work/dir"  

To use the above properties in a service class, you might be familiar with the following approach:

class StampingService {

    def grailsApplication

    def stamp(File file) {
        def filePath = grailsApplication.config.stamping.file.path
        def workPath = grailsApplication.config.stamping.file.work.path
        // TODO: do some work on the file
    }
}

There is really nothing wrong with this approach and this is how most (if not all) grails documentation and books will tell you do this. Now, I'll change the technique so that the config properties are injected into the service. First, I'll modify the service class:

class StampingService {

    def filePath
    def workPath

    def stamp(File file) {
        // TODO: do some work on the file
    }
}

Config.properties doesn't need to change at all. We do need to add a new class:

class BeanConfigUtils {

  static void configure(ConfigObject config, ApplicationContext ctx) {
    ctx.stampingService.with {
      filePath = config.stamping.file.path
      workPath = config.stamping.file.work
    }
  }
}

This class simply injects the property values into the appropriate StampingService variables and you can name it whatever you want. To kick off the configure method, just add the following to Bootstrap.groovy:

def grailsApplication  
def init = { servletContext ->  
    BeanConfigUtils.configure grailsApplication.config, grailsApplication.mainContext
}

This may not seem that valuable of a technique, but consider the following; environment specific constants. Often times I've needed to define constant variables of some sort but didn't know what the best option was if these needed to be environment specific. Now, I have a solution for that.

class CookieService {  
    def userCookie
    def recentProjectCookie
    def preferredEmailCookie

    ...
}
environments {  
    development {
        cookies {
            userCookie = "UserDEV"
            recentProjectCookie = "RecentProjectDEV"
            preferredEmailCookie = "PreferredEmailDEV"
        }
    }
    staging {
        cookies {
            userCookie = "UserSTAG"
            recentProjectCookie = "RecentProjectSTAG"
            preferredEmailCookie = "PreferredEmailSTAG"
        }
    }
}
class BeanConfigUtils {

  static void configure(ConfigObject config, ApplicationContext ctx) {

    ctx.stampingService.with {
      filePath = config.stamping.file.path
      workPath = config.stamping.file.work
    }

    ctx.cookieService.with {
        userCookie = config.cookies.userCookie
        recentProjectCookie = config.cookies.recentProjectCookie
        preferredEmailCookie = config.cookies.preferredEmailCookie
    }
  }
}

What I'm still trying to determine is if this helps, in any way, with testing config properties. Nonetheless, I like this approach and can't determine a downside to it. If anyone knows of a reason not to do this, I'd be interested in hearing your opinion.