Tarta
Tarta

Reputation: 2063

Spring Dependency Injection missing bean

I am trying to implement Constructor based Dependency Injection with Spring. From Spring 4.3 annotations are not required for constructor injection, so my class looks like this:

@RestController
public class CardController {

    private IDeckManager _deckManager;

    public CardController(IDeckManager deckManager){
        _deckManager = deckManager;
    }

    @RequestMapping("/preparedeck")
    public void PrepareDeck(){
        _deckManager.InitializeDeck();
        _deckManager.ShuffleDeck();
    }
}

where IDeckManager is:

public interface IDeckManager {

    void InitializeDeck();

    void ShuffleDeck();
}

and the actual implementation of IDeckManager is:

public class DeckManager implements IDeckManager {

    public Stack<Card> deck;

    public DeckManager() {
        deck = new Stack<Card>();
    }

    @Override
    public void InitializeDeck() {

        for (int i = 0; i < ICard.Suit.length; i++) {
            for (int j = 0; i < ICard.Values.length; i++) {
                deck.add(new Card(ICard.Suit[i], ICard.Values[j]));
            }
        }
    }

    @Override
    public void ShuffleDeck() {
        Collections.shuffle(deck);
    }
}

Unfortunately at runtime it says that: Parameter 0 of constructor in CardController required a bean of type IDeckManager that could not be found.

What am I missing to make the DI work properly?

Upvotes: 2

Views: 3090

Answers (3)

Mark Bramnik
Mark Bramnik

Reputation: 42501

As our colleagues already have stated, the DeckManager class has to be managed by Spring and putting a @Component or @Service annotation will resolve the issue.

However I would like to clarify one additional thing here that might save you from a possible bug.

Spring beans by default are singletons, so there will be a single instance of DeckManager injected by spring to controller. I assume it should manage deck of cards.

So when you'll call /prepareDeck it will indeed create a deck and will fill it with the cards, so far so good. However, what if you (or someone else) will call this HTTP method once again?

The answer is that it will create an another series of cards and will put it to the stack. Essentially it will add another N cards per each invocation which is probably not what you want.

Another use-case: What if two (or more) requests to "initialize deck" will be called simultaneously? The internal stack will contain a strange mix of cards... Again, probably not your goal.

Its possible to create an "init" method for deck manager and annotate it with @PostConstruct annotation. In this method you can create a deck and you won't need the HTTP method. Spring will call this method exactly once during the initialization.

Upvotes: 1

Dmitry Ionash
Dmitry Ionash

Reputation: 821

DeckManager should be a component of Spring - @Component, @Service, etc. Or just @Bean.

And, please, Java and Spring have own naming convention ... names InintializeDeck and ShuffleDeck are not correct for method names! Use initializeDeck and shuffleDeck.

Upvotes: 1

Ori Marko
Ori Marko

Reputation: 58792

Spring need to identify DeckManager as Spring managed bean, if you use component scan add @Service or @Component annotation on implementation

@Service
public class DeckManager implements IDeckManager {

Or add it in Configuration class as a Bean

@Bean
IDeckManager deckManager() {
   return new DeckManager();
}

Upvotes: 2

Related Questions