3
public class Player {
   @Autowired gameService

   @Getter @Setter String name;

   public Player(String name) {
      this.name = name
   }

   public doSomething() {
      gameService.something() // gameService is null!
   }

}
@Service 
class GameService { public void something() {...} }

If I were to do new Player("John").doSomething() java complains that this.gameService is null. Player class is needed to be instantiated.

Is it possible to make gameService autowire to the service correctly?

  • 2
    of course, but only if Player is also instantiated using the Spring framework. So, make your Player class a Service or Component, and have Spring instantiate it for you, and autowire it where you use itµ – Stultuske Apr 07 '22 at 06:49
  • 2
    Add @Component in your Player class – Batek'S Apr 07 '22 at 06:50
  • @Stultuske can a class be instantiated using the Spring framework so that multiple instances are present? My program requires more that one Player object. – user10469929 Apr 07 '22 at 07:13
  • For Refrence link who is best: https://stackoverflow.com/questions/40620000/spring-autowire-on-properties-vs-constructor – Batek'S Apr 07 '22 at 07:14

3 Answers3

1

If I were to do new Player("John").doSomething()

When you create the java instance by your self, this instance is unknown to Spring framework. So Spring will not enrich it with any dependencies it contains.

For your class to contain dependencies via @Autowired you have to let spring create this instance. Spring in actuality will create a proxy to the class you provide and not the actual class that you have written. One way to achieve that is to mark your class Player with @Component and then you must also retrieve the instance player from Spring framework to correctly contain it's dependencies.

Keep in mind that with default @Comopnent the Player will become a singleton for spring, which doesn't exactly match to the logical use I see you want to have for this class. Either you want it to be a prototype or even better I think you have to move the use of gameService outside of Player class.

Probably you could have the method something() in GameService taking as parameter a Player and doing the same thing. Then you can autowire everywhere the gameService which sounds like it should be a singleton.

Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47
0

You can make Player a component which makes autowiring available:

@Component
public class Player {
   @Autowired 
   GameService gameService

Additionally, dependency injection best practices are to use constructor based injection:

@Component
public class Player {
   private final GameService gameService;
   
   @Autowired
   public Player(GameService gameService){
      this.gameService = gameService;
   }
void
  • 144
  • 8
  • In the constructor, how would I set a `String name` property? So if I add `@Component` calling the method `doSomething()` from `Player p1 = new Player("John"); Player p2 = new Player("Doe")` should be fine? – user10469929 Apr 07 '22 at 07:11
  • I think there may be a structural issue there. Although not ideal in terms of Object Oriented Programming paradigms, ```@Services``` commonly act on business objects that are not ```@Components``` - so your GameService would retrieve a list of Players either from a controller (i.e. your frontend) or a repository (i.e. your database) and act based on the information provided. But in general, if you want to pass some information to your service's method, just go with ```void doSomething(String playerName)``` - but ultimately you still may want to think about your flow there. – void Apr 07 '22 at 07:15
0

Since you want gameService to be @Autowired, I believe you want some processing to be done based on Player object on that gameService. If yes, instead of calling gameService.something(), call gameService.something(player).

Here is a possible solution:

@Component
public class Player {
    @Autowired GameService gameService;

    @Getter
    @Setter
    String name;

    public Player() {
    }

    public Player(String name) {
        this.name = name;
    }

    public void doSomething(Player player) {
        gameService.something(player);
    }
}

In caller side however, it should be something like:

@Autowired
Player player;
...

public void callPlayer() {
   Player johnPlayer = new Player("John");
   player.doSomething(johnPlayer);
}

The reason for doing this is let spring create Player component and have dependency injection and you leverage spring created component.

Hope this will help.

YoManTaMero
  • 391
  • 4
  • 10