It's been 3rd day I've been trying to implement a simple CRUD application using Mybatis XML configuration and I'm new to the whole Spring ecosystem. The question is a bit long but I've only sharec the essentials.
I have a class Employee.java:
import lombok.*;
#Getter #Setter #AllArgsConstructor #NoArgsConstructor #ToString
public class Employee {
private long emp_Id;
private String emp_name;
private String emp_dept;
}
Then I wrote a Mapper
#Mapper
public interface EmployeeMapper {
public Employee getEmployee(#Param("emp_Id") Long emp_Id);
public List<Employee> getAllEmployee();
}
Then I wrote a mapper XML named EmployeeMapper.xml
...
<mapper namespace="Employee">
<select id="getAllEmployee" resultType="com.tmb.mybatiscrudproj.domains.Employee">
select * from employee
</select>
<select id="getEmployee" resultType="com.tmb.mybatiscrudproj.domains.Employee">
select * from employee where emp_Id = #{emp_Id}
</select>
</mapper>
Then I have written a service:
public interface EmployeeService {
public Employee getEmployee(Long emp_Id);
public List<Employee> getAllEmployee();
}
and here is the service implementation:
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
EmployeeMapper employeeMapper;
#Override
public List<Employee> getAllEmployee() {
List<Employee> list = employeeMapper.getAllEmployee();
return list;
}
#Override
public Employee getEmployee(Long emp_Id) {
return employeeMapper.getEmployee(emp_Id);
}
}
and finally the controller class
#RestController
#RequestMapping("/employee")
public class EmployeeController {
#Autowired
EmployeeService empService;
#RequestMapping(value="/getEmp/{empId}",method = RequestMethod.GET)
public Employee getEmployee(#PathVariable Long empId){
return empService.getEmployee(empId);
}
#GetMapping(value="/getAllEmp")
public List<Employee> getAllEmployee(){
return empService.getAllEmployee();
}
I'm confused about the configurations. As I have a built-in application.properties inside the resources older and in it I have:
server.port: 8081
spring.h2.console.enabled=true
spring.h2.console.path=/h2
spring.datasource.url=jdbc:h2:~/test
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
mybatis.config-location=classpath:mapper/mybatisConfig.xml
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
mybatis.type-aliases-package=com.tmb.mybatiscrudproj.domains
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30
Following many tutorials and answers, I created a mybatisConfig.xml and EmployeeMapper.xml file is also inside the `resources folder.
In the mybatisConfig.xml I've done almost the same thing as I did in .properties file
...
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="org.h2.Driver"/>
<property name="url" value="jdbc:h2:~/test"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
<property name="path" value="/h2"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="EmployeeMapper.xml"/>
</mappers>
</configuration>
Here is the screenshot of the project structure:
when I run the project I get the following errors:
Error creating bean with name 'employeeController': Unsatisfied dependency expressed through field 'empService';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeServiceImpl': Unsatisfied dependency expressed through field 'employeeMapper';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'employeeMapper' defined in file [MY_PATH/mybatiscrudproj/target/classes/com/tmb/mybatiscrudproj/mapper/EmployeeMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [org/mybatis/spring/boot/autoconfigure/MybatisAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is java.lang.IllegalStateException: Property 'configuration' and 'configLocation' can not specified with together
Now based on the searches I have done I made sure the in the main class I add:
#MappedTypes({Employee.class})
#MapperScan("com.tmb.mybatiscrudproj.mapper")
#SpringBootApplication
public class MybatiscrudprojApplication {
public static void main(String[] args) {
SpringApplication.run(MybatiscrudprojApplication.class, args);
}
}
but still the same error. How can I successfully configure the project with the structure I have shared in this question?
Your "employeeMapper" is not declared as a spring bean, so when dependency injection, there's no bean with this type. Try adding a #Component on your class.
Related
I am building a REST API and can't seem to get rid of the org.springframework.beans.factory.UnsatisfiedDependencyException, I can't spot the issue in this. I will appreciate a fresh insight into this.
p.s: Using mongo DB for this
first off the full error
2020-05-04 01:16:31.468 WARN 14412
--- [ main] ConfigServletWebServerApplicationContext :
Exception encountered during context initialization -
cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'productController':
Unsatisfied dependency expressed through field 'productService';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'productServiceImpl':
Unsatisfied dependency expressed through field 'productRepo';
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'productRepo':
Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException:
No property id found for type Product!
public class Product {
#Id
private int ProductId;
// and other variables plus setters and getters
#Repository
public interface ProductRepo extends MongoRepository<Product, String> {
// methods
}
public interface ProductService {
// methods
}
#Service
public class ProductServiceImpl implements ProductService {
#Autowired
private ProductRepo productRepo;
// implementations
}
Try changing the Product class as the following:
#Entity
public class Product {
#Id
private String productId; // MongoRepository<Product, String>
// methods
}
In the Product class the #Entity annotation is missing and the productId should be a String, as specified in the repository.
Or change to extends MongoRepository<Product, Integer> if you want to keep the current field type.
In any case, they should match.
Make You That Your Spring Application Knows Where Your Classes Resides.
Use #ComponentScan(basePackages = "com.package").
Moreover If Your Product Class Is Something That You Want to Persist Mark It With #Entity So Spring Knows about It And Creates A Bean Out Of it.
Mark Your interface ProductService with #service, So that Spring Knows About it.
I have created a simple maven project using SpringBoot and MongoDB. I have two repository implementations i.e. StudentRepository and StudentRepositoryCustom. StudentRepository extends in built MongoRepository and the custom repository. The custom repository methods are implemented in StudentRepositoryImpl. The applications runs without errors when I put StudentRepository, StudentRepositoryCustom and StudentRepositoryImpl in same package i.e. com.aman.springboot.repository. But the application throws error when the implementation class is moved to some other package let's say com.aman.springboot.impl.
What am I doing wrong ?
Here's the main class:
package com.aman.springboot.client;
#SpringBootApplication(scanBasePackages = "com.aman.springboot")
public class ApplicationLauncher {
public static void main(String[] args) {
SpringApplication.run(StudentController.class, args);
}
}
Here's RestController class:
package com.aman.springboot.controller;
#RestController
#EnableAutoConfiguration
#EnableMongoRepositories(basePackages = "com.aman.springboot.repository")
#RequestMapping(value = "/student")
public class StudentController {
#Autowired
private StudentRepository studentRepository;
#RequestMapping(value = "/getStudent", method = RequestMethod.GET)
public StudentRepo getStudent(#RequestParam(required = true) int id) {
return studentRepository.findStudentById(id);
}
#RequestMapping(value = "/removeStudent", method = RequestMethod.POST)
public void removeStudent(#RequestBody(required = true) StudentRepo
studentRepo) {
studentRepository.deleteStudent(studentRepo);
}
}
Here's StudentRepository:
package com.aman.springboot.repository;
#Repository
public interface StudentRepository extends MongoRepository<StudentRepo,
String>, StudentRepositoryCustom {
public StudentRepo findStudentById(int id);
}
Here's StudentRepositoryCustom:
package com.aman.springboot.repository;
public interface StudentRepositoryCustom {
public void deleteStudent(StudentRepo studentRepo);
}
Here's StudentRepositoryImpl:
package com.aman.springboot.impl;
#Service
public class StudentRepositoryImpl implements StudentRepositoryCustom{
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private StudentRepo student;
#Override
public void deleteStudent(StudentRepo studentRepo) {
mongoTemplate.remove(studentRepo);
}
}
As you can see both interfaces or repositories are in same package but the implementation class for StudentRepositoryCustom interface is in different package. In this case the application throws error while deploying:
Here's the stack trace:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error
creating bean with name 'studentController': Unsatisfied dependency
expressed through field 'studentRepository'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'studentRepository': Invocation of init method failed; nested
exception is org.springframework.data.mapping.PropertyReferenceException: No
property deleteStudent found for type StudentRepo! at
org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject
(AutowiredAnnotationBeanPostProcessor.java:586)
~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE] at
org.springframework.beans.factory.annotation.InjectionMetadata.inject
(InjectionMetadata.java:91) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at
org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues
(AutowiredAnnotationBeanPostProcessor.java:372) ~[spring-beans-
5.0.8.RELEASE.jar:5.0.8.RELEASE] at
.
.
.
.
org.springframework.boot.SpringApplication.run(SpringApplication.java:1246)
[spring-boot-2.0.4.RELEASE.jar:2.0.4.RELEASE] at
com.aman.springboot.client.ApplicationLauncher.main
(ApplicationLauncher.java:17) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'studentRepository': Invocation of init method
failed; nested exception is
org.springframework.data.mapping.PropertyReferenceException: No property
deleteStudent found for type StudentRepo! at
org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory.initializeBean
(AbstractAutowireCapableBeanFactory.java:1699) ~[spring-beans-
5.0.8.RELEASE.jar:5.0.8.RELEASE] at
.
.
.
.
tializeBean(AbstractAutowireCapableBeanFactory.java:1695) ~[spring-beans-
5.0.8.RELEASE.jar:5.0.8.RELEASE] ... 29 common frames omitted
The application works fine if I move the StudentRepositoryImpl class to package in which the repositories are i.e. com.aman.springboot.repository.
Any help would be appreciated !!! Thanks.
I solved my problem by refactoring the package structure for custom repository and its implementation class. What I understand from the problem is Spring looks for implemented classes for repositories in child packages.
For example, if repository is defined in com.foo.repo, it's implementing class should be in com.foo.repo.impl.
The repositories should be defined in top level packages and the implementing class should be in same package or it's child package.
I need a help regarding dependency injection.
I hava a bean class which is having a object reference of JdbcTemplate and I am using #Autowired to
create instance of that object. But that object is not getting loaded and as a result NullPointerException is thrown
from setCustName() method.
Please help
Bean Class :
class CustomerBean {
private String custName;
#Autowired
private JdbcTemplate jdbcTemplate;
public void setCustName(String custName) {
this.custName = custName;
jdbcTemplate.update(query);
}
}
XML :
<bean id="myjdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="custBean" class="com.test.CustomerBean">
<property name="custName" value="John" />
</bean>
Stacktrace:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'custName' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:334)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1419)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1160)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
you get NullPointerException as jdbcTemplate is null / not injected.
if you describe bean custBean by xml , as you did, you should add :
< property name="jdbcTemplate" value="myjdbcTemplate" /> for inject jdbcTemplate into your bean.
you have mixed configuration - xml and annotation. in your xml should be :
<context:component-scan base-package="package....." />
to support #Autowired and CustomerBean should be #service or #component.
vaiant1 :
add into xml and
#Component
class CustomerBean {
private String custName;
#Autowired
private JdbcTemplate jdbcTemplate;
public void setCustName(String custName) {
this.custName = custName;
jdbcTemplate.update(query);
}
}
variant2 :
class CustomerBean {
private String custName;
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
this.jdbcTemplate = jdbcTemplate;
}
public void setCustName(String custName) {
this.custName = custName;
jdbcTemplate.update(query);
}
}
and xml
<bean id="custBean" class="com.test.CustomerBean">
<property name="custName" value="John" />
<property name="jdbcTemplate" ref="myjdbcTemplate" />
</bean>
Add #Component annotation to the bean class which contains beans that can be autowired.
After adding the above #Component annotation on beans, we need to tell spring to scan these respective beans and load all the autowired dependencies. This can be done by declaring the following XMLconfiguration
<context:component-scan base-packages="<your_package_names>"/>
for example if my package structure is com.mycompany
<context:component-scan base-packages="com.mycompany"/>
Use <context:annotation-config> which enables the usage of different annotations in bean classes.
Also I strongly recommend against usage of different dependencies in properties setters. In your code sample you assume that the jdbcTemplate was autowired before the call of the setter, fact that you cannot be sure of.
Therefore the logic that you placed in the setter, regarding the jdbc template would be more properly placed in a method annotated with #PostConstruct.
I created an interface and a class:
public interface UserService {
List<User> listAll();
}
#Transactional
public class DefaultUserService implements UserService {
private String tableName;
public List<User> listAll() { someDao.listAllFromTable(tableName); }
public void setTableName(String tableName) { this.tableName = tableName; }
}
Also in my application context xml file context.xml, I defined:
<bean id="userService" class="mypackage.DefaultUserService">
<property name="tableName" value="myusers" />
</bean>
Then I want to test the DefaultUserService:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:context-test.xml"})
#TransactionConfiguration(transactionManager = "testTransactionManager")
#Transactional
public class UserServiceTest {
#Autowired
private DefaultUserService userService;
#Before
public void setup() {
userService.setTableName("mytesttable");
}
#Test
public void test() {
// test with userService;
userService.listAll();
}
}
Notice it uses context-test.xml, which imported the original context.xml:
<import resource="classpath:context.xml"/>
Unfortunately, when the test starts, spring throws exception:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'mypackage.UserServiceTest':
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field:
private mypackage.DefaultUserService mypackage.userService
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [mypackage.DefaultUserService] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
I'm not sure where is wrong, why spring can't find the bean DefaultUserService I defined?
It's because #Transactional places the bean is behind a jdk proxy implementing UserService interface, after that the bean is only available as UserService and not DefaultUserService.
See https://stackoverflow.com/a/18875681/241986.
You can try setting the table name with a property placeholder #Value("${someprop}") and define that property in test context, or create another interface that will expose setTableName(), and autowire that helper interface into the test case.
I'm not sure there are any easy solutions of the problem, I think this task can be subsumed under the problem of bean redefinition in Spring test-context framework
Spring beans redefinition in unit test environment
Try to replace the class DefaultUserService to the interface UserService
public class UserServiceTest {
#Autowired
private UserService userService;
....
}
You have not defined the getter for your property tableName in your implementing class.Spring IOC container works on the POJO model
I´m pretty new to Spring, and I´m currently struggling with an exception being thrown when I´m attempting to extend JdbcUserDetailsManager since I need additional features besides the ones provided. The class signature looks looks like this, with a default constructor.
#Repository
public class PrimeUserDetailsManager extends JdbcUserDetailsManager implements CustomUserDetailsManager {
public static String CUSTOM_USERS_BY_USERNAME_QUERY = "select username,password,enabled from users where username like ?%";
public static String FIND_ALL_USERS_QUERY = "select username,password,enabled from users";
#Override
public List<UserDetails> loadUsersByUsername(String username) {
return super.loadUsersByUsername(username);
}
#Override
public List<UserDetails> findAllUsers() {
return getJdbcTemplate().query(FIND_ALL_USERS_QUERY, new RowMapper<UserDetails>() {
public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
boolean enabled = rs.getBoolean(3);
return new User(username, password, enabled, true, true, true, AuthorityUtils.NO_AUTHORITIES);
}
});
}
}
}
My custom Interfaces looks like this:
public interface CustomUserDetailsManager extends UserDetailsManager {
public List<UserDetails> loadUsersByUsername(String username);
public List<UserDetails> findAllUsers();
}
Simple autowire:
#Service("userService")
public class UserServiceImpl implements UserService{
#Autowired
public UserServiceImpl(CustomUserDetailsManager customUserDetailsManager) {
this.customUserDetailsManager = customUserDetailsManager;
}
private CustomUserDetailsManager customUserDetailsManager;
....
}
And in my ApplicationContext, I have this:
<beans:bean id="jdbcUserService" class="org.primefaces.examples.moviecollector.custom.PrimeUserDetailsManager">
<beans:property name="dataSource" ref="dataSource"/>
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="enableGroups" value="true"/>
<beans:property name="enableAuthorities" value="false"/>
</beans:bean>
Still, when staring my application, I get the exception below, so apperently I must have missed something? Can someone please tell me what?
Complete stacktrack:
2011-sep-07 13:08:49 org.apache.catalina.core.StandardContext listenerStart
ALLVARLIG: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userBean' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\beans\UserBean.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.security.provisioning.GroupManager]: : Error creating bean with name 'primeUserDetailsManager' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\custom\PrimeUserDetailsManager.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primeUserDetailsManager' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\custom\PrimeUserDetailsManager.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1003)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:907)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4701)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5204)
at org.apache.catalina.core.StandardContext$1.call(StandardContext.java:5199)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'primeUserDetailsManager' defined in file [C:\Program\springsource\vfabric-tc-server-developer-2.5.0.RELEASE\Localhost\wtpwebapps\prime-sweet\WEB-INF\classes\org\primefaces\examples\moviecollector\custom\PrimeUserDetailsManager.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:844)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:786)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
... 23 more
Caused by: java.lang.IllegalArgumentException: 'dataSource' or 'jdbcTemplate' is required
at org.springframework.jdbc.core.support.JdbcDaoSupport.checkDaoConfig(JdbcDaoSupport.java:112)
at org.springframework.dao.support.DaoSupport.afterPropertiesSet(DaoSupport.java:44)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 34 more
EDIT:
I´ve included the entire body of PrimeUserDetailsManager above. Here´s the dataSource definition:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="${database.driver}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
You've got two beans. One is defined in XML. There's another one being created because you've annotated your class with #Repository. That's the one giving you the trouble because you haven't given it any instructions about wiring the required "'dataSource' or 'jdbcTemplate'". Note in the exception that the bean's name is given as "primeUserDetailsManager". That's the lower-cased simple class name, which is the default name for beans created via component scanning with annotations.
I create an intermediate JdbcDaoSupport derived super class that all my DAO classes extend from that looks like this:
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class MyJdbcDaoSupport extends JdbcDaoSupport {
#Autowired private DataSource dataSource;
#PostConstruct
private void initialize() {
setDataSource(dataSource);
}
}
This assumes you have a data source bean with id "dataSource", as shown by the OP.
Works for me in Spring 4.x but should work with earlier versions too.
The only way I managed to solve is by defining following in my DAO.
private SimpleJdbcTemplate simpleJdbcTemplate;
protected SimpleJdbcTemplate getSimpleJdbcTemplate() {
return simpleJdbcTemplate;
}
#Autowired
public void setDataSource(DataSource dataSource) {
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
It seems the SimpleJdbcDaoSupport does not have #Autowired annotation to its setDataSource method.
This works even in spring 2.5
/**
* Sets the parent class DataSource to the auto-wired data source.
*
*
*/
#Autowired
public void setParentDataSource(
#Qualifier("dataSource") DataSource dataSource) {
super.setDataSource(dataSource);
}