-1

Note: I'm updating this since I've found a solution.

This question is similar to Why is my Spring @Autowired field null?, but I'm using the main() method here. The solution is to mark Foo with @Component and autowire it into Main through a @PostConstruct method. I learned about this through How to use autowired (@Autowired) references from main(String[] args) method?

On PostContruct: Why use @PostConstruct?

@PostConstruct makes sure all beans are fully initialized before executing (including the bean class you're actively editing).

But the bigger issue was me doing Foo foo = new Foo(). foo is outside the scope of Spring's context and 100% of it's lifecycle is managed by me. Put everything back in Spring's hands by autowiring everything:

New Main.java

package org.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import javax.annotation.PostConstruct;

@SpringBootApplication
public class Main {
    @Autowired
    Foo foo;

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

    @PostConstruct
    public void test() {
        foo.message();
    }
}

New Foo.java

package org.example;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Component
@Slf4j
public class Foo {

    @Autowired
    Bar bar;

    public Foo() {
        log.info("Foo bean created");
    }

    public void message() {
        log.info(bar.getWord());
    }

}

The original question is below:

I've followed so many Spring tutorials that do it this way, and it never works on my end. No clue what I'm doing wrong, but I seriously need help figuring this out.

Main.java

package org.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);

        Foo foo = new Foo();
        foo.message();
    }
}

Foo.java

package org.example;

import org.springframework.beans.factory.annotation.Autowired;

public class Foo {

    @Autowired
    Bar bar;

    public void message() {
        System.out.println(bar.getWord());
    }

}

Bar.java

package org.example;

import org.springframework.stereotype.Component;

@Component
public class Bar {
    String word = "word";

    public String getWord() {return word;}
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>untitled</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.7.5</version>
        </dependency>

    </dependencies>

</project>

When running from Main(), I get:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.example.Bar.getWord()" because "this.bar" is null
    at org.example.Foo.message(Foo.java:11)
    at org.example.Main.main(Main.java:14)

These are all in the same directory/package. I've been at this for two hours and have no clue why this isn't working. Any help on this would be greatly appreciated.

What I tried:

  • Using @Autowired to create a bean that I can use in another class.

What I expected to happen:

  • The String word to be printed to the console.
  • My understanding is that a class that has @Component is up for grabs by Spring to be a bean if you're using @Autowired to inject it. I have met that criteria and I am not getting my expected result.

What actually resulted:

  • A NullPointerException
  • 1
    It seems that ```Foo``` hasn't been managed as Bean by Spring. Have you configure it in the Config class or xml file? Or you can try to add ```@Service``` annotation in ```Foo``` definition. – kuriboh Nov 06 '22 at 07:47
  • I tried doing `@Service` in `Foo` and I'm still getting the same issue. I even put a print statement in the `Bar` constructor and it shows up when Spring is initializing, so it looks like the bean is being created and loaded. No idea why `@Autowired` isn't using that bean... – Rosk Kruni Nov 06 '22 at 14:03

1 Answers1

1

Autowired only works when you inject the component. You will have to make Foo a component (or define a bean) too and Autowire that into your main class for this to work. Alternatively, you can use an instance of the ApplicationContext.

You also don't need that @ComponentScan annotation since the @SpringBootApplication already has it.

See: https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-boot-using-springbootapplication-annotation.html

RyannnnnnR
  • 41
  • 8
  • I'm not sure I understand what you mean by "works when you inject the component." `Bar` is marked with `@Component` and is being injected in `Foo` through `@Autowired`. Per the other comment, I also tried doing `@Service` in `Foo` and I'm still getting the same issue, and I cannot `@Autowired` the `Foo foo = new Foo()` in `Main` because I would need to make `foo` static to use in the method, and I cannot use `@Autowired` on a static field. – Rosk Kruni Nov 06 '22 at 14:08
  • If you explicitly instantiate `Foo` we aren’t leveraging the DI container. So you have to inject `Foo` into your main class, so Spring can populate it’s dependencies I.e `Bar` – RyannnnnnR Nov 06 '22 at 23:34