SpringBoot: Can't Autowire Class from Other Jar Library

32,152

Solution 1

I have now found the solution on my problem. I have to move up my main MyApp.java one package level higher in order to scan my data libraries.

Instead of putting my MyApp.java under my.app package, I have to move it under my in order to successfully scan my libraries with my.data.jpa and my.data.jdbc packages.

Solution 2

Adding @ComponentScan won't work if the class you're attempting to Autowire isn't annotated with @Component. In order to get this to work, you'll have to annotate a method in your @Configuration class. Something like this should allow you to autowire the class:

@Configuration
public class ConfigClass{

    @Bean
    public JPADataService jpaDataService(){
        return new JPADataService();
    }
}

Solution 3

You need to config spring.factories at external jar:

external-jar-project
   |--java
   |--resources
        |-- META-INF
              |-- spring.factories

the contect of spring.factoires, like this:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx
Share:
32,152
Jown
Author by

Jown

Updated on July 31, 2022

Comments

  • Jown
    Jown almost 2 years

    I am developing a SpringBoot application (e.g. MyApp) with dependency to two data projects with different implementation:

    data-jdbc.jar

    • built using the spring-boot-starter-jdbc which exposes JDBCDataService class that will be used by my application

    Sample Code:

    @Service 
    public class JDBCDataServiceImpl implements JDBCDataService {
    
    @Autowired
    private JDBCDataRepository jdbcDataRepository;    
    ... 
    }
    
    • with package my.data.jdbc
    • there is no SpringBoot main class. Spring configuration only created for the unit test classes
    • the repository classes are using JDBCTemplate

    Sample Repository:

    @Repository
    public class JDBCDataRepositoryImpl implements JDBCDataRepository {
    
    @Autowired
    protected JdbcTemplate jdbcTemplate;
    ...
    }
    

    data-jpa.jar

    • built using the spring-boot-starter-data-jpa which also exposes JPADataService class that will also be used by my application

    Sample Code:

    @Service 
    public class JPADataServiceImpl implements JPADataService {
    
    @Autowired
    private JPADataRepository jpaDataRepository;    
    ... 
    }
    
    • with package my.data.jpa
    • there is no SpringBoot main class. Spring configuration only created for the unit test classes
    • repository classes extends the CrudRepository interface

    Sample Repository:

    @Repository
    public interface JPADataRepository extends CrudRepository<MyObject, Integer{
    ...
    }
    

    In my SpringBoot project, I have the following SpringBoot main application:

    @SpringBootApplication
    public class MyApp extends SpringBootServletInitializer {
    }
    

    In my business service MainService class, I have the following injection

    @Service
    public class MainServiceImpl implements MainService {
    
    @Autowired
    private JDBCDataService jdbcDataService;
    
    @Autowired
    private JPADataService jpaDataService;
    

    However, I have encountered the problem "Could not Autowire. No beans of 'JPADataService' type found" which only exists for the class JPADataService but working fine for JDBCService class.

    I have tried the solution found in the following questions, but none of these work in my case:

    Can't I @Autowire a Bean which is present in a dependent Library Jar?

    @ComponentScan(basePackages = {"org.example.main", "package.of.user.class"})
    

    How can I @Autowire a spring bean that was created from an external jar?

    @Configuration
    @ComponentScan("com.package.where.my.class.is")
    class Config {
    ...
    }
    

    I have now found the solution on my problem. I have to move up my main MyApp.java one package level higher in order to scan my data libraries.

    Instead of putting my MyApp.java under my.app package, I have to move it under my in order to successfully scan my libraries with my.data.jpa and my.data.jdbc packages.

  • Christopher Schneider
    Christopher Schneider almost 8 years
    I should add I'm not familiar with JPADataService. It may require some sort of configuration that I didn't account for.
  • Jown
    Jown almost 8 years
    If this is the case, it should also not work in JDBCService object as I have not declared this class in any Java configuration file in my application which uses them. AFAIK, using @SpringBootApplication should do the magic for you :-)
  • SHAKU
    SHAKU over 6 years
    anybody know why '@ComponentScan' wont work? I am facing the same issue, my repository is even annotated with '@Repository' and added a ComponentScan with base package value, which is one level up where spring could see all the beans even from jar libraries. The application only worked when I moved up one level the SpringBootApplication as @Jown said.
  • ajaristi
    ajaristi about 6 years
    Why did this happen? It's a bug or a spring-boot feature?
  • Gagandeep Kalra
    Gagandeep Kalra about 6 years
    It's not a bug, @ComponentScan by default picks up from package where main class is defined and it's sub-directories
  • Nisarg
    Nisarg about 4 years
    Please write your answer in English only.
  • Satya P
    Satya P about 3 years
    You are a life savior @Jown. I spent almost a day to figure out the problem in my application. I added ComponentScan to my SpringBoot main application calls, it solved the actual problem, but that caused some other problem internal to my app. I have moved the SpringBoot main class, and it solved my problem. Literally you have saved my weekend.. kudos!