Reputation: 115
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
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