0
@SpringBootApplication
public class MainApplication {

    @Autowired
    static BibliographyIndexer bi;

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

}


@Repository
public class BibliographyIndexer {
    ...
}

Whenever I access the properties of bi I get a NullPointerException. I know the @Autowired notation didn't work. But why?

Note: both classes are under the same package.

Additional question: Since I want to run a method upon the start of the spring application. Is this the best approach since @pepevalbe's answer already gave me the workaround I needed. Is there another way to run a method upon the start of the spring application?

kecoliva
  • 80
  • 1
  • 11
  • remove static from BibliographyIndexer – MyTwoCents Nov 12 '19 at 08:58
  • but then I will not be able to access it under the main function. – kecoliva Nov 12 '19 at 08:59
  • 1
    you cannot inject `static` fields. Nor shoul dyou access it like that in your `main`. The `run` method returns an `ApplicationContext` which you can use to obtain a `BibliographyIndexer` using `getBean`. Or create an `@Bean` method which returns a `CommandLineRunner` which you give a `BibliographyIndexer` and invoke the method there. – M. Deinum Nov 12 '19 at 09:03

4 Answers4

1

Because you can't @Autorwire an static class. It doesn't get initialized so you get a NPE when trying to use it.

There are workarounds to wire a bean into a static class, but it is strongly discouraged.

EDIT: If you need to execute code after initilization you could add an event listener:

@SpringBootApplication
public class MainApplication {

    @Autowired  
    BibliographyIndexer bi;

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

    @EventListener(ApplicationReadyEvent.class)
    public void doAfterStartUp() {
        bi.reindex();
    }
}
pepevalbe
  • 1,340
  • 6
  • 18
  • If that's the case then how will I be able to use any of my autowired variables under the main function without declaring them as static? – kecoliva Nov 12 '19 at 08:59
  • You shouldn't write code under the main function. If you need to execute code after initialization you can add an event listener. I will extend my answer for that – pepevalbe Nov 12 '19 at 09:02
  • Under the main function, I instantiated an object that uses the autowired class. But when I use that object and access the autowired class, it is still null. – kecoliva Nov 12 '19 at 09:02
  • Is this the best approach in running a method upon the start of the spring application? – kecoliva Nov 12 '19 at 09:18
  • There are many alternatives, you could write a component class that implements the CommandLineRunner or the ApplicationRunner interfaces. Here you have some examples: https://stackoverflow.com/questions/27405713/running-code-after-spring-boot-starts – pepevalbe Nov 12 '19 at 09:26
0

There are several reasons @Autowired might not work.

When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection. Also when you use @Autowired in the class of which you created a new instance, the Spring context will not be known to it and thus most likely this will also fail. Another reason can be that the class you want to use @Autowired in, is not picked up by the ComponentScan. This can basically be because of two reasons.

The package is outside the ComponentScan search path. Move the package to a scanned location or configure the ComponentScan to fix this. The class in which you want to use @Autowired does not have a Spring annotation. Add one of the following annotatons to the class: @Component, @Repository, @Service, @Controller, @Configuration. They have different behaviors so choose carefully........

Omkar SJ
  • 1
  • 1
0

In main method you can refer to context and from it get access to bean BibliographyIndexer. In static main spring can not creates and injects bean so this is how you can get it from context.

public static void main(String[] args) {
  ApplicationContext  context = SpringApplication.run(MainApplication.class, args);
  BibliographyIndexer bibliographyIndexer = context.getBean(BibliographyIndexer.class);
  bibliographyIndexer.reindex();
}

You can also do as in answer from pepevalbe and execute this code after initialization.

lczapski
  • 4,026
  • 3
  • 16
  • 32
0

Your problem is that you cannot use bi in main because main is static. Making bi static doesn't help because static fields will not be @Autowired (It is possible but does not make sense in the concepts of Dependency Injection).

Remove static and move bi.reindex() to a new method annotated with @PostConstruct. It will be executed after the MainApplication-bean is fully initialized and here you can use your injected bi.

groovedigga
  • 233
  • 3
  • 13