Problems with Autowired and Spring Injection
autowired, code-injection, java, spring-mvc
Solution
Eventhough you have solved this issue, the solution is ugly in terms of Spring Dependency Injection and Inversion of Control theories.
Basically you should never use the `new` keyword to instantiate objects if you are using Spring. Because all objects must be instantiated and injected only by the Spring Container.
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<context:annotation-config />
<context:spring-configured />
<context:component-scan base-package="com.agrichem.server" />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="WEB-INF/jdbc.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="securityDao"
class="com.agrichem.server.model.repositories.impl.SecurityDaoImpl">
</bean>
<bean id="customerService"
class="com.agrichem.server.path.to.service.CustomUserDetailsService">
</bean>
</beans>
WebSecurityConfig.java
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService customUserDetailsService
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(customUserDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/home/logout.do").permitAll()
.anyRequest().authenticated().and().formLogin()
.loginPage("/home/login.do").permitAll()
.failureUrl("/home/accessdenied.do").permitAll();
}
}
And you should have a Default Constructor for `CustomUserDetailsService` which doesn't take in any arguments. All your `@Autowired` properties should be inject by the spring container.
Furthermore you are intermixing Spring Java Configuration and Spring XML Configuration which is fine, but it is better if you decide on one particular method to define your beans.
Problem
SOLVED Lately I've been having problems with an Spring MVC application which I'm trying to develop. The main problem is that I don't know exactly why the @Autowired annotation is not working properly and that's probably because I have something wrong. I'm going to post here my code so you can help me with my issue! Thanks a lot guys: web.xml ``` <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <display-name>HelloWorld Application</display-name> <description> This is a simple web application with a source code organization based on the recommendations of the Application Developer's Guide. </description> <servlet> <servlet-name>webDispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>webDispatcher</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext.xml </param-value> </context-param> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> ``` applicationContext.xml ``` <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:annotation-config /> <context:spring-configured /> <context:component-scan base-package="com.agrichem.server" /> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="classpath:messages" /> <property name="defaultEncoding" value="UTF-8" /> </bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="WEB-INF/jdbc.properties" /> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation"> <value>classpath:hibernate.cfg.xml</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${jdbc.dialect}</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <bean id="securityDao" class="com.agrichem.server.model.repositories.impl.SecurityDaoImpl"> </bean> </beans> ``` webDispatcher-servlet.xml ``` <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd"> <context:annotation-config /> <context:spring-configured /> <context:component-scan base-package="com.agrichem.server" /> <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <property name="prefix" value="/views/"/> <property name="suffix" value=".jsp"/> </bean> <!-- <import resource="spring-security-web.xml"/> --> </beans> ``` SecurityDao.java ``` public interface SecurityDao { public boolean validateUser(User user); public User authenticateUser(User user); public User getUser (User user); } ``` SecurityDaoImpl.java ``` @Repository("securityDao") public class SecurityDaoImpl extends HibernateDao implements SecurityDao { public SecurityDaoImpl() { super(); } @Override public boolean validateUser(User user) { Query query = openSession() .createQuery( "from User u where u.login = :login and u.password = :password"); query.setParameter("login", user.getLogin()); query.setParameter("password", user.getPassword()); return (query.list().size() > 0) ? true : false; } @Override public User authenticateUser(User user) { Query query = openSession() .createQuery( "from User u where u.login = :login and u.password = :password"); query.setParameter("login", user.getLogin()); query.setParameter("password", user.getPassword()); return (User) query.uniqueResult(); } @Override public User getUser(User user) { Query query = openSession().createQuery( "from User u where u.login = :login"); query.setParameter("login", user.getLogin()); return (User) query.uniqueResult(); } } ``` WebSecurityConfig.java ``` @Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(new CustomUserDetailsService()); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests().antMatchers("/home/logout.do").permitAll() .anyRequest().authenticated().and().formLogin() .loginPage("/home/login.do").permitAll() .failureUrl("/home/accessdenied.do").permitAll(); } } ``` CustomUserDetailsService.java ``` @Configurable @Transactional public class CustomUserDetailsService implements UserDetailsService { @Autowired @Qualifier("securityDao") private SecurityDao securityDAO; @Override public UserDetails loadUserByUsername(String arg0) throws UsernameNotFoundException { com.agrichem.server.model.security.User user = securityDAO .getUser(new com.agrichem.server.model.security.User(arg0, "")); User userDetails = new User(user.getLogin(), user.getPassword(), getGrantedAuthorities(user.getRoles())); return userDetails; } public static List<GrantedAuthority> getGrantedAuthorities(Set<Role> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); for (Role role : roles) { authorities.add(new SimpleGrantedAuthority(role.getName())); } return authorities; } public SecurityDao getSecurityDAO() { return securityDAO; } public void setSecurityDAO(SecurityDao securityDAO) { this.securityDAO = securityDAO; } } ``` In this point when I try to login to the application and I'm gonna check the Dao to access to the database I'm getting the 'securityDao' property null. Exactly in CustomUserDetailsService in the following line : com.agrichem.server.model.security.User user = securityDAO.getUser(new com.agrichem.server.model.security.User(arg0, "")); and obvisously I'm getting a NullPointerException. ``` org.springframework.security.authentication.InternalAuthenticationServiceException at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:110) at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177) at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94) at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.NullPointerException at com.agrichem.server.services.security.CustomUserDetailsService.loadUserByUsername(CustomUserDetailsService.java:35) at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:102) ... 36 more ``` Solution: Found it! The problem was that in WebSecurityConfig I was doing the following: ``` @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(**new CustomUserDetailsService()**); } ``` and then the new instance of CustemUserDetailsService was out of the Spring Control. To solve it I added in CustomUserDetailsService a constructor: ``` private SecurityDao securityDAO; public CustomUserDetailsService(SecurityDao securityDAO) { super(); this.securityDAO = securityDAO; } ``` and I modified WebSecurityConfig in this way: ``` @Autowired private SecurityDao securityDao; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(new CustomUserDetailsService(securityDao)); } ``` Thanks anyway for your help!