Search code examples
javaspringspring-bootjpaspring-data-jpa

Spring Repository won't instantiate/autowire in Configuration class


I've been building a project app and wanted to include JWT security. I followed along with a tutorial and have an issue with this code snippet.

@Configuration
@RequiredArgsConstructor
public class ApplicationConfig {

    private final UserRepository repository;

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> repository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setUserDetailsService(userDetailsService());
        authProvider.setPasswordEncoder(passwordEncoder());
        return authProvider;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

I receive this error:

ApplicationConfig.java:21: error: variable userRepository not initialized in the default constructor
    private final UserRepository userRepository;
                                 ^

From extensive googling/stackoverflow reading I believe that the repository isn't getting instantiated by Spring before Spring loads this configuration class. I've tried auto wiring the repository, among other things.

I've seen no one else post this issue on the GitHub page that I followed and I'm unsure how to fix, advice welcome!

Other relevant code snippets following:

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
        Optional<User> findByUsername(String username);
}
@SpringBootApplication
@EnableConfigurationProperties(ConfigProperties.class)
@EnableJpaRepositories("com.browna.teller_back.repositories")
public class TellerBackApplication {

    public static void main(String[] args) {
        SpringApplication.run(TellerBackApplication.class, args);
    }

}

User entity class

@Builder
@Entity
@Table(name = "users",
        uniqueConstraints = {
                @UniqueConstraint(columnNames = "username"),
                @UniqueConstraint(columnNames = "email")
        })
public class User implements UserDetails {

    @Getter
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotBlank
    @Size(max = 20)
    private String username;

    @NotBlank
    @Size(max = 50)
    @Email
    private String email;

    @NotBlank
    @Size(max = 120)
    private String password;

    @Enumerated(EnumType.STRING)
    private Role role;

    public User() {
    }

    public User(String username, String email, String password) {
        this.username = username;
        this.email = email;
        this.password = password;
    }

    public @NotBlank @Size(max = 20) String getUsername() {
        return username;
    }

Solution

  • The problem is that you are using Project Lombok at least you have put the @RequiredArgsConstructor on your configuration class in the hopes to not have to add a constructor.

    ApplicationConfig.java:21: error: variable userRepository not initialized in the default constructor
    

    The error you get mentions the default constructor. Which is the default no-args constructor which will get added to Java classes when no other explicit constructor has been added.

    This simply means that you have added Lombok as a dependency but haven't setup the compiler plugin in your Maven pom.xml or Gradle build.gradle.

    If it were me I would ditch Lombok and simply add a single arg constructor to your ApplicationConfig class. This would make it work without any additional added code generation magic.

    @Configuration
    public class ApplicationConfig {
    
      private final UserRepository repository;
    
      public ApplicationConfig(UserRepository repository) {
        this.repository=repository;
      }
    
       // Other code not listed...
    }
    

    If you really want make sure you setup the maven-compiler-plugin correctly.

    Dependency declaration

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>provided</scope>
    </dependency>
    

    Plugin configuration

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <annotationProcessorPaths>
                <path>
                    <groupId>org.projectlombok</groupId>
                    <artifactId>lombok</artifactId>
                </path>
            </annotationProcessorPaths>
        </configuration>
    </plugin>
    

    NOTE: You don't need the version tags as Spring Boot will manage those.

    NOTE2: If you get this error in your IDE (like Intellij) make sure that you have enabled annotation processors, else the annotations from Lombok won't do anything.