Search code examples
javaspringspring-boothibernate-entitymanagercomponent-scan

Spring configuring bean with component scan - Field userRepository in service.UserService required a bean of type 'repository


I have checked many examples but they are generally about marking the classes with @Repository or @Service etc...For example here it is about the packages to scan and I am not sure where and in which method I should make scan.

I have a simple application and a User model, UserRepository extending JPA repository and a service. When I try to connect db it is ok by default settings but whenever I want to use custom configuration then the program cannot find the UserRepository class even if I mark it as @Repository. The program still needs repository class configuration bean.

Here is my service method:

@Service
public class UserService {
    @Autowired
    UserRepository userRepository;
    public User findById(Long id) {
        return userRepository.findById(id).get();
    }
}

The model is:

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String name;
    private Date birthday;
}

UserRepository class:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

And here is the configuration that I try to achieve:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager")
public class UserDbConfig {
    
    @Primary
    @Bean("dataSource")
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/testSchema");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    
    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("dataSource") DataSource dataSource
    ) {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.practice.multiDatabase.model");
        factory.setDataSource(dataSource());
        return factory;
    }
    
    @Bean("transactionManager")
    public PlatformTransactionManager transactionManager(@Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {

        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory);
        return txManager;
    }
}

Here is my project structure and main method(I haven't add anything special) enter image description here

The output is:

***************************
APPLICATION FAILED TO START
***************************

Description:

Field userRepository in com.practice.multiDatabase.service.UserService required a bean of type 'com.practice.multiDatabase.repository.UserRepository' that could not be found.

The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.practice.multiDatabase.repository.UserRepository' in your configuration.

Extra notes: When I add this to main method

@SpringBootApplication(scanBasePackages = {
        "com.practice.multiDatabase.repository",
        "com.practice.multiDatabase.controller",
        "com.practice.multiDatabase.service",
        //"com.practice.multiDatabase.config"
        //, "com.practice.multiDatabase.model"
})
public class MultiDatabaseApplication {

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

}

The program is working but probably it is ignoring the config file because I have explicitly write the controller-sevice-repository and if I uncomment the config folder as well then still getting same error.


Solution

  • Omg. I have found it. I have just added

    basePackages = {"com.practice.multiDatabase.repository"}
    

    to config and it is working now.

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
            basePackages = {"com.practice.multiDatabase.repository"},
            entityManagerFactoryRef = "entityManagerFactory",
            transactionManagerRef = "transactionManager")
    public class UserDbConfig {