1

I'm getting an exception when I start my application, where Spring complain about UnsatisfiedDependencyException:

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'applicationConfig': Unsatisfied dependency expressed through field 'controlRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean found for dependency [com.oak.api.finance.repository.ControlRepository]: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)

My application is organized in this format:

  1. I declared my repository interfaces, with the proper Spring JPA annotations:

    @RepositoryRestResource(collectionResourceRel = "exchange", path = "exchanges")
    public interface ControlRepository extends PagingAndSortingRepository<Control, Long> { 
    }
    
  2. I annotated the EntryPoint class that contains the main method

    @SpringBootApplication
    @EntityScan(basePackages = {"com.oak.api.finance.model.dto"})
    @EnableJpaRepositories(basePackages = {"com.oak.api.finance.repository"})
    public class EntryPoint {
        public static void main(String[] args) {
            Logger logger = LogManager.getLogger(EntryPoint.class);
            logger.info("Starting application");
    
            ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
    //      SpringApplication.run(EntryPoint.class, args);
    
            ctx.getBean(ApplicationServer.class).start();
        }
    
  3. I used @Autowired to inject my repository into my spring config (java based) ApplicationConfig class:

    @Autowired 
    private ControlRepository controlRepository;
    @Autowired
    private CompanyRepository companyRepository;
    @Autowired
    private SectorRepository sectorRepository;
    

Essentially I want to control the dependency on Spring and limit it to a couple of packages, (the repositories, the java config, and the program entry point - EntryPoint)

I assumed that, by specifying @EnableJpaRepositories with the package where my repositories are located, spring would create a proxy for my repository and instantiate an instance of that, and that by the time I call :

    ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class)

The repositories instances would be present in the beans poole and would be possible to autowire them into my ApplicationConfig context, and then inject them into my controller.

This is clearly not happening, and Spring is complaining about the missing Bean to autowire, but I'm not sure what am I missing.

Below a snapshot of my packages: enter image description here any ideas?

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
Charbel
  • 14,187
  • 12
  • 44
  • 66
  • In which package is the Control class. You set Entity scan do model.dto which seems odd to me. – mh-dev Oct 19 '16 at 01:15
  • The Control class as well as the rest of the Entity classes are in: com.oak.api.finance.model.dto , dto is where I put all my Entity classes.. – Charbel Oct 19 '16 at 01:25
  • Add SpringApplication.run(EntryPoint.class); after the logging and remove the ApplicationContext part. Than ensure that your ApplicationConfig class is annotated with @Configuration – mh-dev Oct 19 '16 at 01:31
  • that works when I stop trying to create the `ApplicationContext` (from the `ApplicationConfig`) which is ok until the point where I need to get hold of the `ApplicationServer` bean (instance of class `ApplicationServer`), to call start() on it. I pointed to the `ApplicationConfig` using the `@ComponentScan` and I can see my beans instantiated. But if I try `@Autowired ApplicationServer app;` it doesn't get injected, and if I call `start()` I get a `NullPointerException` – Charbel Oct 19 '16 at 02:29
  • 1
    Implement the CommandLineRunner interface. Autowired beans should than be available in the run method. Oh I just see your package structure is odd. You need to set the component scan to com.oak -> scanBasePackages argument of @SpringBootApplication – mh-dev Oct 19 '16 at 02:32
  • that did the trick! thanks a lot! – Charbel Oct 19 '16 at 02:40

1 Answers1

1

My guess is your repositories are not being scanned, so as a result beans are not getting created. Can you try removing these 2 annotations

@EntityScan(basePackages = {"com.oak.api.finance.model.dto"})
@EnableJpaRepositories(basePackages = {"com.oak.api.finance.repository"})

And keep only @SpringBootApplication. If this is not working, you might need to check the package structure (if possible paste a screenshot here)

Edit 1

replace @SpringBootApplication with

@Configuration
@EnableAutoConfiguration
@ComponentScan("com.oak")

Edit2

Use

 new SpringApplicationBuilder() 
        .sources(SpringBootApp.class) 
        .web(false) 
        .run(args); 

Or use CommandLineRunner after changing ComponentScan path to "com.oak" as mh-dev suggested

so-random-dude
  • 15,277
  • 10
  • 68
  • 113
  • Unfortunately that didn't fix the problem. I'm trying to put all in github, if that turns out complicated I'll try with a screenshot. (I thought it was already on github, but it looks like I created a local branch - not sure how to put that on github, I'll see) – Charbel Oct 19 '16 at 00:24
  • OK I couldn't sort out github now, I added a screenshot – Charbel Oct 19 '16 at 01:06
  • 1
    I think this is the problem. http://stackoverflow.com/questions/33619532/configuration-using-annotation-springbootapplication – so-random-dude Oct 19 '16 at 01:26
  • Solution: Since your package structure is non-convntional , I would replace "@SpringbootApplication" annotation with '@Configuration, @EnableAutoConfiguration and @ComponentScan("com.oak") '... – so-random-dude Oct 19 '16 at 01:41
  • that works only if I stop trying to create the `ApplicationContext` (from the `ApplicationConfig`) which is ok until the point where I need to get hold of the `ApplicationServer` bean, to call `start()` on it. I pointed to the ApplicationConfig using the `@ComponentScan` and I can see my beans instantiated. But if I try `@Autowired ApplicationServer app;` it doesn't get injected, and if I call `start()` I get a `NullPointerException` – Charbel Oct 19 '16 at 01:59
  • Essentially it looks like instantiating the ApplicationContext is the root cause of the problem, and without that I don't know how to get hold of the starting point bean – Charbel Oct 19 '16 at 02:00
  • Probably I failed to understand your use case... got a question, why can't you start the application like this `public class EntryPoint { public static void main(String[] args) { SpringApplication.run(EntryPoint.class, args); } }` And let spring take care of starting the embedded servlet container (tomcat/jetty) for you. – so-random-dude Oct 19 '16 at 02:09
  • Sorry, ApplicationServer is just another class with a method called start and that's what I need to call to start the application. (there is no web application or anything like that) – Charbel Oct 19 '16 at 02:27
  • Ok.. have you annotated ApplicationServer class with @Component (@Service or similar annotation which will tell spring to create a bean of that class)? – so-random-dude Oct 19 '16 at 02:38
  • The comment from mh-dev solved it, to answer your question, no I instantiate it as a `@Bean` in the `@Config (ApplicationConfig)`. Anyway now it's working – Charbel Oct 19 '16 at 02:41