How to give priority to spring bean with same id? - java

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

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

Properties file value is not being read in xml

I was learning Java Spring and faced a problem while working with properties file. Property File value is not being read in xml file and throwing exception.
The XML file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="triangle1" class="com.springtest.shapes.Triangle">
<property name="pointA" ref="zeroPoint"/>
<property name="pointB" ref="point2" />
<property name="pointC" ref="point3" />
</bean>
<bean id="zeroPoint" class="com.springtest.shapes.Point">
<property name="x" value="#{pointA.pointX}" />
<property name="y" value="#{pointA.pointY}" />
</bean>
<bean id="point2" class="com.springtest.shapes.Point">
<property name="x" value="5" />
<property name="y" value="2" />
</bean>
<bean id="point3" class="com.springtest.shapes.Point">
<property name="x" value="-20" />
<property name="y" value="10" />
</bean>
<bean class="com.springtest.main.DisplayNameBeanPostProcessor"/>
<bean class="org.SpringFramework.beans.factory.config.PropertyPlaceHolderConfigurer">
<property name="locations">
<value>classpath:pointconfig.properties</value>
</property>
</bean>
</beans>
The Property file is as follows:
pointA.pointX=0
pointA.pointY=0
The following exception is being shown:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'pointA' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public?
at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:213)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:100)
at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:87)
at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:52)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:111)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:270)
at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:163)
... 28 more
The Project Structure is also provided
Thanks in advance
I finally get the answer after continuous digging. Thanks Manish Shen from Youtube.
My Problem was,
I named the class name wrong. This class name was used in previous version of spring. The new class name is "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer".
The Value in the property of spring.xml should be written as "${pointA.pointX}" instead of "#{pointA.pointX}".
I am sharing the screenshot from where i got the answer.

Spring MVC 3.2.8: Create a new FileSystemXmlApplicationContext and loading the definitions from the given XML files

I have an Spring MVC 3.2.8 app, and I want to run StandAlone process to generate a PDF. I want to initialize the container and manage beans from an stand-alone app.
I have this piece of code:
public class CreatePDF {
private static final Logger LOGGER = Logger.getLogger (ImportEcolabelToolboxToECAT.class);
public static void main(String[] args) {
String[] configLocations = new String[] {
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/dao/dataAccessContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/webapp/WEB-INF/dao/databaseMessageSource.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/services/impl/servicesContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/webapp/WEB-INF/applicationContext.xml",
"C:/Development/Workspaces/EclipseWS/devices/deviceWeb/src/main/resources/com/nicinc/controller/propertyeditors/propertyeditorsContext.xml"};
FileSystemXmlApplicationContext ctx =
new FileSystemXmlApplicationContext(configLocations, true);
}
}
But I have this error when running the app.
Error creating bean with name 'dataSource': Invocation of init method failed; nested exception is javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
and here the definition from the file dataAccessContext.xml :
<!-- The PropertyPlaceholderConfigurer replaces placeholders in Spring bean definitions with the values from the chosen properties files. -->
<!-- There is an example use in the datasource definition below. Look for the $\{jdbc.*} values. -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:com/nicinc/dao/jdbc-test.properties</value>
<value>classpath:com/nicinc/dao/dbMessageSource.properties</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="${hibernate.dialect}"/>
<property name="generateDdl" value="false"/>
<property name="showSql" value="false" />
</bean>
</property>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
The javax.naming package comprises the JNDI Api. Since it is just an API its implementation you will have to provide. Generally the implementation is provided by App server. As per the error you are Missing the JNDI implementation.
Possible solution:
If you dont have any javaee related requirement then you should directly use DriverManagerDataSource.
You need to provide your own implementation.Below link might help.
using application data source locally.

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.

spring - how to autowire data source?

I'm having some problem with autowire and DI in general, so I hope that someone can help cause I've been stuck for days now.
This is the code:
#Service
public class TicketsController implements Controller {
private TicketManager ticketManager;
#Autowired
public void setTicketManager(TicketManager ticketManager) {
this.ticketManager = ticketManager;
}
...
}
#Service
public class SimpleTicketManager implements TicketManager {
private TicketsDao ticketsDao;
#Autowired
public void setTicketsDao(TicketsDao ticketsDao) {
this.ticketsDao = ticketsDao;
}
...
}
#Repository
public class JdbcTicketDao implements TicketsDao {
private DataSource dataSource;
#Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource=dataSource;
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
}
...
}
public final class AppContext {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
BeanFactory factory = context;
TicketsController ticketsController = (TicketsController) factory.getBean("ticketsController");
}
...
}
In my beans.xml I've got:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mytckdb"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
</bean>
<context:component-scan base-package="bp.dao" />
<context:component-scan base-package="bp.mvc" />
<context:component-scan base-package="bp.svc" />
<context:component-scan base-package="bp.view" />
This doesn't work and I get:
Error creating bean with name 'jdbcTicketDao': Injection of autowired dependencies failed
... nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [javax.sql.DataSource] found for dependency.`
Can someone please help out with this? What am I doing wrong? It seems that autowiring is working all until the next step where it fails when injecting dataSource.
EDIT: I was playing with the code, and forgot #Autowire before setDataSource() but it is supposed to be there.
Maybe you're missing wiring configuration, try
<context:annotation-config/>
This will be due to the order of bean instance creation. Your DAO has been instantiated before the dataSource instance created.
Keep your data Source bean definition before
other way is , define your dataSource definitions in a separate xml and import that before
Try org.apache.commons.dbcp.BasicDataSource :
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://127.0.0.1:3306/mytckdb?autoReconnect=true"
p:username="user" p:password="pass" />
I use JPA so generally prefer to create EntityManagerFactory and use that
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="PU" />
<property name="jpaVendorAdapter">
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="${database}" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
Looks like you are using Spring 2.0 but i think context:component-scan was introduced in Spring 2.5.
Maybe update spring xml-config and spring dependencies to 2.5?
Change
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mytckdb"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
</bean>
to
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mytckdb"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
</bean>
The property is called driverClassName, not driverClass.
Also, you don't need multiple context:component-scan elements You can change
<context:component-scan base-package="bp.dao" />
<context:component-scan base-package="bp.mvc" />
<context:component-scan base-package="bp.svc" />
<context:component-scan base-package="bp.view" />
To
<context:component-scan base-package="bp.dao,bp.mvc,bp.svc,bp.view" />

Categories