Qualified Injection
In the business framework, you always inject dependencies by interface not by implementation class. For each injection point, two situations are possible:
- If only one implementation exists for a specific interface, it is injected without ambiguity.
- If multiple exists for a specific interface, the injection point should be qualified to select the implementation to
inject. This done by putting an qualifier annotation along the
@Inject
annotation.
Built-in qualifiers
SeedStack provides several built-in qualifiers.
@InMemory
The @InMemory
qualifier denotes an implementation that stores its state
in memory only. It currently can be applied to:
- The
Repository
interface for selecting an implementation of repository that stores aggregates in a map. - The
SequenceGenerator
interface for selecting an implementation that generates a sequence of numbers with anAtomicLong
.
@Random
The @Random
qualifier denotes an implementation that uses random values.
It currently can be applied to:
- The
UuidGenerator
interface for selecting an implementation that generates a randomUUID
.
Other built-in qualifiers
Other qualifiers can be found in add-ons, particularly in persistence add-ons.
Generic @Named qualifier
The @Named
annotation is a qualifier that uses a String as the qualifying element. This is
the only qualifier that is part of the JSR-330 standard.
As an example, consider the following policy interface:
@Policy
public interface TaxesPolicy {
int computeTaxes(Order order);
}
You can have multiple implementation of this policy, for instance one for each country. To define a qualified implementation,
apply the @Named
annotation on the implementation class. Consider the France implementation:
@Named("FR")
public class FranceTaxesPolicy implements TaxesService {
int computeTaxes(Order order){
// ...
}
}
And the United Kingdom implementation:
@Named("UK")
public class UnitedKingdomTaxesPolicy implements TaxesService {
int computeTaxes(Order order){
// ...
}
}
Having defined at least two implementations of the same interface, you can choose which one to inject by reusing the same qualifier injection point:
public class SomeClass {
@Inject
@Named("FR")
private TaxesPolicy frenchTaxesPolicy;
@Inject
@Named("UK")
private TaxesPolicy ukTaxesPolicy;
}
Sometimes, you need to dynamically select the right implementation. You can do so by using the DomainRegistry
:
public class SomeClass {
@Inject
private DomainRegistry domainRegistry;
public void someMethod(CountryCode userCountryCode) {
TaxesPolicy userTaxesPolicy = domainRegistry.getPolicy(TaxesPolicy.class, userCountryCode);
}
}
Defining a custom qualifier
You can choose to write your own qualifier. To do this, create a custom annotation that is itself annotated by
@Qualifier
:
@Qualifier
@Target({ TYPE, METHOD, FIELD })
@Retention(RUNTIME)
public @interface France {
}
You can then qualify an implementation with it:
@France
public class FranceTaxesPolicy implements TaxesService {
int computeTaxes(Order order){
// ...
}
}
And use it at the injection point:
public class SomeClass {
@Inject
@France
private TaxesPolicy frenchTaxesPolicy;
}
Patterns supporting qualifiers
The business framework support qualified injection for the following interfaces: