In order to inject different instances, there are different ways to construct and inject beans.
Approach 1:
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface ClassifierOne {
}
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface ClassifierTwo {
}
These qualifiers can be used in your class part of construction parameter injection or setter injection level.
@ClassifierOne
public class MyClassOne implements MyInterface {
// ...
}
@ClassifierTwo
public class MyClassTwo implements MyInterface {
// ...
}
public class XY {
private final MyInterface myClassOne;
private final MyInterface myClassTwo;
@Inject
public XY ( @ClassifierOne MyInterface myClassOne, @ClassifierTwo MyInterface myClassTwo ) {
this.myClassOne = myClassOne;
this.myClassTwo = myClassTwo;
}
}
Approach 2: Use of @Produces
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
public @interface MyClassType {
ClassImplName value();
}
public enum ClassImplName {
CLASS_ONE(MyClassOne.class),
CLASS_TWO(MyClassTwo.class);
private Class<? extends MyInterface> classType;
private ClassImplName(Class<? extends MyInterface> clazz) {
this.classType = clazz;
}
public Class<? extends MyInterface> getClassType(){
return classType;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface ClassType {
ClassImplName value();
}
Above custom qualifiers will allow you to chose type of implementation by removing abibuaty in producer method.
And, you can use below mentioned MyClassFactory to produce interfaces. This mechanism would be efficient as it uses InjectionPoint where the bean is injected.
public class MyInterfaceFactory {
@Produces
@MyClassType
public MyInterface createMyClasses(@Any Instance<MyInterface> instance, InjectionPoint injectionPoint) {
Annotated annotated = injectionPoint.getAnnotated();
ClassType classTypeAnnotation = annotated.getAnnotation(ClassType.class);
Class<? extends MyInterface> classType = classTypeAnnotation.value().getClassType();
return instance.select(classType).get();
}
}
Finally, you can use these generated instances in your class.
public class XY {
@Inject
@ClassType(ClassImplName.CLASS_ONE)
@MyClassType
private MyInterface myClassOne;
@Inject
@ClassType(ClassImplName.CLASS_TWO)
@MyClassType
private MyInterface myClassTwo;
// Other methods using injected beans ...
}