Burak Aktas Software Engineer

Create Qualifiers for CDI Beans

As I described in my previous [post][1], we can define and inject cdi beans by @Named annotation. Well according to the CDI specification (JSR-299) injecting beans by their names is legacy and tend to cause issues (if a bean is tried to be injected by an undefined/wrong name then we will get errors which are hard to find). Thus, we are going to create different annotations (qualifiers) to inject different type of beans from same interface. Moreover, we will use Weld CDI implementation.

Create a Qualifier

Creating your own qualifier is easy. We have to create a standard annotation and mark it with @Qualifier.

import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD, METHOD, TYPE, PARAMETER})
public @interface <annotation_name> {
}

So, according to the qualifier template we will need three annotations; Bmw, Honda, and Ford.

Bmw.java

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD, METHOD, TYPE, PARAMETER})
public @interface Bmw {
}

Honda.java

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD, METHOD, TYPE, PARAMETER})
public @interface Honda {
}

Ford.java

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({FIELD, METHOD, TYPE, PARAMETER})
public @interface Ford {
}

Notes

  • Retention</b> determines at what point an annotation is discarded. More explanation can be seen from here. </li>
  • Target</b> defines the type of our annotation. Explanation with clear examples can be seen from here. </li> </ul> </div> I will again use the same code examples which I used in my previous posts. There is one interface called AutoService and three implementations of it. AutoService.java
    public interface AutoService {
        String getService();
    }
    
    BMWAutoService.java
    @Bmw
    public class BMWAutoService implements AutoService{
    
        @Override
        public String getService() {
            return "You chose BMW auto service";
        }
    }
    
    FordAutoService.java
    @Ford
    public class FordAutoService implements AutoService{
    
        @Override
        public String getService() {
            return "You chose Ford auto service";
        }
    }
    
    HondaAutoService.java
    @Honda
    public class HondaAutoService implements AutoService{
    
        @Override
        public String getService() {
            return "You chose Honda auto service";
        }
    }
    
    Now we are completely ready to inject our cdi beans by their qualifiers! So, lets see three different injection examples – Field, Constructor and Setter method injection -.

    1. Injection Through Fields

    public class Example {
     
        @Inject
        @Bmw
        private AutoService bmwAutoService;
     
        @Inject
        @Honda
        private AutoService hondaAutoService;
     
        @Inject
        @Ford
        private AutoService fordAutoService;
     
        ...
    }
    

    2.Injection Through Setter Methods

    public class Example {
     
        private AutoService bmwAutoService;
        private AutoService hondaAutoService;
        private AutoService fordAutoService;
     
        @Inject
        public void setBmwAutoService(@Bmw AutoService bmwAutoService) {
            this.bmwAutoService = bmwAutoService;
        }
     
        @Inject
        public void setHondaAutoService(@Honda AutoService hondaAutoService) {
            this.hondaAutoService = hondaAutoService;
        }
     
        @Inject
        public void setFordAutoService(@Ford AutoService fordAutoService) {
            this.fordAutoService = fordAutoService;
        }
       
       ...
    }
    

    3.Injection Through Constructor

    public class AutoServiceCallerImp 
     
        private AutoService bmwAutoService;
        private AutoService hondaAutoService;
        private AutoService fordAutoService;
     
        @Inject
        public AutoServiceCallerImp(@Bmw AutoService bmwAutoService,
                                 @Honda AutoService hondaAutoService,
                                 @Ford AutoService fordAutoService) {
     
            this.bmwAutoService = bmwAutoService;
            this.fordAutoService = fordAutoService;
            this.hondaAutoService = hondaAutoService;
        }
    
        ...
    }
    
    There is also a second way to use qualifiers to prevent from annotation overflow. In normal life we have tens of auto models. So, instead of creating lots of qualifiers, we can only create one qualifier and enum to define the type of annotation we want to use -enum is optional we can specify types by integer, string etc-. With this way we will be able to handle lots of annotations easily. Let us see; AutoType.java
    public enum AutoType {
        Bmw, Ford, Honda
    }
    
    Auto.java
    @Qualifier
    @Retention(RetentionPolicy.RUNTIME)
    @Target({METHOD, TYPE, PARAMETER, FIELD})
    public @interface Auto {
        AutoType type() default AutoType.Bmw;
    }
    
    default property is optional here. It means if we dont specify a type then the default value will be used. Now let's an example by field injection.
    public class AutoServiceCallerImp implements AutoServiceCaller{
    
        @Inject
        @Auto(type = AutoType.Bmw)
        private AutoService bmwAutoService;
    
        @Inject
        @Auto(type = AutoType.Honda)
        private AutoService hondaAutoService;
    
        @Inject
        @Auto(type = AutoType.Ford)
        private AutoService fordAutoService;
    
        ...
    }
    
    So, as we can see we define the type of our cdi beans just by giving type value, and we have only used @Auto annotation. [1]: http://buraktas.com/java-cdi-dependency-injection-example/