tags:

views:

132

answers:

3

Hi,

Is it possible from Spring to inject the result of calling a method on a ref bean?

I'm trying to refactor some cut/pasted code from two separate projects into a common class. In one of the projects, the code lives in a class I'll call "MyClient" that is being instantiated from Spring. It is injected with another spring-instantiated class "MyRegistry", then the MyClient class uses that class to look up an endpoint. All I really need is the endpoint String in my refactored class, which can be initialized via a Setter. I really cannot have a dependency on MyRegistry from MyClient in the refactored code.

So, my question is this... is there a way I can inject the endpoint String from spring that was looked up in the MyRegistry class. So, I currently have:

<bean id="registryService" class="foo.MyRegistry">
...properties set etc...
</bean>

<bean id="MyClient" class="foo.MyClient">
    <property name="registry" ref="registryService"/>
</bean>

But I'd like to have (and I know this is imaginary Spring syntax)

<bean id="MyClient" class="foo.MyClient">
    <property name="endPoint" value="registryService.getEndPoint('bar')"/>
</bean>

where MyRegistry will have a method getEndPoint(Stirng endPointName)

Hope that makes sense from a the standpoint of what I'm trying to achieve. Please let me know if something like this is possible in Spring!

+6  A: 

It's possible in Spring 3.0 via Spring Expression Language:

<bean id="registryService" class="foo.MyRegistry">
...properties set etc...
</bean>

<bean id="MyClient" class="foo.MyClient">
  <property name="endPoint" value="#{registryService.getEndPoint('bar')}"/>
</bean>
ChssPly76
@ChssPly76 Welcome, you are back
Arthur Ronald F D Garcia
A: 

Or in Spring 2.x, by using a BeanPostProcessor

Typically, bean post processors are used for checking the validity of bean properties or altering bean properties (what you want to) according to particular criteria.

public class MyClientBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext;
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if((bean instanceof MyClient)) && (beanName.equals("MyClient"))) {
            Myregistry registryService = (Myregistry) applicationContext.getBean("registryService");

           ((MyClient) bean).setEndPoint(registryService.getEndPoint("bar"));
        }

        return bean;
    }
}

And register your BeanPostProcessor

<bean class="br.com.somthing.MyClientBeanPostProcessor"/>
Arthur Ronald F D Garcia
+3  A: 

The nicest solution is to use Spring 3's expression language as described by @ChssPly76, but if you're using an older version of Spring, it's almost as easy:

<bean id="MyClient" class="foo.MyClient">
   <property name="endPoint">
      <bean factory-bean="registryService" factory-method="getEndPoint">
         <constructor-arg value="bar"/>
      </bean>
   </property>
</bean>
skaffman
Very cool - and a little devious. We are using Spring 2.5.6 here so I will try to use this technique. I see what you're doing now... you treat the getEndPoint() method as a factory method on registryService - the "factory-constructed" class being a simple String representing the endPoint. Very cool! I hope this works!
Alex Worden
"Devious" indeed, how dare you :) This is exactly how `factory-bean` and `factory-method` are supposed to be used, I'll have you know :)
skaffman