/java/

Using Qualifiers to choose implementation during @Inject

2015-07-08 19:35:47

Let's assume that you have interface

package pl.btbw.service;

public interface AnimalService {
    String getType();
}

with one implementation

package pl.btbw.service;

public class DogService implements AnimalService {
    public String getType() {
        return "My type is Dog";
    }
}

if you inject AnimalService somewhere, everything should work

    @Inject
    private AnimalService animalService;

but if you have two implementation like this

package pl.btbw.service;

public class DogService implements AnimalService {
    public String getType() {
        return "My type is Dog";
    }
}
package pl.btbw.service;

public class HumanService implements AnimalService {
    public String getType() {
        return "My type is Human";
    }
}

CDI have problem...

Error during artifact deployment....
java.lang.Exception.....
  - Managed Bean [class pl.btbw.service.HumanService] with qualifiers [@Any @Default],
  - Managed Bean [class pl.btbw.service.DogService] with qualifiers [@Default @Any]

because it marked both implementation as @Default, form DI perspective your both implementations looks like this

package pl.btbw.service;

import javax.enterprise.inject.Default;

@Default
public class DogService implements AnimalService {

    public String getType() {
        return "My type is Dog";
    }
}
package pl.btbw.service;

import javax.enterprise.inject.Default;

@Default
public class HumanService implements AnimalService {
    public String getType() {
        return "My type is Human";
    }
}

to fix that problem you have to introduction your custom annotation

package pl.btbw.service;

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

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

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

and use this in one of your Service

package pl.btbw.service;

@HumanSelector
public class HumanService implements AnimalService {

    public String getType() {
        return "My type is Human";
    }
}
package pl.btbw.service;

import javax.enterprise.inject.Default;

@Default
public class DogService implements AnimalService {

    public String getType() {
        return "My type is Dog";
    }
}

now DI know what to do, if you do something like this:

    @Inject
    private AnimalService animalService;

DI will inject @Default implementation,

if you add custom annotation

    @Inject @HumanSelector
    private AnimalService animalService;

then it will take Service (implementation) with @HumanSelector annotation

Github