Reputation: 187549
I know that I can replace a Spring bean provided by Grails simply by defining my own bean with the same name. For example, if I want to replace the messageSource
bean provided by Grails
class MyMessageSource implements MessageSource {
// methods omitted
}
Then add the following in resources.groovy
messageSource(MyMessageSource)
However, assume that I want MyMessageSource
to decorate the implementation of this bean provided by Grails
class MyMessageSource implements MessageSource {
// this field should be set to the MessageSource impl provided by Grails
MessageSource messageSource
}
I can't figure out how to wire this up in resources.groovy
. Obviously I can't do this:
messageSource(MyMessageSource) {
messageSource = ref('messageSource')
}
Because it looks like I'm defining a bean that depends on itself. I could of course give my bean a different name, e.g.
myMessageSource(MyMessageSource) {
messageSource = ref('messageSource')
}
But then any class beyond my control (e.g. a plugin class) that declares a dependency on messageSource
will be set to the bean provided by Grails rather than my decorator.
Upvotes: 4
Views: 984
Reputation: 27245
In an application (not a plugin), something along these lines should work...
The new message source:
// src/groovy/com/demo/MyMessageSource.groovy
package com.demo
import org.springframework.context.MessageSource
import org.springframework.context.MessageSourceResolvable
import org.springframework.context.NoSuchMessageException
class MyMessageSource implements MessageSource {
MessageSource theRealMessageSource
String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
theRealMessageSource.getMessage code, args, defaultMessage, locale
}
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException {
theRealMessageSource.getMessage code, args, locale
}
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
theRealMessageSource.getMessage resolvable, locale
}
}
A post processor:
// src/groovy/com/demo/MyPostProcessor.groovy
package com.demo
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.BeansException
class MyPostProcessor implements BeanFactoryPostProcessor {
@Override
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// error handling ommitted for brevity here...
def realMessageSource = beanFactory.getBean('messageSource')
def newMessageSource = new MyMessageSource()
newMessageSource.theRealMessageSource = realMessageSource
beanFactory.removeBeanDefinition 'messageSource'
beanFactory.registerSingleton 'messageSource', newMessageSource
}
}
Register the post processor:
// grails-app/conf/spring/resources.groovy
beans = {
myMessageSourcePostProcessor com.demo.MyPostProcessor
}
Upvotes: 7
Reputation: 27245
After the context is initialized you can retrieve the messageSource bean, create an instance of your bean that delegates to the messageSource bean and then register your bean with the context under the name "messageSource" so when DI happens, your bean is the bean that will be used. In a plugin you should be able to do this in doWithApplicationContext (not doWithSpring).
Upvotes: 1