0

I have problem with Spring autowire. I'm trying to use Autowire to inject repository, which by the way already works when I'm injecting it into the controller, into authentication service. For further reference I'm adding relevant code and error.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>Restful Web Application</display-name>


     <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            enterprise.util.SpringSecurityConfig
        </param-value>
    </context-param>

    <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>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>


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

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

    <servlet-mapping>
        <servlet-name>restEnterprise</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>




</web-app>

restEnterpise-servlet.xml -- EmployeeRepository is in dbService

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="enterprise.service" />
    <context:component-scan base-package="enterprise.controller" />
    <context:component-scan base-package="enterprise.util" />
    <context:component-scan base-package="dbService" />

    <mvc:annotation-driven />

</beans>

SpringSecurityConfig.java

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    private final TokenAuthenticationService tokenAuthenticationService; //handles adding auth token to response and checking for auth header in requests
    private final EmployeeDetailsService employeeDetailsService;
    public SpringSecurityConfig() {
        super(true);
        tokenAuthenticationService = new TokenAuthenticationService("tooManySecrets");
        employeeDetailsService = new EmployeeDetailsService();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
      web
        .debug(true);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .exceptionHandling().and()
                .anonymous().and()
                .servletApi().and()
                .headers().cacheControl().and().and()
                .authorizeRequests()

                // Allow anonymous logins
                .antMatchers("/auth/**").permitAll()

                // All other request need to be authenticated
                .anyRequest().authenticated().and()

                // Custom Token based authentication based on the header previously given to the client
                .addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService), UsernamePasswordAuthenticationFilter.class);
    }

//http://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.html

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    @Override
    public EmployeeDetailsService userDetailsService() { 
        return employeeDetailsService;
    }

//--------------

    @Bean
    public TokenAuthenticationService tokenAuthenticationService() {
        return tokenAuthenticationService;
    }
}

EmployeeDetailsService.java

@Component
public class EmployeeDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {

    @Autowired
    private EmployeeRepository employeeRep;

    @Override
    public final UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Employee employee = employeeRep.findByLogin(username);
        if (employee == null) {
            throw new UsernameNotFoundException("Employee not found");
        }
        List<GrantedAuthority> authorities = buildUserAuthority(employee.getRole());
        return buildUserForAuthentication(employee, authorities);
    }

    // Converts Employee to
    // org.springframework.security.core.userdetails.User
    private User buildUserForAuthentication(Employee user, 
        List<GrantedAuthority> authorities) {
        return new User(user.getLogin(), user.getPassword(), 
            true, true, true, true, authorities);
    }

    private List<GrantedAuthority> buildUserAuthority(String userRole) {

        Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();

        setAuths.add(new SimpleGrantedAuthority("ROLE_" + userRole.toUpperCase()));

        List<GrantedAuthority> Result = new ArrayList<GrantedAuthority>(setAuths);

        return Result;
    }

}

Error during deploy

2015-08-18 10:15:34,389 ERROR [org.jboss.as.controller.management-operation]     (management-handler-thread - 1) JBAS014613: Operation ("redeploy") failed - address: ([("deployment" => "enterprise.war")]) - failure description: {"JBAS014671: Failed services" => {"jboss.undertow.deployment.default-server.default-host./enterprise" => "org.jboss.msc.service.StartException in service jboss.undertow.deployment.default-server.default-host./enterprise: Failed to start service
    Caused by: java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userDetailsService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private dbService.dao.EmployeeRepository enterprise.service.EmployeeDetailsService.employeeRep; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [dbService.dao.EmployeeRepository] 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)}

As I've said - this autowire works when I'm using it in controller but not in EmployeeDetailsService.

Roman C
  • 49,761
  • 33
  • 66
  • 176
Krzysztof Piszko
  • 1,355
  • 3
  • 12
  • 17
  • Where is the class which implements/extends `dbService.dao.EmployeeRepository`? – Aakash Aug 18 '15 at 08:45
  • Is `dbService.dao.EmployeeRepository` annotated as repository? – Jens Aug 18 '15 at 08:49
  • Why are you using new to instantiate EmployeeDetailsService.? Using new creates an instance outside of spring container – jozzy Aug 18 '15 at 08:52
  • EmployeeRepository is JPA interface. As i've said it's been working when used in RestController so I don't think the problem lies on this side. @jozzy I see! That indeed might be the case. How else would I instantiate it? By declaring it as a bean in servlet? – Krzysztof Piszko Aug 18 '15 at 08:54

3 Answers3

1

Instead of instantiating EmployeeService using new, you should let spring container do the instantiation and the wiring.

You can autowire your employeeservice as

 @AutoWired
 private final EmployeeDetailsService employeeDetailsService;

and remove the new Instantiation from constructor and also remove the @Bean annotation from userDetailsService() method

UPDATED

If you have a main spring context xml import it to the config class as shown below

@Configuration
@ImportResource("restEnterpise-servlet.xml")
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter

If you don't have any spring xml's you can add the componentscan annotation to discover spring components @ComponentScan

jozzy
  • 2,863
  • 3
  • 15
  • 12
  • When I do your fix, I get `ERROR Context initialization failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityConfig': Injection of autowired dependencies failed; (...) Could not autowire field: private enterprise.service.EmployeeDetailsService enterprise.util.SpringSecurityConfig.employeeDetailsService;(...)No qualifying bean of type [enterprise.service.EmployeeDetailsService] found for dependency:(...)` It would seem that G. Trubach is right. It's an issue with loading stuff. – Krzysztof Piszko Aug 18 '15 at 10:22
  • Thank you very much! Your update and original post helped me solve this issue – Krzysztof Piszko Aug 18 '15 at 12:21
0

If your Repository extends JpaRepository then you need to use @Resource in place of @Autowired in your EmployeeDetailsService

Nicholas Robinson
  • 1,359
  • 1
  • 9
  • 20
0

This link will be helpfull.

Your services declared in restEnterpise-servlet.xml and you want to use EmployeeRepository. But security config loaded before your servlet config. So you need to create another spring config where will be declared all component scan and that will be loaded before security config. For example spring-config.xml

 <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="enterprise.service" />
    <context:component-scan base-package="enterprise.controller" />
    <context:component-scan base-package="enterprise.util" />
    <context:component-scan base-package="dbService" />

    <mvc:annotation-driven />

</beans>

In web.xml

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring-config.xml
            enterprise.util.SpringSecurityConfig
        </param-value>
    </context-param>

I hope this will help you.

Community
  • 1
  • 1
  • Yeah, could be it. Problem is, that when I use your solution, I get `2015-08-18 12:06:49,467 INFO [org.springframework.web.context.support.AnnotationConfigWebApplicationContext] (MSC service thread 1-1) No annotated classes found for specified class/package [/WEB-INF/spring-beforeSecurityLoad.xml`. Do you know why it can't find anything? – Krzysztof Piszko Aug 18 '15 at 10:08
  • What is in `spring-beforeSecurityLoad.xml`? Try to read this [post](http://stackoverflow.com/questions/8075790/how-to-register-spring-configuration-annotated-class-instead-of-applicationcont). –  Aug 18 '15 at 10:20
  • I simply copied and pasted component scans from servlet config. – Krzysztof Piszko Aug 18 '15 at 10:23
  • Try to read this [post](http://stackoverflow.com/questions/8075790/how-to-register-spring-configuration-annotated-class-instead-of-applicationcont). It maybe will helpfull. –  Aug 18 '15 at 10:24
  • The problem related with annotated config. –  Aug 18 '15 at 10:31