Refer a set of properties in a spring bean - java

I am using spring and having a requirement where I need to configure lots of beans. ex :
<bean name="PC_Name" class="com.stack.Exchange">
<property name="firstName" value="jack"/>
<property name="lastName" value="nicolas"/>
</bean>
<bean name="Mobile_Name" class="com.stack.Exchange">
<property name="firstName" value="jack"/>
<property name="lastName" value="nicolas"/>
</bean>
Now, as in both above beans I am using same properties and same values.
Is there any way to write these properties in a common tag and inject that in above beans. some thing like :
<bean name="PC_Name" class"com.stack.Exchange">
<properties name="nameReference"/>
</bean>
<bean name="Mobile_Name" class"com.stack.Exchange">
<properties name="nameReference"/>
</bean>
<properties name="nameReference">
<property name="firstName" value="jack"/>
<property name="lastName" value="nicolas"/>
</properties>
I know it can be achieved by Defining another class with firstName and lastName variables and inject that class in the required bean.
But I do not want to change code which has been written already in com.stack.Exchange class.
Thanks
Nitin

You have the possibility to create a Bean definition template. In this bean you have to declare an attribute "abstract" with value true. You should not specify class attribute in it.
<bean id="beanTemplate" abstract="true">
<property name="firstName" value="jack"/>
<property name="lastName" value="nicolas"/>
</bean>
<bean name="PC_Name" class"com.stack.Exchange" parent="beanTemplate">
</bean>
<bean name="Mobile_Name" class"com.stack.Exchange" parent="beanTemplate">
</bean>

Related

Spring - use different properties file for each bean

Not sure if it's possible since properties namespace is shared, but I was wondering how to make bean properties injection with values from a particular configuration file if there are few beans originating from same class and different only by bean Id.
For example, let's say there's a class Position
class Position{
int id;
String title;
}
And for each position there's a property file with values:
Employee.properties
id=1
title=Employee
Director.properties
id=2
name=Director
And XML configuration file looks like this:
<beans xmlns=.......>
<bean id="employeeProp" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:Employee.properties"/>
</bean>
<bean id="directorProp" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:Director.properties"/>
</bean>
<bean id="employee" class="com.example.title" lazy-init="true">
<property name="id" value="#{employeeProp.id}"/>
<property name="title" value="#{employeeProp.title}"/>
</bean>
<bean id="director" class="com.example.title" lazy-init="true">
<property name="id" value="#{directorProp.id}"/>
<property name="title" value="#{directorProp.title}"/>
</bean>
</beans>
Obviously that doesn't work because in #{employeeProp.id} I'm refering to id field of PropertyPlaceholderConfigurer object, not of the data it loaded from file.
Property or field 'id' cannot be found on object of type 'org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' - maybe not public?
I thought about to passing configuration as inner bean to constructor but that would unnecessary complicate class' logic.
How else (or If) it's possible to do properties injection based on values in different files without modifying class' logic?
Turns out you can use placeholderPrefix property for refering to exact config placeholder
So the resulting file would look like
<beans xmlns=.......>
<bean id="employeeProp" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:Employee.properties"/>
<property name="placeholderPrefix" value="employee-"/>
</bean>
<bean id="directorProp" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:Director.properties"/>
<property name="placeholderPrefix" value="director-"/>
</bean>
<bean id="employee" class="com.example.title" lazy-init="true">
<property name="id" value="employee-id}"/>
<property name="title" value="employee-title}"/>
</bean>
<bean id="director" class="com.example.title" lazy-init="true">
<property name="id" value="director-id}"/>
<property name="title" value="directorProp-title}"/>
</bean>
Note that I'm not using default value reference notation ${name} but name} because for some reason in case of using prefixes the former notation concatenates '${' to the value

How to give priority to spring bean with same id?

In our project we are using spring with Junit for Junit testing. We have used #ContextConfiguration annotation for loading multiple file. We have two classes AbstractContextJUnitTest and ContextJUnitTest and ContextJUnitTest extends AbstractContextJUnitTest.
During code flow I have noticed that same bean Id in multiple files with different bean types. When I am testing these Junits and getting the below error.
Error:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean
named 'voterId' is expected to be of type [com.spring.test2.Student]
but was actually of type [com.spring.test2.Parent]
My requirement is Student bean should load with VoterId instead of Parent Bean.
Below are the java files and spring bean xml files:
test.xml:
<beans>
<context:annotation-config/>
<bean id="voterId" class="com.spring.test2.Parent">
<property name="Name" value="hai"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="system" />
<property name="password" value="system" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
test1.xml
<beans>
<context:annotation-config/>
<bean id="voterId" class="com.spring.test2.Student">
<property name="name" value="hello"/>
<property name="number" value="2080"/>
</bean>
</beans>
AbstractContextJUnitTest.java
#ContextConfiguration(locations="classpath:/com/spring/test2/test1.xml")
public class AbstractContextJUnitTest extends AbstractTransactionalJUnit4SpringContextTests{
}
ContextJUnitTest.java
#ContextConfiguration(locations={"classpath:/com/spring/test2/test.xml"})
public class ContextJUnitTest extends AbstractContextJUnitTest{
#Test
public void testStudent(){
Student stud=applicationContext.getBean("voterId",Student.class);
assertEquals(stud.getNumber(), 2080);
}
}
Did you tried #Primary?
<bean id="voterId" class="com.spring.test2.Student" primary="true">
<property name="name" value="hello"/>
<property name="number" value="2080"/>
</bean>
You have to use #Qualifier for com.spring.test2.Parent wherever you need.
Or you can get the bean with type as:
applicationContext.getBeansOfType(Student.class).get("voterI‌​d")
This is probably because you have extended classes in that order..and your test.xml doesn't have any bean with of Student. So it is simply following inheritance and found parent.
Below lines make it look for bean voterid in test.xml first and it found it there.
ContextConfiguration(locations={"classpath:/com/spring/test2/test.xml"}) public class ContextJUnitTest

java.util.Properties: How do I retrieve values from Properties in spring config xml

I have a java.util.Properties object which has few key value pairs in it. I am trying to use this Property object in the spring configuration file i.e. define the key in the spring config and during runtime, it should get the value from the properties object.
For ex:
<bean id="test" class="com.sample.Test">
<constructor-arg value="${PROPERTY_KEY} />
</bean>
Now during the runtime, the constructor should get the value that is present in the Property object.
Is there a way to get this done ?
Note: I do not want to use config.properties here. Looking to use java.util.Properties
Thanks,
Rahul
<context:property-placeholder location="classpath:placeholder.properties"/>
or
<bean id="properties"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:<file-name>.properties" />
</bean>
First you have to create bean to access your property file, like below
<bean id="appProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="singleton" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath*:localhost-mysql.properties</value>
<value>classpath*:mail-server.properties</value>
</list>
</property>
</bean>
<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="appProperties" />
</bean>
Next you can access Key-Value pair from your property files, like below
<bean id="mailServerSettings" class="com.ratormonitor.app.context.EmailSettings">
<property name="host" value="${mail.server.host}" />
<property name="port" value="${mail.server.port}" />
<property name="username" value="${mail.server.username}" />
<property name="password" value="${mail.server.password}" />
<property name="requestContextPath" value="${request.context.path}" />
</bean>
Hope this code will solve your problem.
You can use Spring Expression Language (SpEL) to get a java object value in spring configuration xml file.
An example :
<property name="misfireInstruction"
value="#{T(org.quartz.CronTrigger).MISFIRE_INSTRUCTION_FIRE_ONCE_NOW}"/>
So this is how I did:
As I said I had a java.util.Properties object. I then created a CustomProperty class which extended PropertySource>
public class CustomPropertySource extends PropertySource<Map<String, Object>>
Then in my main class I did the following:
AbstractApplicationContext context = new ClassPathXmlApplicationContext(new String[] {springConfigLocation, false);
context.getEnvironment().getPropertySources.addlast(new CustomPropertySource("custom", propertiesObject));
conext.refresh();
And then in the spring config file, I had to add this:
<context: property-placeholder ignore-unresolvable="true"/>
So in this way, I could fetch values for the keys defined in the spring config file, just like how we get the values from property files.
Thanks,
Rahul

Spring XML Configuration - How to specify property value for a group of objects?

Say I have the following beans defined.
<bean id="testBean1" class="org.springframework.beans.TestBean" scope="prototype">
<property name="hariColor" value="Black"/>
<property name="spouse">
<bean class="org.springframework.beans.TestBean">
<property name="age" value="11"/>
</bean>
</property>
</bean>
<bean id="testBean2" class="org.springframework.beans.TestBean" scope="prototype">
<property name="hariColor" value="Black"/>
<property name="spouse">
<bean class="org.springframework.beans.TestBean">
<property name="age" value="19"/>
</bean>
</property>
</bean>
I have a set of beans with hairColor Black, another set of beans with hairColor Blonde etc.. Is there a way in Spring to group all Black hair color beans together and define the hairColor in only one place rather than specifying for each bean?
Yes you can achieve it via abstract="true" element in Spring's bean as explained below
<bean id="blackHairColor" abstract="true">
<property name="prop1" ref="someBlackBean"/>
<property name="prop2" ref="someOtherBlackBean"/>
</bean>
<bean id="blondeHairColor" abstract="true">
<property name="prop1" ref="someBlondeBean"/>
<property name="prop2" ref="someOtherBlondeBean"/>
</bean>
<bean id="someBean1" class="a.b.c.d" parent="blackHairColor">
<property name="someOtherProp" ref="someRef1"/>
</bean>
<bean id="someBean2" class="a.b.c.d" parent="blondeHairColor">
<property name="someOtherProp" ref="someRef1"/>
</bean>
Here we define two abstract beans with respective properties. Do note that these abstract beans do not have a class attached to them and thus creates a set of common properties which could be re-used in other bean(s).
To inherit the abstract bean simply mention their id in the parent element of bean definition. Also note that the bean class does not need to inherit any class to inherit another bean i.e. class a.b.c.d do not need to inherit any class for the bean inheritance to work.

Wrong value injected with Spring PropertyPlaceholderConfigurer

I have two properties files:
prop1.properties:
prop1.sample=value123
and
prop2.properties:
prop2.sample=value234
When I inject these properties values two my "InjectValues" bean then everything works in a proper way. But when I want to inject a value from one PropertyPlaceHolder to another class which simply extends PropertyPlaceHolder then instead of value, the key is inserted as presented below.
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>file:C:\test\prop1.properties</value>
</property>
<property name="placeholderPrefix" value="${" />
<property name="placeholderSuffix" value="}" />
</bean>
<bean id="propertyConfigurerNew"
class="com.test.spring.property.EncryptedPlaceHolder">
<property name="location">
<value>file:C:\test\prop2.properties</value>
</property>
<property name="key" value="${prop1.sample}" /> <!-- Value "${prop1.sample}" is injected instead of value123 -->
<property name="placeholderPrefix" value="#[" />
<property name="placeholderSuffix" value="]" />
</bean>
<bean id="injectValues"
class="com.test.spring.property.InjectValues">
<property name="value1" value="${prop1.sample}" /> <!-- Correct value "value123" is injected -->
<property name="value2" value="#[prop2.sample]" /> <!-- Correct value "value234" is injected -->
</bean>
It looks that PropertyPlaceHolders can't replace placeholders in other PropertyPlaceHolders because are executed in the same phase as mentioned in the comments.

Categories