Null pointer in Initialising NamedParameterJdbcTemplate bean - spring

If i do the code in controller with
final DataSource dataSource = (DataSource) getApplicationContext().getBean("dataSource", DataSource.class);
final JdbcTemplate jdbcTemplate = new JdbcTemplate(jdbcDataSource);
final NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
This will work fine
If i have to attain the same in Spring application context
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" autowire="constructor" />
<bean class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"
id="namedParameterJdbcTemplate">
<constructor-arg ref="jdbcTemplate" />
</bean>
In Hibernate Repository Class
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void setNamedParameterJdbcTemplate(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
This throws error
Is there any way to make the object namedParameterJdbcTemplate working in Repository class

If you've declared your jdbcTemplate in your XML, that is all you should need.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
You do need to set the datasource on the JdbcTemplate though.
Once you autowire the JdbcTemplate into your DAO, you should be able to use that to create a NamedParameterJdbcTemplate.
#Repository
public class DAOImpl implements DAO {
#Autowired
private JdbcTemplate jdbcTemplate;
public void foo() {
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
....
}
}
You need to actually create an instance of it before you use it.
If you want to use XML to create your instance you can do that too, but you'll need to autowire in the instance that gets created by the XML.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="namedParamterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="jdbcTemplate"/>
</bean>
Then you should only have to autowire in the NamedParameterJdbcTemplate into your DAO.

Related

Spring batch doesnt start transaction when using custom writer

I am working on a spring batch which reads from a csv file and writes into database. i am using FlatFileItemReader for reading the file and implemented ItemWriter which uses Jpa to insert data into database. But batch fails with no transaction in progress.
Here is my job configuration
<bean id="datasource" class="oracle.jdbc.pool.OracleDataSource">
<property name="user" value="xxx" />
<property name="password" value="xx" />
<property name="URL" value="xxx" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="entityManagerFactory" name="model"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="datasource"/>
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="false"/>
<property name="showSql" value="true"/>
<property name="database">
<util:constant
static-field="org.springframework.orm.jpa.vendor.Database.ORACLE"/>
</property>
<property name="databasePlatform" value="org.hibernate.dialect.Oracle12cDialect"/>
</bean>
</property>
</bean>
<batch:job id="testJob">
<batch:step id="step">
<batch:tasklet>
<batch:chunk reader="cvsFileItemReader" writer="databaseWriter"
commit-interval="10">
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
And below is my writer
public class DatabaseWriter implements ItemWriter<Report> {
private EntityManagerFactory entityManagerFactory;
#Autowired
public DatabaseWriter(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
#Override
public void write(List<? extends Report> list) throws Exception {
EntityManager entityManager = entityManagerFactory.createEntityManager();
for (Report report : list) {
entityManager.persist(report );
}
entityManager.flush();
}
}
It only works if start transaction explicitly .that is like below
public class DatabaseWriter implements ItemWriter<Report> {
private EntityManagerFactory entityManagerFactory;
#Autowired
public DatabaseWriter(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
#Override
public void write(List<? extends Report> list) throws Exception {
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
for (Report report : list) {
entityManager.persist(report );
}
entityManager.getTransaction().commit();
}
}
Is it really needed that transaction should be maintained explicitly and spring batch doesn't control it out of box?
EDIT
I fixed it by changing writer like
public class DatabaseWriter implements ItemWriter<Report> {
#PersistenceContext
private EntityManager entityManager;
#Override
public void write(List<? extends Report> list) {
for (Report report : list) {
entityManager.persist(report );
}
}
Changing EntityMangerFactory to EntityManager with PersistenceContext fixed the problem. But i am struggling to understand reason for this behaviour
Create DAO and move your JPA code there and autowire the DAO in your writer.
Also make sure you autowire the entity manager like below.
#PersistenceContext
private EntityManager em;
But i am struggling to understand reason for this behaviour
The first approach does not work because you create a transaction manually while your code is actually running within the scope of a transaction driven by Spring Batch. So there will be two transactions with different contexts.
You should keep in mind that a tasklet is executed in a transaction driven by Spring Batch (including the item writer for a chunk-oriented tasklet). So any code running in that scope should conform to the transaction definition of the tasklet. In your case, the EntityManager injected in the writer is driven by the JpaTransactionManager you defined, which is also used by Spring Batch for the tasklet's transaction.
As a side note, you can use the JpaItemWriter provided by Spring Batch instead of writing a custom writer. The code is almost identical.

Connection pool replacement for already implemented Spring Jdbctemplate project

I am a doing a mid size project with spring jdbc and MsSQL server , project is almost 50% done , now when every request doing lots of inserts and updates specially with those tables which contains lots of columns and large datasets is performing very slow , and sometimes showing connection closed.
Now i am thinking to integrate C3p0 or similar connection pooling but i cant change any DAO code which i already done ..
I implemented a DAOHelper class with JDBCTemplate variable and injecting the JDBCTemplate dependency in applicationContext.xml with autowiring of DAOClass in controller class , and i extended this DAOHelper to all DAO classes and using this jdbcTemplate to do JDBC operations.
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/>
<property name="url" value="jdbc:sqlserver://192.168.1.101:1433;databaseName=OrderManager"/>
<property name="username" value="sa"/>
<property name="password" value="520759"/>
</bean>
<bean id="JdbcDataSource" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds"/>
</bean>
<bean id="OrderDAO" class="com.ordermanager.order.dao.OrderDAO" >
<property name="jdbcTemplate" ref="JdbcDataSource"/>
<property name="transactionManager" ref="transactionManager"/>
</bean>
#Controller
public class OrderController {
#Autowired
OrderDAO orderDAO;
#RequestMapping(value = "/addNewItem", method = RequestMethod.GET)
public ModelAndView addItem(#RequestParam("ParamData") JSONObject paramJson) {
ApplicationContext ctx = new FileSystemXmlApplicationContext(ConstantContainer.Application_Context_File_Path);
OrderDAO orderDAO = (OrderDAO) ctx.getBean("OrderDAO");
return new ModelAndView("MakeResponse", "responseValue", orderDAO.addItem(paramJson));
}
public class DAOHelper {
private JdbcTemplate jdbcTemplate;
private PlatformTransactionManager transactionManager;
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
public void setTransactionManager(PlatformTransactionManager txManager) {
this.transactionManager = txManager;
}
public JdbcTemplate getJdbcTemplate() /*I am using this Method for all JDBC Task*/ {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
Now with minimal code changes how can i integrate C3p0 or any good connection pooling library with my already written code.
Just change the ds bean in your config xml with following and consider adding other c3p0 properties according to your own. make sure to have c3p0 jar in your classpath.
<bean id="ds" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="jdbcUrl" value="jdbc:sqlserver://192.168.1.101:1433;databaseName=OrderManager" />
<property name="user" value="sa" />
<property name="password" value="520789" />
</bean>

Spring 3 MVC:java.lang.IllegalArgumentException: Property 'dataSource' is required.How to set JdbcTemplate correctly?

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();
}
}

#Autowired entityManagerFactory is null

My app can't autowire entityManagerFactory.
My applicationContext.xml:
<tx:annotation-driven/>
<context:component-scan base-package="top.level.package" />
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocation">
<value>classpath:jpa-persistence.xml</value>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
My java class:
#Component
public class Engine {
#Autowired
#Qualifier("entityManagerFactory")
private EntityManagerFactory entityManagerFactory;
......
}
Question:
Why entityManagerFactory is null?
For spring to do autowring using annotations you have to tell spring that. In your xml configuration (assuming you don't already have context:component-scan element) add a context:annotation-config. This will instruct the spring application context to scan for annotations (like #Autowired, #Inject, #Resource etc.) to do autowiring.
Also make sure that the class you want the EntityManagerFactory to be injected into (the Engine class) is a spring managed bean. Spring will only inject references into spring managed beans.
Have you tried with this ?
private EntityManagerFactory entityManagerFactory;
#Autowired
#PersistenceUnit(unitName = "myUnitName")
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
I had the same error some time ago, and I found this a solution.
If you craeate your Engine with new Engine() (as stated in one of your comments), it's not managed by Spring. #Component has no effect then and dependencies won't be injected. You need to inject your engine.

Bean property 'myDataSource' is not writable or has an invalid setter method

Getting the following error with this configuration in Spring beans:
<bean name="/login.htm" class="com.virtusa.web.EmployeeController">
<property name="service" ref="service"></property>
</bean>
<bean id="service" class="com.virtusa.service.ServiceIMP">
<property name="dao" ref="EmployeeDAO"></property>
</bean>
<bean id="EmployeeDAO" class="com.virtusa.dao.EmployeeDAO">
<property name="myDataSource" ref="myDataSource" />
</bean>
My spring config file is as follows:
private DataSource myDataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource myDataSource) {
this.myDataSource = myDataSource;
this.jdbcTemplate = new JdbcTemplate(myDataSource);
}
my dao
Since you have property name="myDataSource", your setter needs to be named setMyDataSource() rather than setDataSource().

Resources