In the Java EE platform with CDI, it is possible to introduce instances of POJO classes. Very simply, we need to use the @Inject annotation to enter the default instance of some interface. We can also use qualifiers to enter a specific class in our field. But these solutions are pretty static.
I need another dynamic model of injection material.
Let me introduce my problem: Let's say that we have an Animal interface and three classes that implement this interface: Ant, Dog, Elephant. I would like to dynamically insert an instance of one of these three classes, and it depends on some variable, such as string (animal name). In Java SE, I would do this as shown below:
Map<String, Animal> animalMap = new HashMap<>(); animalMap.put("ant", new Ant()); animalMap.put("dog", new Dog()); animalMap.put("elephant", new Elephant()); ... String animalName = ...; Animal animal = animalMap.get(animalMap); animal.doSomething();
I need something like:
class AnimalManager { @Inject
In all classes implementing the Animal interface, I need to use variables with @EJB annotations.
What is the best and most correct way to do this in Java EE?
EDIT:
OK, based on a response from Svetlin Zarev and hwellmann (thanks!) I created this:
First we create an Animal model:
@Qualifier @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.TYPE}) public @interface AnimalModel { Type value(); enum Type { ANT, DOG, ELEPHANT } }
Let me create an Animal:
public interface Animal { public void eat(Object food); }
Next, specific classes:
@AnimalModel(AnimalModel.Type.ANT) public class Ant implements Animal { @Override public void eat(Object food) { ... } } @AnimalModel(AnimalModel.Type.DOG) public class Dog implements Animal { @Override public void eat(Object food) { ... } } @AnimalModel(AnimalModel.Type.ELEPHANT) public class Elephant implements Animal { @Override public void eat(Object food) { ... } }
Next, AnimalLiteral:
public class AnimalLiteral extends AnnotationLiteral<AnimalModel> implements AnimalModel { private static final long serialVersionUID = 1L; private Type type; public AnimalLiteral(Type type) { this.type = type; } public Type value() { return type; } }
The main component is Animal factory:
@Dependent public class AnimalFactory { @Inject @Any private Instance<Animal> animals; private static Map<String, AnimalModel.Type> animalMap; public AnimalFactory() { animalMap = new HashMap<>(); animalMap.put("ant", AnimalModel.Type.ANT); animalMap.put("dog", AnimalModel.Type.DOG); animalMap.put("elephant", AnimalModel.Type.ELEPHANT); } public Animal getAnimal(String animalName) { AnimalModel.Type type = animalMap.get(animalName); AnimalLiteral literal = new AnimalLiteral(type); Instance<Animal> animalInstance = animals.select(literal); return animalInstance.get(); } }
And the client:
public class Client { @Inject private AnimalFactory animalFactory; public void run(String animalName) { Animal animal = animalFactory.getAnimal(animalName); animal.eat("some food..."); } }
I do not know that placing the animalMap card in this place is correct ...?