How to create multiple objects of same class , with different values , in Spring using xml config file? - spring

appContextXmlAutowiring.xml
<bean id="emp" class="com.org.epam.Assignment.Spring.XmlAutowiring.Employee" >
<property name="name" value ="Vineet"/>
<property name="id" value ="100"/>
<property name="age" value ="28"/>
<property name="addressNew" ref="addressNew"/>
</bean>
<bean id="emp1" class="com.org.epam.Assignment.Spring.XmlAutowiring.Employee">
<property name="name" value ="Ashutosh"/>
<property name="id" value ="200"/>
<property name="age" value ="29"/>
<property name="addressNew" ref="addressNew1"/>
</bean>
<bean id="addressNew1" class="com.org.epam.Assignment.Spring.XmlAutowiring.Address" >
<property name="country" value ="India1"/>
<property name="state" value ="Maharashtra"/>
<property name="city" value ="Pune"/>
</bean>
<bean id="addressNew" class="com.org.epam.Assignment.Spring.XmlAutowiring.Address" >
<property name="country" value ="Ind"/>
<property name="state" value ="Mah"/>
<property name="city" value ="Punite"/>
</bean>
</beans>
Driver Main Class
public class DriverClass {
public static void main(String[] args) {
try{
ApplicationContext ac = new ClassPathXmlApplicationContext("appContextXmlAutowiring.xml");
Employee e = ac.getBean(Employee.class);
System.out.println(e.toString());
//System.out.println(e.getAddressNew().getCity());
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Error Message
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.org.epam.Assignment.Spring.XmlAutowiring.Employee' available: expected single matching bean but found 2: emp,emp1
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1041)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:345)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1092)
at com.org.epam.Assignment.Spring.XmlAutowiring.DriverClass.main(DriverClass.java:12)
I am getting mentioned error when trying to create two different objects of same type i.e. Employee using Spring Application context.
Could anyone please help me in solving this error.
Also please mention how to create multiple objects of same class , with different values , in Spring using xml config file ?
Thanks

You are creating two beans with the same class and then retrieve the bean by class. The error says it doesn't know which bean to choose.
You should use the
applicationContext.getBean(name)
method instead

Your code is already creating multiple beans of same class as you defined in your xml config. That is not where the code is failing it is failing while retrieving the Employee bean from the application context. The reason behind this failure is pretty clear in the error message;
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type
'com.org.epam.Assignment.Spring.XmlAutowiring.Employee' available:
expected single matching bean but found 2: emp,emp1
You need to retrieve the bean by its name in such situation as below;
Employee e = (Employee) ac.getBean("emp");
Employee e1 = (Employee) ac.getBean("emp1");

Related

difference in behaviour between spring PropertyPlaceholderconfigurer and PropertyOverrideConfigurer

I wanted to externalize my configuration properties so planned to use - PropertyPlaceholderconfigurer - here is my context file:
<bean id="helloBean" class="com.springex1.HelloWorld">
<property name="name" value="test!{my.db.jdbc.driver}" />
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="testPropertyConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="location" value="classpath:/springdb.properties"/>
<property name="placeholderPrefix" value="test!{"/>
<property name="placeholderSuffix" value="}"/>
<property name="order" value="0"/>
</bean>
Simple java class - HelloWorld.java
public class HelloWorld {
private String name;
public void setName(String name) {
this.name = name;
}
public void printHello() {
System.out.println("Hello ! " + name);
}
My properties file:
my.db.jdbc.driver=xyz
foo=bar
All of this works fine. Note that the first property is being injected
my.db.jdbc.driver=xyz
while the second property
foo=bar
is not being used - but spring works fine and does not complain
Now I decided to override the properties - so decided to add the propertyOverrideConfigurer
<bean id="propertyOverrideConfigurer"
class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="location" value="classpath:/override.properties" />
<property name="order" value="20" />
</bean>
Added the override.properties:
helloBean.name=oracle.jdbc.OracleDriver
This works as expected and prints - oracle.jdbc.OracleDriver
Now my understanding was that I wanted to override the additional property
foo=baz
And then code failed :
Exception in thread "main" org.springframework.beans.factory.BeanInitializationException: Could not process key 'foo' in PropertyOverrideConfigurer; nested exception is org.springframework.beans.factory.BeanInitializationException: Invalid key 'foo': expected 'beanName.property'
This part is understood - spring is looking for bean name 'helloBean' and then its corresponding attribute.
While the issue is understood - my question is - in PropertyPlaceholderConfigurer I can define additional properties which are not injected and it works fine.
But - PropertyOverrideConfigurer - any property defined must get injected and for that to happen - there must be a bean with attributes available
I cannot really have additional properties hanging around in case of PropertyOverrideConfigurer - which does not sound right.
am I missing something that can ignore this error ?

Spring - how to reference another property within the same bean?

I have the following definition in my configuration:
<bean class="com.project.TimerBean">
<property name="delay" value="30000" />
<property name="interval" value="60000" />
<property name="invokeThis" value="com.project.TargetClass" />
<property name="receiver" value="XYZ" />
<property name="args" value="#{interval}" />
</bean>
I would like to set the value of args to the same value as interval (in this case, 60000) without having to hard-code the value. However, the above snippet doesn't seem to work. How should I change this?
# syntax (Spel Expressions) are supposed to work the way you wrote it. You need to replace
#{interval} to #{beanId.interval}.
For example, if the id of the bean you are creating is timerBean, #{timerBean.interval} is supposed to work. You cannot refer to a property directly even if it is a part of the bean definition.
It only works if the property you are referring to is a part of another bean.
<bean id="beanA" class="org.BeanA">
<property name="prop1" value="1000" />
</bean>
<bean id="beanB" class="org.BeanB">
<property name="prop2" value = "#{beanA.prop1}" />
<property name="prop3" value = "#{beanB.prop2}" />
</bean>
In the above example, prop2 gets initialised from prop1 correctly. But prop3 gets initialised to null.
If you look at AbstractAutowireCapableBeanFactory class and method,
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
you can see that all the property values in a single bean definition are looped over and values are parsed. After all the values have been successfully parsed, only then they are set on the bean instance. In the above beanA and beanB example when prop3's value is getting parsed, spring looks for the value of prop2 on beanB which is not yet set and hence returns null.
AFAIK, there is no way around this except the way suggested by #Alex
PS: I am using spring version 4.1.6.RELEASE
Move interval value "60000" to the property file
yourVariableName = 60000
and change to:
<property name="interval" value="${yourVariableName}" />
<property name="args" value="${yourVariableName}" />

create a bean from jobparameter in spring batch

I want to a create bean with some of job parameters. I found one thread here
but that seems to unsolved and was an old post.
<bean id="context" class="com.test.MyConfig" scope="step" >
<property name="toDate" value="#{jobParameters['toDate']}" />
<property name="fromDate" value="#{jobParameters['fromDate']}" />
</bean>
<bean id="testId" class="com.test.SomeClass" scope="step" >
<property name="context" ref="context" />
</bean>
And setter attribute is like below And MyConfig does not implement any interface.
MyConfig config;
public void setConfig(MyConfig config)
{
this.config = config
}
I get an exception
Error creating bean with name 'lazybidingProxy.anotherBean' defined in
class path [resource/config/spring-context.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportException: Failed to convert value of type 'com.sun.proxy.$Proxy17 implementing org.springframework.beans.factory.Initializing,java.io.Serializable,org.springframework.aop.scope.ScopedObject.....
to required type[package.someClass]: no matching editors or conversion strategy found]

spring bean initializing instances differently via property wiring

I have the following properties in a property file:
context1.property1=value1
context1.property2=value2
context1.property3=value3
context2.property1=value4
context2.property2=value5
context2.property3=value6
I have a bean with the following structure:
class Bean {
private property1;
private property2;
private property3;
}
Is there any way better to initialize 2 instances of Bean without writing something like:
<bean id="bean1" class="com.test.Bean">
<property name="property1" value="${context1.value1}" />
<property name="property2" value="${context1.value2}" />
<property name="property3" value="${context1.value3}" />
</bean>
<bean id="bean2" class="com.test.Bean">
<property name="property1" value="${context2.value1}" />
<property name="property2" value="${context2.value2}" />
<property name="property3" value="${context2.value3}" />
</bean>
Thanks!
Have a look at PropertyOverrideConfigurer:
Property resource configurer that overrides bean property values in an application context definition. It pushes values from a properties file into bean definitions.
Configuration lines are expected to be of the following form:
beanName.property=value
Example properties file:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
See also
Using PropertyOverrideConfigurer with Annotated Classes in Spring 3

Ant task for Spring Validation

I need an ANT task to validate spring configuration. I need to find problems at build time before runtime ? For example, In spring context file contains a property a bean, but this bean doesnt have this property.
In eclipse, there is a tool Spring Explorer that do this validation.
thanks,
org.springframework.web.context.ContextLoaderListener failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'readController' defined in class path resource [applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'productOperations' of bean class [com.bee.view.json.ReadController]: Bean property 'productOperations' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?.
An easy way to ensure that your context is valid would be to create a JUnit test, which loads the context. Using the spring-test.jar support classes makes that easy:
public class MyTest extends AbstractDependencyInjectionSpringContextTests {
// this will be injected by Spring
private QueryDao queryDao;
private MyBusinessObject myBusinessObject;
// ensure that spring will inject the objects to test by name
public MyTest () {
setAutowireMode(AUTOWIRE_BY_NAME);
}
#Override
protected String[] getConfigLocations() {
return new String[] { "applicationContextJUnit.xml" };
}
public void testQueryDao() {
List<SomeData> list = queryDao.findSomeData();
assertNotNull(list);
// etc
}
public void testMyBusinessObject() {
myBusinessObject.someMethod();
}
public void setQueryDao(QueryDao queryDao) {
this.queryDao = queryDao;
}
}
The problem with loading a context that is used in a web application is that JUnit does not necessarily have access to the same resources (e.g. JNDI data sources), so if you've got the following in your "applicationContext.xml":
<beans ...>
<bean id="myBusinessObject" class="com.test.MyBusinessObject">
<property name="queryDao" ref="queryDao"/>
</bean>
<bean id="queryDao" class="com.test.QueryDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<jee:jndi-lookup
id="dataSource"
jndi-name="jdbc/mydatasource"
resource-ref="true"
cache="true"
lookup-on-startup="false"
proxy-interface="javax.sql.DataSource"/>
</beans>
and your "applicationContextJUnit.xml" would import your "real" application context and redefine resources:
<beans ...>
<import resource="classpath:applicationContext.xml"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:..."/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
</beans>
That way your unit tests will load the application context (even the ones that you don't explicitly test in your unit test), and you can have the confidence that your context is correct, because Spring itself loaded it. If you have an error, then the unit tests will fail.

Resources