13

I am trying to write a ValidatorFactory which will give me a validator based on its type

public Validator getNewValidator(ValidatorType type){

    switch:
         case a : new Validator1();
         break;
          case b : new Validator2();
        break;

}

I want to write using spring xml beans definition

I can use method injection but it will let me create only one object and the method does

not take any arguments.

I don't want to use FactoryBean.. I am just looking whether we can do this using spring xml

bean definition.

skaffman
  • 398,947
  • 96
  • 818
  • 769
Shekhar
  • 5,771
  • 10
  • 42
  • 48

5 Answers5

22

you can do conditional bean injection with plain xml. The "ref" attribute can be triggered by property values from a property file and thus create conditional beans depending on property values. This feature is not documented but it works perfect.

<bean id="validatorFactory" class="ValidatorFactory">
<property name="validator" ref="${validatorType}" />
</bean>

<bean id="validatorTypeOne" class="Validator1" lazy-init="true" />
<bean id="validatorTypeTwo" class="Validator2" lazy-init="true" />

And the content of the property file would be:

validatorType=validatorTypeOne

To use the property file in your xml just add this context to the top of your spring config

<context:property-placeholder location="classpath:app.properties" />
guido
  • 687
  • 4
  • 13
  • Just need a little more explanation on how could I do validatorType=validatorTypeOne in XML code? – huahsin68 Jun 22 '12 at 06:36
  • 1
    validatorType=validatorTypeOne is the content in a property file and the syntax ${validatorType} gets expanded to the value of the property which is in this case: validatorTypeOne. As this points to a bean reference id an instance of the class Validator1 gets created and assigned to the property in ValidatorFactory. Got it? – guido Jun 25 '12 at 08:53
  • No, I am a bit confuse on the statement validatorType=validatorTypeOne. What if I need it to be validatorTypeTwo? And also I got syntax error on ref="${validatorType}". I need some reference on this ref thing so that I can understand it clearly. – huahsin68 Jun 25 '12 at 11:00
  • Just be wary of trying this with any beans that use SmartLifecycle. See [this thread](http://stackoverflow.com/questions/4412628/spring-3-0-lazy-init-not-honoured-for-defaultmessagelistenercontainer) for details. – pards Jul 16 '13 at 15:20
3

For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.

jplandrain
  • 2,278
  • 4
  • 24
  • 24
2

If you are using annotation (@Autowired, @Qualifier etc) instead of xml, you are not able to make conditional beans work (at least at current version 3). This is due to @Qualifier does not support expression

@Qualifier(value="${validatorType}")

More information is at https://stackoverflow.com/a/7813228/418439

Community
  • 1
  • 1
Lee Chee Kiam
  • 11,450
  • 10
  • 65
  • 87
1

I had an slightly different requirements. In my case I wanted to have encoded password in production but plain text in development. Also, I didn't have access to parent bean parentEncoder. This is how I managed to achieve that:

<bean id="plainTextPassword" class="org.springframework.security.authentication.encoding.PlaintextPasswordEncoder"/>
<bean id="shaPassword" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
    <constructor-arg type="int" value="256"/>
</bean> 

<bean id="parentEncoder" class="org.springframework.aop.framework.ProxyFactoryBean"> 
  <property name="targetSource"> 
    <bean class="org.springframework.aop.target.HotSwappableTargetSource"> 
      <constructor-arg ref="${password.encoding}Password"/> 
    </bean> 
  </property> 
</bean>

Of course, I defined password.encoding in a property file with possible values as sha or plainText.

SHOJAEI BAGHINI
  • 123
  • 1
  • 5
0

You should be able to do this:

<bean id="myValidator" factory-bean="validatorFactory" factory-method="getNewValidator" scope="prototype">
    <constructor-arg><ref bean="validatorType"/></constructor-arg>
</bean>

<bean id="validatorType" ... />

Of course, it uses an automatically configured FactoryBean underneath but you avoid any Spring dependency in your code.

gpeche
  • 21,974
  • 5
  • 38
  • 51