-1

I'm learning Spring with Hibernate and making a demo project with simple login. I'm stuck with @Autowired giving NullPointerException. I'm not getting the correct reason behind it but I guess it's because Spring is not able to instantiate the bean on it's own.

There is problem only when I'm using customAuthenticationProvider for my login. If I use default <user-service> with username and password as admin, the code is running fine.

Here is my code,

web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
     http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

  <display-name>Archetype Created Web Application</display-name>

  <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
      <servlet-name>dispatcher</servlet-name>
      <url-pattern>/</url-pattern>
  </servlet-mapping>

  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
        /WEB-INF/spring-security.xml
      </param-value>
  </context-param>

  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

<!-- Spring Security -->
  <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>

  <context-param>
      <param-name>log4jConfigLocation</param-name>
      <param-value>classpath:log4j.properties</param-value>
  </context-param>

  <listener>
      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>

</web-app>

dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/mvc 
http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<mvc:annotation-driven />
<context:component-scan base-package="com.ssb" />
<context:annotation-config />

<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url"
        value="jdbc:mysql://localhost:3306/springHibernateDemo" />
    <property name="username" value="root" />
    <property name="password" value="admin" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.ssb.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

</beans>

spring-security.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security.xsd">

<http pattern="/resources/**" security="none" />

<http auto-config="true" use-expressions="true">
    <http-basic/>
    <intercept-url pattern="/login" access="permitAll"/>
    <intercept-url pattern="/**" access="isAuthenticated()" />
    <form-login login-page="/login" default-target-url="/home"
        authentication-failure-url="/login?error" login-processing-url="/j_spring_security_check"
        username-parameter="username" password-parameter="password" />
    <logout logout-success-url="/login?logout" logout-url="/j_spring_security_logout"/>
    <!-- enable csrf protection -->
    <csrf/>
</http>

<beans:bean id="customAuthenticationProvider"
    class="com.ssb.components.CustomAuthenticationProvider">
</beans:bean>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="admin" password="admin" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
    <authentication-provider ref="customAuthenticationProvider">
    </authentication-provider>
</authentication-manager>

</beans:beans>

CustomAuthenticationProvider.java

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    public AuthService authService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        authService.authenticateUser(authentication);
        // it never gets to this line as authService is null
        return new UsernamePasswordAuthenticationToken(authentication.getName(), "");
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }

}

HomeController.java

@Controller
public class HomeController {

  @Autowired
  HomeService homeService;

  @Autowired
  SessionFactory sessionFactory;

  @RequestMapping(value="/home", method=RequestMethod.GET)
  public String home(Model model){

      User user = new User();
      user.setName("test");
      user.setPassword("test");
      homeService.save(user);

      return "home";
  }

  @RequestMapping(value= "/login", method=RequestMethod.GET)
  public ModelAndView login(
          @RequestParam(value = "error", required = false) String error,
          @RequestParam(value = "logout", required = false) String logout) throws IOException {

          ModelAndView model = new ModelAndView();
          if (error != null) {
              model.addObject("error", "Invalid username and password!");
          }
          if (logout != null) {
            model.addObject("msg", "You've been logged out successfully.");
          }
          model.setViewName("login");
          return model;
      }

}

AuthServiceImpl.java

@Service
public class AuthServiceImpl implements AuthService{

  @Autowired
  HomeDao homeDao;

  @Transactional
  public void authenticateUser(Authentication authentication) {
    homeDao.authenticateUser(authentication);
  }

}

HomeDao.java

@Repository
public class HomeDao {

  @Autowired
  SessionFactory sessionFactory;

  public void save(User user){
      Session session = sessionFactory.getCurrentSession();
      Roles role = (Roles) session.get(Roles.class, 1);
      user.setRole_id(role);
      session.save(user);
  }

  public void authenticateUser(Authentication authentication) {
      Criteria criteria =  sessionFactory.getCurrentSession().createCriteria(User.class);
      criteria.add(Restrictions.eq("username", authentication.getPrincipal().toString()));
      criteria.add(Restrictions.eq("password", authentication.getCredentials().toString()));
      @SuppressWarnings("unchecked")
      List<User> result = criteria.list();
      System.out.println(result);

  }

}

error

SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/springAct] threw exception
java.lang.NullPointerException
at com.ssb.components.CustomAuthenticationProvider.authenticate(CustomAuthenticationProvider.java:20)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:192)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:93)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:120)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
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:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:495)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:767)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1347)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Rajeev
  • 113
  • 1
  • 2
  • 17
  • 2
    A Spring `@Autowired` cannot be `null` if that would be the case your application wouldn't even startup. It will only be `null` if you haven't setup annotation processing `context:component-scan` or `context:annotation-config` in your xml, or you are creating new instances of beans yourself. In your situation the first looks like the case. – M. Deinum Feb 05 '18 at 11:50
  • @M.Deinum Please look into **dispatcher-servlet.xml** . ```````` is there. – Rajeev Feb 05 '18 at 12:18
  • That is the context loaded for the `DispatcherServlet` not the one loaded by the `ContextLoaerListener` those don't influence each other with `Bean(Factory)PostProcessors`. – M. Deinum Feb 05 '18 at 13:41

2 Answers2

1

You are loading spring-security.xml as spring root context, and in this context there is not any context:component-scan, so it is absolutely normal to receive a NPE whilst trying to use an @Autowired bean in the root context which has been loaded in mvc context, which is a child context.

You could get more info in this answer: https://stackoverflow.com/a/30640404/4190848

To avoid this kind of error, I would do the following:

  1. In your dispatcher-servlet.xml just map in the context:component-scan @Controller mapped stereotypes.

For example:

<context:component-scan base-package="com.ssb.controller" />
  1. As you are using just spring-security.xml as root-context, there you should map any other stereotypes mapped with @Service, @Repository or @Component.

For example:

<context:component-scan base-package="com.ssb.repositories" />
<context:component-scan base-package="com.ssb.services" />
  1. As well, you should move some beans defined in dispatcher-servlet.xml into spring-security.xml.

Just these:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <property name="url"
        value="jdbc:mysql://localhost:3306/springHibernateDemo" />
    <property name="username" value="root" />
    <property name="password" value="admin" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.ssb.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

So that, the resulting dispathcer-servlet.xml and spring-security.xml should be just like this, only setting correct packages in context:component-scan base-packages:

dispatcher.servlet.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.0.xsd
       http://www.springframework.org/schema/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven />
    <context:component-scan base-package="com.ssb.controller" />
    <context:annotation-config />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

spring-security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://www.springframework.org/schema/security"
  xmlns:tx="http://www.springframework.org/schema/tx" 
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security 
    http://www.springframework.org/schema/security/spring-security.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <context:component-scan base-package="com.ssb" />

    <beans:bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
    destroy-method="close">
        <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <beans:property name="url"
        value="jdbc:mysql://localhost:3306/springHibernateDemo" />
        <beans:property name="username" value="root" />
        <beans:property name="password" value="admin" />
    </beans:bean>

    <beans:bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <beans:property name="dataSource" ref="dataSource" />
        <beans:property name="packagesToScan" value="com.ssb.model" />
        <beans:property name="hibernateProperties">
            <beans:props>
                <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
                <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
                </beans:prop>
                <beans:prop key="hibernate.show_sql">true</beans:prop>
            </beans:props>
        </beans:property>
     </beans:bean>

    <tx:annotation-driven transaction-manager="transactionManager" />

    <beans:bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <beans:property name="sessionFactory" ref="sessionFactory" />
    </beans:bean>

    <http pattern="/resources/**" security="none" />

    <http auto-config="true" use-expressions="true">
        <http-basic />
        <intercept-url pattern="/login" access="permitAll" />
        <intercept-url pattern="/**" access="isAuthenticated()" />
        <form-login login-page="/login" default-target-url="/home"
        authentication-failure-url="/login?error" login-processing-url="/j_spring_security_check"
        username-parameter="username" password-parameter="password" />
        <logout logout-success-url="/login?logout" logout-url="/j_spring_security_logout" />
        <!-- enable csrf protection -->
        <csrf />
    </http>

    <beans:bean id="customAuthenticationProvider"
        class="com.ssb.components.CustomAuthenticationProvider">
    </beans:bean>

    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user name="admin" password="admin" authorities="ROLE_USER" />
            </user-service>
        </authentication-provider>
        <authentication-provider ref="customAuthenticationProvider">
        </authentication-provider>
    </authentication-manager>

</beans:beans>
Rajeev
  • 113
  • 1
  • 2
  • 17
jlumietu
  • 6,234
  • 3
  • 22
  • 31
0

try with placing context:component-scan base-package="com.ssb" at end of dispatcher-servlet.xml it may work because while placing beans in ioc container it need dependency, so while creating AuthService bean it need dependency classes which are not at been created in IOC container.Ensure all dependencies configure proper order

balu
  • 444
  • 1
  • 3
  • 10