My problem statement is as follows :
I want to connect to db and from a table get certain values and assign those to a bean. In current spring project, it is done as follows :
The class com.some.DbPropertyPlaceholderConfigurer is in a jar file.
<bean id="propertyConfigurer"
class="com.some.DbPropertyPlaceholderConfigurer">
<property name="dataSourceName" value="dataSource" />
<property name="locations">
<list>
<value>classpath:resources/context.properties</value>
</list>
</property>
</bean>
<bean id="someObject" class="com.some.beans.SomeObject">
<property name="someprop" value="${prefix.someprop}" />
<property name="someprop1" value="${prefix.someprop1}" />
<property name="someprop2" value="${prefix.someprop2}" />
....
</bean>
DbPropertyPlaceholderConfigurer is in a jar file, it reads from a db table.
The Db table has key value columns.
The key contains "prefix.someprop" and it has some value.
Now, I am working on converting spring beans into spring boot beans using annotations.
Following is the bean in spring.
I came up with following for spring boot but bean it is not getting initialized.
I am not sure how to map properties "dataSourceName" and "locations"
#Configuration
public class AppConfig {
#Bean
public DbPropertyPlaceholderConfigurer propertyConfigurer() {
return new DbPropertyPlaceholderConfigurer();
}
#Bean
public SomeObject someObject() {
return new SomeObject();
}
}
It throws following exception :
[localhost-startStop-1] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.lang.NullPointerException
at com.some.configuration.DbPropertyPlaceholderConfigurer.processProperties(DbPropertyPlaceholderConfigurer.java:130)
Also if it gets initialzed, how will I actually use it ?
I am facing a strange problem with Spring, a bean is not initialized completely with injected dependency. It works fine if a thread sleep of minimal 5 seconds is introduced before accessing that bean.
This is not a case of notify/wait as this is in control of Spring.
Another pointer is that the bean's methods are static and variable is also static.
Any hints will be appreciated.
Here's the code
public final class UserPreferencesUtils {
/** siamHandlerFacade variable. */
private static SiamHandlerFacade siamHandlerFacade;
=====
public static String getSubscriberXXXX() {
try {
// Here the above is being used
// This method is also static
showSubscriberProfile = siamHandlerFacade
.retrieveSubscriberProfile(retrieveSubscriberProfile);
} catch (WebServiceClientException ex) {
ex.getMessage();
bean configuration
<bean id="userPreferenceUtils" class="aero.sita.voyager.ias.client.commons.utils.UserPreferencesUtils">
<property name="siamHandlerFacade" ref="siamServiceManagerRemoteService"></property>
<property name="queryLMData" ref="queryLMData"></property>
</bean>
<bean id="siamServiceManagerRemoteService"
class="aero.sita.voyager.ias.client.commons.webserviceproxy.SiamHandlerFacadeImpl">
<property name="siamWebServiceCallProxy" ref="siamWebServiceCallProxy"/>
<property name="officeWebServiceCallProxy" ref="officeWebServiceCallProxy"/>
<property name="subscriberWebServiceCallProxy" ref="subscriberWebServiceCallProxy"/>
<property name="masterAgreementWebServiceCallProxy" ref="masterAgreementWebServiceCallProxy"/>
<property name="agreementWebServiceCallProxy" ref="agreementWebServiceCallProxy"/>
<property name="userProfileWebServiceCallProxy" ref="userProfileWebServiceCallProxy"/>
</bean>
I'm new to Spring development.And right now,i'm really facing a problem.Here are the code snippets to make you realize my problem clearly.............
Here is my DAO class:
public class LoginDaoImpl {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public int checkLoginDetails(LoginVo loginVo){
String sql = "select count(*) from empsctygrp where username=? and password=?";
jdbcTemplate = new JdbcTemplate(dataSource);
int count = jdbcTemplate.queryForObject(sql,new Object[]{loginVo.getUserName(),loginVo.getPassword()},Integer.class);
return count;
}
}
Now here is my Business-Object(BO) class:
public class LoginBo {
LoginDaoImpl loginDaoImpl = new LoginDaoImpl();
public int checkLoginDetails(LoginVo loginVo){
return loginDaoImpl.checkLoginDetails(loginVo);
}
}
Now,here is my dispatcher-servlet xml code:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#117.194.83.9:1521:XE"/>
<property name="username" value="system"/>
<property name="password" value="password1$"/>
</bean>
<bean id="loginDaoImpl" class="com.abhinabyte.dao.LoginDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
Now whenever i'm trying to run this on server the following exception is given:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/A] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required] with root cause
java.lang.IllegalArgumentException: Property 'dataSource' is required
Please help me solve this problem.............:(
Try this in LoginBo class:
#Autowired
LoginDaoImpl loginDaoImpl;
instead of
LoginDaoImpl loginDaoImpl = new LoginDaoImpl();
The problem is that you manually instantiate LoginDaoImpl.
I was having the same problem and could not find a comprehensive answer on the web, so I decided to post one here for anyone else, or for future me.
I'm still learning so if you think I have made a mistake below, please feel free to edit.
Summary:
Include <integration:annotation-config/> <context:component-scan base-package="myproject"/> in your servlet to pick up annotations
Configure JUnit tests with #RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:WEB-INF/FinanceImportTool-servlet.xml")
Don't autowire dataSource or jdbcTemplate if these fields are already provided by a parent class e.g. StoredProcedure
Don't use new() as this initializes classes outside the applicationContext
Beware of using properties in your constructor which have not yet been set - obvious but embarrassingly easy to do
My original class (now altered):
public class MyDAOImpl extends StoredProcedure implements MyDAO {
private static final String SPROC_NAME = "dbo.MySP";
public MyDAOImpl(DataSource dataSource) {
super(dataSource, SPROC_NAME);
// ...declared parameters...
compile();
}
}
MyProject-servlet.xml file (only relevant bits included):
<!-- Used by Spring to pick up annotations -->
<integration:annotation-config/>
<context:component-scan base-package="myproject"/>
<bean id="MyDAOBean" class="myproject.dao.MyDAOImpl" >
<constructor-arg name="dataSource" ref="myDataSource"/>
</bean>
<!-- properties stored in a separate file -->
<bean id="myDataSource" class="com.microsoft.sqlserver.jdbc.SQLServerDataSource">
<property name="databaseName" value="${myDataSource.dbname}" />
<property name="serverName" value="${myDataSource.svrname}" />
<!-- also loaded portNumber, user, password, selectMethod -->
</bean>
Error: property 'dataSource' is required, or NullPointerException (1)
Other answers say make sure you have passed dataSource as a <property> for your bean in the servlet, etc.
I think #Abhinabyte the OP needed to annotate his setDataSource() method with #Annotation, and use <integration:annotation-config/> <context:component-scan base-package="myproject"/> in his servlet to successfully pass in dataSource as a dependency to LoginDaoImpl.
In my case, I tried adding 'dataSource' as a property and autowiring it. The "dataSource is required" error message became a NullPointerException error.
I realised after far too long that MyDAOImpl extends StoredProcedure.
dataSource was already a property of StoredProcedure. By having a dataSource property for MyDAOImpl, the autowiring was not picking up and setting the dataSource property of StoredProcedure, which left dataSource for StoredProcedure as null.
This was not picked up when I tested the value of MyDAOImpl.dataSource, as of course by now I had added a MyDAOImpl.dataSource field that had been autowired successfully. However the compile() method inherited from StoredProcedure used StoredProcedure.dataSource.
Therefore I didn't need public DataSource dataSource; property in MyDAOImpl class. I just needed to use the StoredProcedure constructor with super(dataSource, sql); in the constructor for MyDAOImpl.
I also didn't need a MyDAOImpl.jdbcTemplate property. It was set automatically by using the StoredProcedure(dataSource, sql) constructor.
Error: NullPointerException (2)
I had been using this constructor:
private static final String SPROC_NAME = "dbo.MySP";
public MyDAOImpl(DataSource dataSource) {
super(dataSource, SPROC_NAME);
}
This caused a NullPointerException because SPROC_NAME had not been initialized before it was used in the constructor (yes I know, rookie error). To solve this, I passed in sql as a constructor-arg in the servlet.
Error: [same error message appeared when I had changed file name]
The applicationContext was referring to the bin/ instances of my beans and classes. I had to delete bin/ and rebuild the project.
My new class:
public class MyDAOImpl extends StoredProcedure implements MyDAO {
#Autowired // Necessary to prevent error 'no default constructor found'
public MyDAOImpl(DataSource dataSource, String sql) {
super(dataSource, sql);
// ...declared parameters...
compile();
}
New MyProject-servlet.xml file (only relevant bits included):
<!-- Used by Spring to pick up annotations -->
<integration:annotation-config/>
<context:component-scan base-package="myproject"/>
<bean id="myDAOBean" class="org.gosh.financeimport.dao.MyDAOImpl" >
<constructor-arg name="dataSource" ref="reDataSource"/>
<constructor-arg name="sql" value="dbo.MySP" />
</bean>
<!-- properties stored in a separate file -->
<bean id="myDataSource" class="com.microsoft.sqlserver.jdbc.SQLServerDataSource">
<property name="databaseName" value="${myDataSource.dbname}" />
<property name="serverName" value="${myDataSource.svrname}" />
<!-- also loaded portNumber, user, password, selectMethod -->
</bean>
Helpful places:
If you can get past the rage, this answer on Spring forums might help too
This answer gives a broad introduction to Spring configuration
This answer has simple but useful suggestions
You should annotate that beans that will suffer IoC. Like
#Bean public class LoginDAOImpl { #Inject DataSource dataSource;......}
You set up in spring context this beans, but, you're not using them.
OBS:
When I use the JDBCTemplate I configure de IoC of JDBC like
<bean id="dataSourcePerfil" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${br.com.dao.jdbc.driver}" />
<property name="url" value="${br.com.dao.jdbc.url}" />
<property name="username" value="${br.com.dao.jdbc.user}" />
<property name="password" value="${br.com.dao.jdbc.pass}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSourcePerfil" />
</bean>
then.... after at all
#Bean
public class LoginDAOImpl {
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public List<ClienteReport> getClientes() {
return Collections<ClienteReport>. emptyList();
}
}
I'm working my way through the Spring Framework reference documentation with some very basic application code. So far, I've created an ApplicationContext from an XML file and loaded some beans. I believe I understand this process pretty well. I've loaded some basic beans with attributes based on fundamental types and found that straight-forward.
I'm now working on a composite bean with other beans as its attributes. So far, I've been able to set these attributes using a direct reference to a bean and an inner bean. However, when I try to get the idref element to work (see http://docs.spring.io/spring/docs/3.2.4.RELEASE/spring-framework-reference/html/beans.html#beans-idref-element) I get the following exception:
java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.example.BasicBean] for property 'idRef': no matching editors or conversion strategy found
Code snippets below:
Application Context XML
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="id-bean" class="com.example.BasicBean" scope="singleton">
<property name="value" value="31"/>
</bean>
<bean id="ref-bean" class="com.example.BasicBean" scope="singleton">
<property name="value" value="37"/>
</bean>
<bean id="cb" class="com.example.CompositeBean" scope="singleton">
<property name="id" ref="id-bean"/> <!-- works -->
<property name="inner"> <!-- works -->
<bean class="com.example.BasicBean">
<property name="value" value="43"/>
</bean>
</property>
<property name="idRef"> <!-- exception thrown -->
<idref bean="ref-bean"/>
</property>
</bean>
</beans>
Java App Code
public void main()
{
context = new ClassPathXmlApplicationContext("beans.xml");
CompositeBean cb = context.getBean("cb", CompositeBean.class);
}
Java Bean Code
public class CompositeBean
{
private BasicBean id;
private BasicBean idRef;
private BasicBean inner;
// Default constructor exists
// Setters, getters for each attribute exist
...
}
public class BasicBean
{
private int value;
// Default constructor exists
// Setters, getters for each attribute exist
...
}
Version info: I'm using Eclipse IDE (Kepler), Maven 3.1, Java 7 (1.7.45), Spring 3.2.4
Any thoughts on what I'm doing wrong?
Thanks #Farid for pointing out that I was mis-using the idref attribute in this instance. As the Spring doco points out (which I'd read several times and still missed this) it's designed for passing the id of a bean around a container and not the actual bean. So, stick to the first two means above (ref and inner bean) for passing a bean around.
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