6

When my Grails app starts up, I also begin a Spring Integration and Batch process in the background. I want to have some DB connection properties stored in the Config.groovy file, but how do I access them from a Java class used in teh Integration/Batch process?

I found this thread:

Converting Java -> Grails ... How do I load these properties?

Which suggests using:

private Map config = ConfigurationHolder.getFlatConfig();

followed by something like:

String driver = (String) config.get("jdbc.driver");

This actually works fine (teh properties are loaded correctly from Config.groovy) but the problem is that ConfigurationHolder is after being deprecated. And any thread I've found dealing with the issue seems to be Grails-specific and suggest using dependancy injection, like in this thread:

How to access Grails configuration in Grails 2.0?

So is there a non-deprecated way to get access to the Config.groovy properties from a Java class file?

Community
  • 1
  • 1
Illu
  • 65
  • 1
  • 6
  • What's wrong with the second method in the [accepted answer of the question you linked to](http://stackoverflow.com/a/7136095/6509)? – tim_yates Oct 31 '12 at 12:30
  • Hi Tim, cheers for replying. I put in my java class as a bean in the resources file (with a property of grailsApplication and a ref of grailsApplication), and added the following line to my class: private GrailsApplication grailsApplication; with getter and setter. But when I try to access it via ConfigObject config = grailsApplication.getConfig(); it seems to be null and errors out. Any ideas what I'm doing wrong? Thanks – Illu Oct 31 '12 at 12:53
  • Where are you trying to access it? You can't use dependency-injected beans in the constructor, for example, you need to declare a method annotated with `@PostConstruct` and put the logic that needs the `grailsApplication` in there instead, or alternatively use constructor argument injection rather than setter injection. – Ian Roberts Oct 31 '12 at 12:58
  • Hi Ian, I'm not trying to access it in the constructor, just in a seperate method called connect, which is called by one of the Spring Integration components. The file config file contains the db details/creds that I need. So the line that I posted above is used in there. – Illu Oct 31 '12 at 13:04
  • And do the spring integration components fetch their instance of your class from the Spring context or do they construct their own instance? Dependency injection will only work in the former case. – Ian Roberts Oct 31 '12 at 13:43
  • My class which usese the config was in the spring xml file already as a bean (actually in a seperate integration one which is imported into the resources file), it just didn't have a property of grailsApplication. When I added in the ref part is highlighted and it says Referenced bean grailsApplication not found. – Illu Oct 31 '12 at 13:48
  • The `grailsApplication` bean is declared by the parent context so it's fair enough that it can't be found. I've suggested an alternative approach in an answer below. – Ian Roberts Oct 31 '12 at 16:52

3 Answers3

5

Just to register, in Grails 2.x, there's a Holders class that replaces this deprecated holder. You can use this to access grailsApplication in a static context.

  • This appears to replace Burt's [ApplicationContextHolder](http://burtbeckwith.com/blog/?p=1017) since it offers most from that solution, also address static assignment issue. – raffian May 25 '14 at 17:59
4

Just checked in some of my existing code, and I use this method described by Burt Beckwith

Create a new file: src/groovy/ctx/ApplicationContextHolder.groovy

package ctx

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()
  }
}

Then, edit grails-app/config/spring/resources.groovy to include:

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

Then, in your files inside src/java or src/groovy, you can call:

GrailsApplication app = ApplicationContextHolder.getGrailsApplication() ;
ConfigObject config = app.getConfig() ;
tim_yates
  • 167,322
  • 27
  • 342
  • 338
1

I can't work out why this is not working, but I can suggest an alternative approach entirely. Grails sets up a PropertyPlaceholderConfigurer that takes its values from the grailsApplication.config, so you could declare a

public void setDriver(String driver) { ... }

on your class and then say

<bean class="com.example.MyClass" id="exampleBean">
  <property name="driver" value="${jdbc.driver}" />
</bean>

This also works in resources.groovy if you're using the beans DSL, but you must remember to use single quotes rather than double:

exampleBean(MyClass) {
  driver = '${jdbc.driver}'
}

Using "${jdbc.driver}" doesn't work because that gets interpreted by Groovy as a GString and (fails to be) resolved when resources.groovy is processed, whereas what you need is to put a literal ${...} expression in as the property value to be resolved later by the placeholder configurer.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183