Can I use a property placeholder with Spring EL? - spring

Before upgrading to Spring 3 I had this in my applicationContext.xml file:
<bean class="com.northgateis.pole.ws.PolePayloadValidatingInterceptor">
<property name="validateRequest" value="${validateRequest}" />
<property name="validateResponse" value="${validateResponse}" />
</bean>
where ${validateRequest) and ${validateRequest) refer to properties that may or may not be defined in my properties file.
In Spring 2, if these proeprties were not present in the properties file the setters on the bean were not called and so the defaults hard-coded in PolePayloadValidatingInterceptor were used.
After upgrading to Spring 3, it seems the behaviour is different: If the properties are not present in the properties file I get the following exception:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'annotationMapping' defined in class path resource [com/northgateis/pole/ws/applicationContext-ws.xml]: Could not resolve placeholder 'validateRequest'
at org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.processProperties(PropertyPlaceholderConfigurer.java:272)
at org.springframework.beans.factory.config.PropertyResourceConfigurer.postProcessBeanFactory(PropertyResourceConfigurer.java:75)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:640)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:615)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:405)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:272)
I tried dabbling with Spring EL but the following doesn't seem to work:
<bean class="com.northgateis.pole.ws.PolePayloadValidatingInterceptor">
<property name="validateRequest" value="${validateRequest?:true}" />
<property name="validateResponse" value="${validateResponse?:false}" />
</bean>
The value after the Elvis operator is always used, even when the properties are defined in the proeprties file. Interesting that the syntax is accepted.
Any suggestions?

It looks like Spring 3's handling of default values with the Elvis operator was rather broken. This has apparently been fixed (see SPR-7209) in the fresh-out-of-the-oven Spring 3.0.3, and the correct syntax should be the rather baroque:
#{${validateRequest}?:true}

There's no need for Spring EL for setting a default value for a missing property when resolving it with a placeholder configurer. Simply use ${validateRequest:true}. The "Elvis operator" is not concerned with resolving placeholders, it just relies on whatever input the placeholder configurer provides.
See SPR-4785.

Related

Init-method from properties

I would like to declare a bean for which init-method is not a constant value, but depends on a property:
<bean id="XXX" class="YYY" init-method="${some.property}"/>
I have a PropertyPlaceholderConfigurer bean already configured, but unfortunately spring tries to call method named ${some.property} instead of the property value.
What should I configure in order to spring call the method pointer by some.property value?
To do this, you'll need to include the following bean and put the path to the properties file in the location property:
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean" id="appConfig">
<property name="location" value="classpath:appConfig.properties"></property>
</bean>
Let's suppose your properties file contains the following entry:
init_method = test
Then, by using your own code snippet, you should refer to aforementioned property in this way:
<bean id="XXX" class="YYY" init-method="#{appConfig['init_method ']}"/>
The appConfig must match bean's id declared on the first snippet

using property-placeholder with beanfactory in spring

With below XML configuration
<context:property-placeholder location="constants.properties"/>
<bean id="MyDBDetails"
class="itsmine.springcore.MyDBDetails" scope="singleton">
<property name="fName" value="${fName}" />
<property name="lName" value="${lName}" />
<property name="age" value="${age}" />
</bean>
I created a bean in my main using below 2 options:
1) using ClassPathXmlApplicationContext
2) using bean factor
The dynamic values got set when bean created using ClassPathXmlApplicationContext, but not when created using bean factory.
Could you please suggest how to make it work using bean factory ?
Thanks in advance.
When using XML declaration for bean properties, the property-placeholder is registered as a Bean Factory Post Processor for the IoC container, thus you will have the properties values available.
However, when instantiating beans programatically through a BeanFactory, this factory won't be aware of the properties values unless your configure a `` as its post processor:
BeanFactory factory = /* your factory initialized */;
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("constants.properties"));
cfg.postProcessBeanFactory(factory);
EDIT
Note that the org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#setLocation accepts a org.springframework.core.io.Resource as its argument, i.e. you can use any of the its concrete sub-implementation depending on your needs:
org.springframework.core.io.FileSystemResource: An implementation supporting file handles.
org.springframework.core.io.ClassPathResource: An implementation for classpath resources.
org.springframework.core.io.InputStreamResource: An implementation for an InputStream...

Spring bean creation

Is it possible to create to bean with same id with same class with different property in spring ? Like:
<bean id ="a" class= "com.tofek.A"
<property message = "khan"/>
</bean>
<bean id = "a" class = "com.tofek.A"
<property message="tofek"/>
</bean>
As per my understanding it will create, but while fetching the bean using getBean() method it will give exception like NoBeanDefinitionFoundException.
Please correct my understanding if I'm wrong?
Make sure your spring context is loaded sucessfully.
Answering your question. You can have two identical bean definitions in two different sprintContext configurations.
The bean from second context will override bean created by first one.
For example :
context1.xml
<bean id="bean1" class="org.springframework.beans.TestBean"/>
context2.xml
<bean id="bean1" class="org.springframework.beans.TestBean"/>
then, the bean from context2.xml will override bean created by contex1.xml.
It of course depends on order of creating spring contexts. The laters overrides the ones made before.
You can use getBean() to fetch bean by type or name. In this case, both bean have same id's and types, the spring wouldn't know which one you want to fetch.

c3p0 useScatteredAquireTask Spring Bean

Hello I wan't to know how can I set up a bean so that it sets the ScatteredAquireTask to "True".
I've been trying:
<bean id="c3p0Props" class="com.mchange.v2.resourcepool.BasicResourcePool.ScatteredAcquireTask" >
<property name="USE_SCATTTERED_ACQUIRE_TASK" value="true" />
</bean>
I also tried ...resourcepool.experimental.useScatteredAcquireTask... didn't worked. I'm not sure how can I set this on spring. I'm using 0.9.1.2, can't go to 0.9.2.prep1 at the moment. Thanks.
That's because USE_SCATTTERED_ACQUIRE_TASK isn't a property of the ScatteredAcquireTask class (i.e. there's no method called setUSE_SCATTTERED_ACQUIRE_TASK), it's an internal static field of the class that's not accessible to Spring.
You're not going to be able to set that values in a Spring bean defintion, you need to find out how to influence that value by some other means.

Property Placeholder for Imports/Bean Refs

Can I use a property loaded from property-placeholder to make a context import dynamic?
<context:property-placeholder location="classpath*:/enterprise.properties"/>
<import resource="classpath*:/Fsb${jdbc.ctxType?:Jdbc}-context.xml"/>
Properties File
jdbc.ctxType=JTA
So this way I could change the type of context file that is loaded based on a property.
Also, can I do the same thing to make a bean ref name dynamic?
<bean id="personBusinessService" class="com.foo.PersonBusinessServiceImpl"
p:personUidDataService-ref="personUidDataService${personUidDataService.sib?:Api}"
p:identifierLookupSearchService-ref="identifierLookupSearchService${identifierLookupSearchService.sib?:Api}"
p:contactPointBusinessService-ref="contactPointBusinessService${contactPointBusinessService.sib?:Api}"
/>
Properties File
personUidDataService.sib=Stub
Jay
--------------------Update example of property for ref-------------------------
I created a property file with the following entry:
addressLookupSearchService.sib=DaoMock
Then I have the following configuration in a Spring Context File:
<context:property-placeholder location="classpath*:/simple.properties"/>
<!-- EntityManager will be injected into DAO by JPA annotations -->
<bean id="addressSearchDao" class="com.foo.AddressSearchDaoImpl"/>
<bean id="addressSearchDaoMock" class="com.foo.MockAddressSearchDaoImpl"/>
<bean id="addressLookupSearchService" class="com.foo.AddressLookupSearchServiceImpl"
p:baseDao-ref="addressSearch${addressLookupSearchService.sib?:Dao}"/>
And addressSearch${addressLookupSearchService.sib?:Dao} doesn't work, it always defaults to
the bean id of addressSearchDao even if my property says it should set to addressSearchDaoMock.
Any thoughts as to what I am doing wrong?
This is a similar question to this one.
Imports are resolved before bean (property-placeholder) creation, so you can not use the property file to define properties which you want to use in an import statement. In this case you have to set the property as system property (-Djdbc.ctxType=JTA) (have a look at the link - paragraph Note).
But using the property file properties in bean definitions works fine - that's what they are for :-)
Update: Since Spring 3.1 the Unified Property Management allows to use properties even in imports (thanks #Jay Blanton for mentioning this in the comments).
Yes, you can. You can use expressions in imports and injections.

Resources