How to use property file in util:properties? - java

I must use spring util:properties, however, I need something like this:
if propertyFile x exists, use x, otherwise, use y.
Can you please advise how I can obtain this?

May be this is half solution! Spring can load the wildcard resources. Please see spring <util:properties /> with wildcards
In this way you can name your files like: x-config.properties and y-config.properties:
<bean id = "config"
class = "org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name = "locations"
value = "classpath*:somefolder/*-config.properties" />
</bean>
If both x and y exist both of them are loaded.

Actually, there is an option ignoreResourceNotFound, but it isn't available for namespace component. You have to use PropertiesFactoryBean directly:
<bean id="props" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations" value="y.properties, x.properties"/>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
If your x.properties doesn't exist, it will be ignored and the properties from y.properties will remain.
If x.properties exists and it contains the same keys as y.properties, they override those from y.properties, because all locations are loaded one by one respectively.

Related

Spring 3.5 Setting an xml property, handling the default value using PropertyPlaceholderConfigurer

I'm working with an old project using Spring 3.5 and xml config.
In the application context I am setting a property to an externally configured xml file value so something like this -
<bean id="myService" class="com.mypath.MyService">
<property name="myProperty" value="${myValue}:myDefaultValue" />
</bean>
This all works properly.
In some tests though there is a test-context.xml coming into play which sets the values of the properties like this
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<util:properties>
<prop key="myProperty">myValue</prop>
</util:properties>
</property>
</bean>
This is failing to 'understand' the default value. If I leave the value blank I get :myDefaultValue returned. If I set myValue like my example shows I get myValue:myDefaultValue.
I had a quick peak at the PropertyPlaceholderConfigurer and it looks very basic without many options. I've not used it before. Does anyone know if there is a simple way for me to handle the defaults ? Or maybe I have to use a different method to set the test context values ?
You have your syntax slightly off. The default value for the expression goes inside the braces, like so: ${myValue:defaultValue}.

Spring - PropertyOverrideConfigurer multiple configuration lines for ONE bean property

I have a spring xml file with some beans, two of which I have pasted below:
<bean
class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="locations">
<value>classpath:projectname-override.properties</value>
</property>
</bean>
<bean id="myBeanName"
class="my.company.department.svc.spring.WmSvcJndiDataSource">
<property name="jndiName">
<value>jdbc/XXXXX</value>
</property>
<property name="jndiTemplate">
<ref bean="myJndiTemplate" />
</property>
</bean>
The properties file referred to in the first bean is very small (currently only one line), and looks like this:
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV3
It is my understanding that PropertyOverrideConfigurer in the first bean
pushes values from a properties file into bean definitions
So the value of the jndiName property in the myBeanName bean will turn from
jdbc/XXXXX
to
java:comp/env/jdbc/XXXXX_YYY_DEV3.
This works and it partially does what we want. I need to expand the functionality so that I can handle multiple deployment environments. This currently replaces the bean property for one of our development environments (dev3). I think I need spring to dynamically alter "myBeanName" for about 25 different dev environments.
For example, I think I want my properties file to look like this
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV1
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV2
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV3
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV4
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV5
...
...
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV24
myBeanName.jndiName=java:comp/env/jdbc/XXXXX_YYY_DEV25
I have no idea if this is the right approach.
Any ideas?
Thanks in advance.
NOTE
my.company.department.svc.spring.WmSvcJndiDataSource in the second bean is simply a class we extended off of org.springframework.jndi.JndiObjectFactoryBean, FYI. I don't know if that is important to know or not.

MyBatis - defining a global parameter

First the problem: I'm using XML-defined queries and the SQL contains database name as part of a table name. For example: SELECT * from mydb.bar. Unfortunately, databases are created/named all over the place and mudb part is really dynamic and can change at any moment. So I wanted to replace it with a property so it would look like SELECT * FROM ${dbname}.bar and then I defined the following section in mybatis-config.xml:
<properties>
<property name="dbname" value="mydb"/>
</properties>
But when I run the query ${dbname} evaluates to null. Same happens if I define this property in the properties file. I would hate to pass this as part of the each call parameters since this is truly a global property. Can this be done? And if yes - how?
Yes, you can! This is kind of a weird undocumented feature maybe. When building your Configuration object, do something like this. (org.apache.ibatis.session.Configuration)
configuration.getVariables().put("global_param", "123");
Then in your XML map, you can reference.
select * from ${global_param}
I had the same issue using Spring+MyBatis, and solved it by setting 'configurationProperties' using my Spring XML definition for sqlSessionFactory. My example below shows how to set a custom global property named 'encryptionKey', with a value which you can either hard-code in the XML file, or load from an external file using the context:property-placeholder tag (as below).
<context:property-placeholder location="/WEB-INF/spring/config-datasource.properties" />
<beans:bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="typeAliasesPackage" value="com.example.model" />
<beans:property name="configurationProperties">
<beans:props>
<beans:prop key="encryptionKey">${jdbc.encryptionKey}</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
I was using an XML configuration but not Spring and set a property inside the Configuration object but discovered that had to be done before the mapper files are loaded (see here). I abandoned the Configuration object approach and went with this approach, which worked for me:
Reader reader = Resources.getResourceAsReader("..../mybatis-config.xml");
Properties properties = new Properties();
properties.setProperty("dbname", "mydb");
SqlSessionFactory.factory = new SqlSessionFactoryBuilder().build(reader, "development", properties);
Then, as Andy Pryor posted, use select * from ${dbname} in the XML mapper.

Concatenate strings within a Spring XML configuration file?

I have a String value in a Spring configuration file that comes to be as the result of a JNDI lookup -- it happens to be a path name:
<jee:jndi-lookup id="myAppHomeDir" jndi-name="myAppHomeDir" />
Now I need to concatenate on to the end of this path another string and hand it off to another Spring bean as follows (which of course doesn't work):
<bean id="LogPath" class="org.mystuff.initBean">
<property name="logDirectory">
<jee:jndi-lookup id="myAppHomeDir"
jndi-name="myAppHomeDir" /> + "/logs"
</property>
</bean>
Is there a simple way to do this without me having to write a utility class in Java?
Try using Spring EL (expression language). I would try the following (not tested):
<jee:jndi-lookup id="myAppHomeDir" jndi-name="myAppHomeDir" />
<bean id="LogPath" class="org.mystuff.initBean">
<property name="logDirectory" value="#{myAppHomeDir+'/logs'}"/>
</bean>
Not quite sure if it would work. The thing that troubles me is the cast from File (I guess) to String when concatenating. So if the previous one didn't work, I would try:
#{myAppHomeDir.canonicalPath+'/logs'}
Let us know if it works.

conditional beans using spring

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.
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" />
For complex cases (more complex than the one exposed), Spring JavaConfig could be your friend.
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
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.
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.

Categories

Resources