I'm using Weld for Cdi in a JavaSE application.
Some of my services come in two flavors. Distinction in CDI via Qualifier
(@Italian
or @Chinese
).
Most service code is located in a a shared superclass.
This superclass uses other services. Those with a common implementation are simply injected in the superclass (TimerService
).
But if there is a specific implementation, it depends on the subclass which implementation is to be chosen.
In the example below: When ItalianFoodController
is calling service.cookSoup()
, it should use an Italian recipe for the soup...
public abstract class FoodService {
@Inject TimerService timerService;
abstract protected RecipeService getRecipeService();
protected void cookSoup() {
getRecipeService().getSoupRecipe();
timerService.setTimer(20);
...
}
}
@ApplicationScoped @Italian
public class ItalianFoodService extends FoodService {
@Inject @Italian RecipeService recipeService;
@Override
protected RecipeService getRecipeService() {
return recipeService;
}
...
}
@ApplicationScoped @Chinese
public class ChineseFoodService extends FoodService {
@Inject @Chinese RecipeService recipeService;
...
}
public class ItalianFoodController {
@Inject @Italian ItalianFoodService service;
...
public void cook() {
service.cookSoup();
}
}
The example is working fine.
My question is: Is there a CDI-pattern to get rid of getRecipeService()
?
The most intuitiv approach would be:
public abstract class FoodService {
@Inject RecipeService recipeService;
...
}
public class ItalianFoodService extends FoodService {
@Inject @Italian RecipeService recipeService;
...
}
But this does not work because recipeService will be hidden but not overridden by the subclass.
Thinking about @maress' answer I came up with a different approach which allows me to use the injected service quite intuitively.
Solution using constructor injection:
public abstract class FoodService {
protected RecipeService recipeService;
FoodService (RecipeService recipeService) {
this.recipeService = recipeService;
}
}
public class ItalianFoodService extends FoodService {
// Only needed if ItalianRecipeService holds additional methods.
@Inject @Italian ItalianRecipeService recipeService;
@Inject
ItalianFoodService(@Italian RecipeService recipeService) {
super(recipeService);
}
}
Alternatively the same can be achieved via
Solution using @PostConstruct:
public abstract class FoodService {
protected RecipeService recipeService;
}
public class ItalianFoodService extends FoodService {
// Only needed if ItalianRecipeService holds additional methods.
@Inject @Italian ItalianRecipeService recipeService;
@PostConstruct
postConstruct() {
super.recipeService = recipeService;
}
}
Both solutions are quite short and readable while the one with constructor injection is slightly more explizit about the injection.