Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Programmatic Registration of Java Configuration Beans

DZone's Guide to

Programmatic Registration of Java Configuration Beans

Migrating from XML configuration to Java configuration in Spring can be challenging sometimes. We take a look at a real-world example via Spring Security.

· Java Zone ·
Free Resource

Take 60 minutes to understand the Power of the Actor Model with "Designing Reactive Systems: The Role Of Actors In Distributed Architecture". Brought to you in partnership with Lightbend.

I have been working on refactoring the Spring Security Calendar application from an XML configuration to a Java configuration.

In the migration, the is a DefaultService.java file that is using UserDetailsManager, which extends UserDetailsService:

DefaultService:

@Repository
public class DefaultCalendarService implements CalendarService {
 
    ...
    private UserDetailsManager userDetailsManager;
 
    @Autowired
    public DefaultCalendarService(final EventDao eventDao,
                                  final CalendarUserDao userDao,
                                  final UserDetailsManager userDetailsManager) {
        ...


UserDetailsManager:

public interface UserDetailsManager extends UserDetailsService {
    ...


But, during the Autowire sequence, the Security Objects created from the WebSecurityConfigurerAdapter and used in other @Components can’t be found:
***************************
APPLICATION FAILED TO START
***************************
Description:
 
Parameter 2 of constructor in com.packtpub.springsecurity.service.DefaultCalendarService required a bean of type 'org.springframework.security.provisioning.UserDetailsManager' that could not be found.
 
Action:
 
Consider defining a bean of type 'org.springframework.security.provisioning.UserDetailsManager' in your configuration.


The crux of the issue is that with Java configuration and @Autowired-driven configuration, the configuration initialization ordering does not allow for Security Objects to be initialized before other @Component’s.

There is a JIRA ticket already discussing this issue, and eluding to a possible fix in Spring Security 5. I created a custom WebSecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity(debug = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {


Which has a method we can override to get access to the UserDetailsService as seen here:
@Bean
@Override
public UserDetailsService userDetailsService() {
    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
    manager.createUser(User.withUsername("user").password("password").roles("USER").build());
    manager.createUser(User.withUsername("admin").password("admin").roles("USER", "ADMIN").build());
    manager.createUser(User.withUsername("user1@example.com").password("user1").roles("USER").build());
    manager.createUser(User.withUsername("admin1@example.com").password("admin1").roles("USER", "ADMIN").build());
    return manager;
}


The issue is that we actually needed a UserDetailsManager not a UserDetailsService, so I changed the return type to UserDetailsManager as seen:

@Bean
@Override
public UserDetailsManager userDetailsService() {
    ...


Now we can successfully Autowire a UserDetailsManager into other @Components in our IoC.

Learn how the Actor model provides a simple but powerful way to design and implement reactive applications that can distribute work across clusters of cores and servers. Brought to you in partnership with Lightbend.

Topics:
java ,programmatic bean registration ,spring security ,java configurations ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}