Zed
Zed

Reputation: 5921

Injecting service class by interface?

So I have 2 Service classes that implement the same interface:

@Service
public class ServiceOne implements InterfaceOne {

}

@Service
public class ServiceTwo implements InterfaceOne {

}

I was wondering how I can inject particular instance inside the controller ?

@RestController
@RequestMapping("/test")
public class MyController {
    @Inject
    public MyController(InterfaceOne service) {

    }
}

I'm not sure how DI is supposed to work with service classes. Basically those two services classes have the same interface and I was hoping to avoid nessesary if's if I could just inject the right one into the controller. An example would be much appreciated.

Edit: Sorry guys, I wasn't clear. What I also need to figure out is, which service class needs to be injected in the controller without specifying concrete implementation at that point. So, I was hoping there is a way to do some kind of if statement and check which implementation of the service should be plugged in.

Upvotes: 0

Views: 1241

Answers (1)

Peter Walser
Peter Walser

Reputation: 15706

Two approaches when dealing with multiple implementations:

Use a specific flavour, identified by a @Qualifier

Annotate each implementation with a specific @Qualifier (such as @Qualifier("One") and @Qualifier("Two")), and inject the specific flavour:

@Autowired
@Qualifier("One")
InterfaceOne implementation;

Use all implementations (or evaluate most appropriate with code)

The second approach is useful when you have a strategy interface, and want to have all implementations injected. You can then use all or any of them, and also query them for additional details.

In that case (when expecting 1..n implementations), use:

@Autowired
List<InterfaceOne> implementations;

If the implementations are optional (0..n), use:

@Autowired
Optional<List<InterfaceOne>> implementations;

EDIT: example on how to use a strategy interface with multiple implementations:

Interface:

public interface HelloWorldService {
    String sayHello();
    String getLanguage();
}

Implementations:

@Service
public class HelloWorldServiceEN implements HelloWorldService {
    public String sayHello() { return "Hi there!"; }
    public String getLanguage() { return "en"; }
}

@Service
public class HelloWorldServiceDE implements HelloWorldService {
    public String sayHello() { return "Hallo!"; }
    public String getLanguage() { return "de"; }
}

@Service
public class HelloWorldServiceFR implements HelloWorldService {
    public String sayHello() { return "Salut!"; }
    public String getLanguage() { return "fr"; }
}

Usage:

@Autowired
private List<HelloWorldService> helloWorldServices;

public void sayHelloInAllLanguages() {
    for (HelloWorldService helloWorldService : helloWorldServices) {
        System.out.println(helloWorldService.sayHello());
    }
}

public void sayHelloInUserLanguage() {
    String userLanguage = Locale.getDefault().getLanguage();
    HelloWorldService helloWorldService = find(userLanguage);
    System.out.println(helloWorldService.sayHello());

}

private HelloWorldService find(String language) {

    // find service in specific language
    Optional<HelloWorldService> service = helloWorldServices.stream().filter(s -> language.equals(s.getLanguage())).findFirst();
    if (service.isPresent()) {
        return service.get();
    }

    // fallback to english, if available
    service = helloWorldServices.stream().filter(s -> language.equals("en")).findFirst();
    if (service.isPresent()) {
        return service.get();
    }

    // fallback to any language
    return helloWorldServices.stream().findFirst().orElseThrow(IllegalStateException::new);
}

Upvotes: 3

Related Questions