Suthek
Suthek

Reputation: 115

SpringBoot: Autowired works in Configuration, but returns null in Controller

My Problem: I have created a Singleton Bean of my model Manager. Trying to Autowire it in my Controller, however, results in a nullpointer. In my configuration, however, the Autowiring of the same Bean works just fine.

I should note at this point that this is not the first singleton Bean I have made in this project; and as far as I can tell, I have made it in the same vein as all the others; which all Autowire correctly. That's the main reason why I'm stumped right now.

The Code:

The Main App is under the 'project' package, so all other packages are sub-packages of that one. I opted to omit the imports for brevity, but everything is imported as it should be.

Config

package project.config

@Configuration
public class BootstrapConfig {
    
    @Bean
    @Scope("singleton")
    public ThingManager thingManager() {
        return new thingManager();
    }

   @Autowired
   private ThingManager manager;


   @PostConstruct
   public void initialize() {
     manager.setup() //This works fine.

  }
}

Manager

package project.model

public class ThingManager {

   private HashMap<String, Thing> things;

   public ThingManager() {
     things = new HashMap<String, Thing>();
   }

   public void setup() {
     //Do setup Things
   }

   public Thing getThing(String input) {
     return things.get(input);
   }

}

Controller

package project.controller

@RestController
@RequestMapping("/api/things")
public class ThingController {

  @Autowired
  ThingManager manager; //This is null

  private Thing thing;

  public ThingController() {
    this.thing = manager.getThing("test"); //This then throws NullPointer.
  }

  @GetMapping("/")
  public ResponseEntity<Thing> showThing() {
    return ResponseEntity.ok(thing);
  }
}

What I have tried: I have tried marking ThingManager as @Component @Scope(value = "singleton")instead of setting up the Bean manually (so I removed the @Bean code-block in the configuration); the result is the same; Configuration can Autowire it perfectly fine, but Controller cannot.

I have looked at the myriad of posts about this topic already on here, but most seem to be about someone having forgotten to mark the class they Autowire in as a component or similar. Maybe I overlooked a similarity to my problem; it's hard to tell.

Upvotes: 0

Views: 570

Answers (1)

rnov
rnov

Reputation: 445

Spring can autowire fields only after the object is created (the constructor is called), so you're accessing the manager in the constructor of ThingControler while it's not yet injected. The easiest way to use manager in the constructor would be to add it as a constructor parameter instead of autowiring (Spring will use available bean for the parameter):

// ... 
public class ThingController {

  private final Thing thing;

  public ThingController(ThingManager manager) {
    this.thing = manager.getThing("test");
  }
  // ...
}

Upvotes: 3

Related Questions