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 an AtomicLong.

@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 random UUID.

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:

   

On this page


Edit