2

Hi I am trying to understand autowiring in beans , I am able to autowire but still getting null values here is code snippets

Edited entire code with current output

 @Component
public class A {
    private String value;
    private B b;

    public void display() {
        System.out.println(value);
        System.out.println(b.m());
    }

    public String getValue() {
        return value;
    }


    public void setValue(String value) {
        this.value = value;
    }

    public B getB() {
        return b;
    }

    @Autowired
    public void setB(B b) {
        this.b = b;
    }

}

B class

@Component
public class B {

    private String b;

    public void setB(String b) {
        this.b = b;
    }

    public String m() {
        return b;
    }

}

configuration.java

@Service
@ComponentScan(basePackageClasses = A.class)
public class AppConfig {

    @Autowired
    public A setBean() {
        A a = new A();
        a.setValue("inside A");
        return a;
    }

    @Autowired
    public B setB() {
        B b = new B();
        b.setB("inside B");
        return b;
    }
}

Main

 @ContextConfiguration(classes = AppConfig.class)
public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(
                AppConfig.class);
        A app = (A) configApplicationContext.getBean("a");
        app.display();
    }

}

Now the question is, I am supposed to get all values but instead of that I am getting null value from each bean , So why I am getting this value as null and how can I sort this?

Edit

the output is

log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. null null

Edit After debugging it i found that , in config class it is passing values as specified but when it comes to display values in display() it gives null

  • What are the package names of your classes? – Jens Aug 01 '16 at 07:18
  • That is the package Name or the Folder structure? – Jens Aug 01 '16 at 07:19
  • my classes are in `java` package and the folder str is `test.java.A` (`A` is class) –  Aug 01 '16 at 07:21
  • @Jens did i miss anything? –  Aug 01 '16 at 07:22
  • `@ComponentScan(basePackages = { "*.java" })` must be in a `@Configuration` annotated file not in an `@Service` annotated file. – Jens Aug 01 '16 at 07:22
  • Also your package Name Looks strange – Jens Aug 01 '16 at 07:23
  • changed `@Serivice` to `@Configuration` still getting error –  Aug 01 '16 at 07:24
  • the idea for this package name is like I am specifying a middle folder name , so I can do complex cofiguration but changing it to simple still gets the null value –  Aug 01 '16 at 07:26
  • and when I apply `@required` i get exception of null values in car.class –  Aug 01 '16 at 07:30
  • I would guess, `@ComponentScan(basePackages = { "*.java" })` is not working. Try `@ComponentScan(basePackages = { "test.java" })` – Jens Aug 01 '16 at 07:32
  • @SergeBallesta stack trace is fine and even constructor with debug statement is working –  Aug 01 '16 at 08:18
  • I even tried a new project , still getting same output –  Aug 01 '16 at 08:18
  • The code you've posted here can't produce the output you've posted. You print the value of `b.m()` which means that since you actually get any output `B` is autowired (otherwise you'd get an NPE), but since you initialize *all* instances of B with `value="some value"` `b.m()` *will* return `"some value"`. Additionally, your main class doesn't compile since you've put the method body directly in the class and in the comments you talk about *car.class* which is never mentioned in the question. Please post the *actual* code you're running. – Raniz Aug 01 '16 at 08:21
  • @Raniz I made the edit.. please check –  Aug 01 '16 at 08:44
  • well it looks like your `A` and `B` classes are instantiated twice...... – AntJavaDev Aug 01 '16 at 09:46
  • yeah , just removed the `@component` annotation and replaced it with bean in configuration class solved the error –  Aug 01 '16 at 09:50
  • @AntJavaDev can u help me to figure out , that how i can use `@component` to instantiate bean once..(any hint will be good) –  Aug 01 '16 at 09:51
  • it seams there is an issue with the config of the `AnnotationConfigApplicationContext` , it overrides the bean definition , so first you proper init the `A,B` classes based on the `AppConfig` class , and then again it picks them up by the package context scan thus overriding your beans properties – AntJavaDev Aug 01 '16 at 09:58
  • oo well change the `@Autowired` annotations in the `AppConfig` class with the `@Bean` annotation , as suggested by @deepdownunder2222 , check a proper tutorial and read it carefully , also in order to get the actual bean created by `AppConfig` i dont think that the method `configApplicationContext.getBean("a");` is correct...... – AntJavaDev Aug 01 '16 at 10:05
  • actually when I removed `@component` , it worked –  Aug 01 '16 at 10:18

2 Answers2

0

Possible causes of your receiving null values:

  1. @Component should be written with a capital letter and the proper annotation from the Spring package must be imported;

  2. Class 'ApCfg' should look like this:

    @Configuration // this annotation is needed by Spring to know it is a config class
    @ComponentScan(basePackages = { "java" }) // you have to add the package NAMES here, not a regex
    public class ApCfg {
    
    @Bean // here, you're telling Spring to register a bean in its container, so you have to mark it as so, by using the @Bean annotation
    public A getA() {
        A a = new A(); // constructors are methods too, so they need to be called, using paranthesis
        a.setAValue("asdf"); // setters usually return void, so you shouldn't be able to return this
        return a; // this instance here is what will be registered in the container
     }
    }
    

If you've annotated class A with @Component, then you shouldn't be able to register it twice, so you should choose a way - either use the @Component annotation, or define it manually in the Config class in a method annotated by @Bean.

Also, I tend to agree that your choice of package name is rather peculiar. Are you certain that the package definition at the top of your classes is:

package java;

?

If you don't have any statement starting with the word package, then all you're classes are in the default package and, in that case, I strongly recommend grouping them in real packages instead.

Cristina_eGold
  • 1,463
  • 2
  • 22
  • 41
  • `package test.java` and I am still getting same output –  Aug 01 '16 at 08:16
  • now I got the point, you were right , i was calling `A & B` twice one by `@component` and other by `@configuration` –  Aug 01 '16 at 09:57
  • @themountain, `package test;`, not `package test.java`. `.java` is a *file* extension that you should use for the files in which you write the class definitions (these are the ones that get compiled). I recommend that you skim the Packages chapter in the official Java tutorial: https://docs.oracle.com/javase/tutorial/java/package/packages.html. It is concise and is certain to clear things up. :) – Cristina_eGold Aug 01 '16 at 10:46
  • thanks for tip, but i already use like `package com.java.test.somepackage` that never caused any trouble but i'll take care of it (you increased my workload lol ;) ) BTW thanks for the tip :) –  Aug 01 '16 at 10:52
0

It seems you've not quite grasped the difference between @Autowired, @Bean, and @Component.

  • @Autowired means that a field or method should be set to or called with autowired (injected) beans.
  • @Bean is used in a class marked with @Configuration to tell Spring about a bean that can be autowired
  • @Component is used on a class to tell Spring that this class should be instantiated as a bean that can be autowired.

In your code you've marked both A and B as @Components which means that they will be instantiated as beans using their default constructors, using default values.

You've then tried to instantiate these as beans (again) in AppConfig but used @Autowired to mark the definitions which means that Spring won't pick them up.

You need to choose one way if telling Spring about your beans, so you can either remove @Component from A and B and use @Bean instead of @Autowired on the methods that create them in AppConfig, or remove the bean definitions completely from AppConfig and initialise the members inside A and B upon construction.

First option:

// No @Component here
public class A {
    ...
}

// No @Component here
public class B {
    ...
}

@Configuration
// You probably don't need @ComponentScan anymore since
// no classes are annotated with @Component
@ComponentScan(basePackageClasses = A.class)
public class AppConfig {

    @Bean
    public A setBean() {
        A a = new A();
        a.setValue("inside A");
        return a;
    }

    @Bean
    public B setB() {
        B b = new B();
        b.setB("inside B");
        return b;
    }
}

Second option:

@Component
public class A {
    private String value = "inside A";
    ...
}

@Component
public class B {
    private String b = "inside B";
    ...
}

@Configuration
@ComponentScan(basePackageClasses = A.class)
public class AppConfig {
    // No bean definitions here, but required for @ComponentScan
}
Raniz
  • 10,882
  • 1
  • 32
  • 64
  • Updated the answer with a solution to your updated question – Raniz Aug 01 '16 at 10:00
  • actually I was mixing two approaches , ie by `@component` and by `@confuguration` was causing ambugity now , i know what to do in either of situtation, BTW Thanks :) –  Aug 01 '16 at 10:20