Autowired Bean not found, SpringBoot - java

I'm learning SpringBoot and I built a simple "sample" app but I'm having trouble injecting the different components together.
I get Field b in ca.company.hello.A required a bean of type 'ca.company.hello.B' that could not be found. The injection point has the following annotations:
#org.springframework.beans.factory.annotation.Autowired(required=true).
Here is my configuration:
#Configuration
public class Config {
#Bean
public B b() {
return new B();
}
}
Here is how I use the class B:
#Component
public class A {
#Autowired
private B b;
#Value("Covid 19")
private String calamity;
public void speak() {
b.writeToScreen(this.calamity);
}
}
Can someone tell me please, how do I inject class B correctly into the field b in class A above?
P.S.
Here is the package structure of my project:
And here is my main:
#SpringBootApplication
public class Helloer {
public static void main(String[] args) {
// EDIT: I'm now using ctx to create the A object as per suggestions below. Same error though
ApplicationContext ctx = SpringApplication.run(A.class, args);
A a = ctx.getBean(A.class);
a.speak();
}
}
Thanks!

Spring Boot Must find the Beans (A and B) during the scanning. It has some component scanning rules that should be obeyed (see the explanation in "item 2" below) + the class marked with SpringBootApplication is wrong, these two issues cause the problem:
Solution:
Fix the Helloer class:
Note, that Helloer is passed to SpringApplication.run.
Another issue is that A should be managed By Spring itself, otherwise, if you do a new A() - the autowiring magic won't happen. In general, everything that has autowiring in one way or another must be managed by spring dependency injection container (read, under the responsibility of spring boot)
#SpringBootApplication
public class Helloer {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Helloer.class, args);
A a = ctx.getBean(A.class);
a.speak();
}
}
Move the config class so that its package will be the same or "inner" package related to the "Helloer". Spring boot scans everything in the package of SpringBootApplication and underneath by default during its startup. Only the classes under these packages can be processed by spring:
package ca.company.hello; // note the package - it can also be something "inside" this package, like ca.company.hello.config; otherwise spring won't find it and class B won't be "visible" for spring.
#Configuration
public class Config {
#Bean
public B b() {
return new B();
}
}
If you already have config for class B, why not also manage class A in the #Configuration (well, this one is optional, it will work even without this change):
package ca.company.hello; // note the package - it can also be something "inside" this package, like ca.company.hello.config;
#Configuration
public class Config {
#Bean
public A a() {
return new A();
}
#Bean
public B b() {
return new B();
}
}
With this change, you don't have to put #Component on A - these are kind of two styles of declaring beans, spring boot will work with both. I haven't seen the definition of the class B in the question, but if you manage it through the #Configuration then you shouldn't put a #Component on the class B itself

You defined A to be a component. So instance of A will be created by Spring. then you say new A().
This creates a new instance of A for which it looks for B and doesn't find.
Anywhere in your code when you use "new" keyword, it is just another instance you are creating which Spring is not aware of, hence your error.
So you need to autowire A into the Main class and call the method a.speak.
Plus, your bootstrap class is wrong, you are bootstraping class A, but the run method expects a class which is annotated with SpringBootConfiguration. That is how SpringBoot starts the application.
So your code should be :
#SpringBootApplication
public class Helloer {
#Autowired
private A a;
public static void main(String[] args) {
SpringApplication.run(Hellor.class, args);
a.speak();
}
}
If you do not want to autowire A, second thing you can do is, SpringApplication.run() method returns ApplicationContext. Hold it in a variable and then say context.getBean("a", A.class) -> this returns the instance of A from the Spring Context. Then you can call the a.speak()
#SpringBootApplication
public class Helloer {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(Hellor.class, args);
A a = ctx.getBean("a", A.class);
a.speak();
}
}

Related

Autowired property is null in EnvironmentPostProcessor implementation class on startup

In my SpringBoot app, I have Autowired an configObject in the class that implements EnvironmentPostProcessor.
The injected class reads data from a different source on startup as this is required for the app to work.
But upon starting the application, the configObject is coming off as Null.
#SpringBootApplication
#EnableEncryptableProperties
#EnableConfigurationProperties
#EnableCaching
#Slf4j
public class SBApplication {
public static void main(String[] args) {
SpringApplication.run(SBApplication.class, args);
}
}
And the AppEnvironmentPostProcessor class where the Autowired object is called. This class is configured as org.springframework.boot.env.EnvironmentPostProcessor in spring.factories. The class gets called on start up.
#Slf4j
public class AppEnvironmentPostProcessor implements
EnvironmentPostProcessor, Ordered {
#Autowired
KeysConfig keysConfig;
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
// keysConfig is null
String key = keysConfig.getSecretKeyMap().get("key12");
}
}
And in the KeysConfig class
#Component
public final class KeysConfig {
public Map getSecretKeyMap() {
//Returns key map
}
}
I am using Intellij Ultimate. How can I debug and resolve this?
EnvironmentPostProcessors are created before the application context has been created and, therefore, before dependency injection is possible. This means that #Autowired won’t work.
You’ll have to update your implementation to create an instance of KeysConfig itself, or to use a different approach that mimics whatever KeysConfig currently does.

How to use auto canditate false or exclude bean inside pojo Spring rather than xml?

I have Beans class
class A{
#Autowired
B b;
......
}
Class Config{
#Bean
A a(){
return new A();
}
}
Class Test{
#Autowired
A a;
void doSom(){
a.blabla();
}
public static void main(String[] args){
..........
}
}
My question here,When i inject A in Test class, b also should have the object. else we will get no bean type exception B....So other than required false in autowired, is there any other way to exclude while spring initialize this A class and b should get create based on some conditions .Can you please help or guide how to exclude beans while running Test class

Why spring boot is loading another component even though i am not importing explicitly?

I'm not using #import annotation though context is able to load the bean (SalesService) it should throw the exception find the code.
#SpringBootApplication
public class App {
public static void main(String[] args) {
ApplicationContext context = (ApplicationContext) SpringApplication.run(CustomerConfig.class);
CustomerService customer = (CustomerService) context.getBean("customerBean");
customer.printMessage("setting message for CustomerService");
SalesService sales = (SalesService)context.getBean("salesBean");
sales.printMessage("setting message for SalesService");
}
}
The Anntotation #SpringBootApplication does a #ComponentScan on the package off the annotated class.
This means that every #Component,#Controller, #Service in the same or subpacke gets instantiated.
Have a look here.
You can controll it by providing attributes to `#SpringBootApplication'.
Docs

Java Spring application #autowired returns null pointer exception

Im fairly new to Java Spring IoC and here's my problem
I have a FactoryConfig class with all beans and annotation #Configuration and #ComponentScan written as below.
import org.springframwork.*
#Configuration
#ComponentScan(basePackages="package.name")
public class FactoryConfig {
public FactoryConfig() {
}
#Bean
public Test test(){
return new Test();
}
//And few more #Bean's
}
My Test class has a simple Print method
public class Test {
public void Print() {
System.out.println("Hello Test");
}
}
Now in my Main Class Ive created an ApplicationContentext of FactoryConfig. (I'm expecting all of my #Beans in Factory config will be initialised. However, it returns null when I access the Test class using #Autowired
My Main Class
public class Main {
#Autowired
protected static Test _autoTest;
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
FactoryConfig config = context.getBean(FactoryConfig.class);
config.test().Print();
// _autoTest.Print(); <--- Im getting NULL Pointer Ex here
}
}
What is the correct way to #Autowire and use objects/beans? any clearer explanation would be much appreciated.
Only beans managed by Spring can have #Autowire annotations. Your main class is not managed by Spring: it's created by you and not declared in a Spring context: Spring doesn't known anything about your class, and doesn't inject this property.
You can just access in your main method the Test bean with :
context.getBean(Test.class).Print();
Usually, you get a "bootstrap" from the context, and call this bootstrap to start your application.
Moreover:
On Java, a method shouldn't start with an uppercase. Your Test class should have a print method, not Print.
If you start with Spring, you should maybe try Spring Boot
Spring does not manage your Main class, that's why you are getting Nullpointer Exception.
Using ApplicationContext to load beans, you can get your beans and access Methods as you are already doing -
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
FactoryConfig config = context.getBean(FactoryConfig.class);
config.test().Print();
remove the static argument
protected Test _autoTest;
Your class
public class Test {
public void Print() {
System.out.println("Hello Test");
}
}
is not visible to Spring. Try adding an appropriate annotation to it, like #Component.
The reason is that your Main is not managed by Spring. Add it as bean in your configuration:
import org.springframwork.*
#Configuration
#ComponentScan(basePackages="package.name")
public class FactoryConfig {
public FactoryConfig() {
}
#Bean
public Test test(){
return new Test();
}
#Bean
public Main main(){
return new Main();
}
//And few more #Bean's
}
And then you can edit your main() as follows:
public class Main {
#Autowired
protected Test _autoTest;
public static void main(String[] args) throws InterruptedException {
ApplicationContext context =
new AnnotationConfigApplicationContext(FactoryConfig.class);
Test test = context.getBean(Test.class);
Main main = context.getBean(Main.class);
test.Print();
main._autoTest.Print();
}
}

NoUniqueBeanDefinitionException: No qualifying bean of type : This is not returned

I have the below bean defined as part a A.jar
package abc;
#Component
public class ParentInterceptor implements ClientInterceptor {
}
I have created another bean in a different project under a different package by extending ParentInerceptor
package xyz;
#Component
public class ChildInterceptor extends ParentInterceptor {
}
In my SpringBoot app , I have a bean defined similar to below
#ComponentScan({"abc","xyz"})
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
#Bean
public Data dataRepo(ParentInterceptor p){
}
}
When I run the main method , I am expecting to see NoUniqueBeanDefinitionException as 2 beans are of same type. However I see both the beans are loaded and ParentInterceptor is being used. Is there a reason why the error is not being thrown?
EDIT
However when i did the below , I was able to see the error being thrown. However I am still unable to understand why an error wasn't thrown in the case listed above.
package xyz;
#Component
public class ChildInterceptor1 extends ChildInterceptor {
}
Application Class:
#ComponentScan({"abc","xyz"})
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
#Bean
public Data dataRepo(ChildInterceptor p){
}
}
EDIT 2
I also tried to check if the child bean indeed extending the parent using the code below -
ctx.getBeansOfType(ParentInterceptor.class)
This returns ParentInterceptor & ChildInterceptor. So I am not really sure why Spring is not returning the error!
In your first example (Parent and Child), i have the correct behaviour, which is the NoUniqueBeanDefinitionException thrown.
If you want to specify which bean to be injected, you can use the #Qualifier annotation:
#Bean
public Data dataRepo(#Qualifier("parentInterceptor") ParentInterceptor p) {
}
Optionally, you can give a name to a component:
#Component("foo")
and change the #Qualifier accordingly.

Categories

Resources