Reputation: 183
Working with Wildfly / JBoss Weld / CDI 1.1.
Lets say you have a database. Can be anything, MySQL, MongoDB. Could be a REST service. From that database, you get a list of Animals.
[
"Cat",
"Dog",
"Giraffe",
"Tiger",
"Chicken"
]
You do not know what animals you will get from this service, but what you want to do is make them available for Instance injection.
Animal Class:
public class Animal {
private final String type;
public String getType() {
return type;
}
public Animal(String aType) {
type = aType;
}
}
Injection Point:
@Inject @Any
public Instance<Animal> animals;
You can make a Producer method that makes AN animal, for instance with a qualifier to make a certain animal:
@Produces @AnimalType
public Animal makeAnimal(InjectionPoint ip) {
// Get AnimalType qualifier and make a new Animal(typeString),
// ...
return animal;
}
But how do you Produce ALL (known from data) animals so that you can iterate over them with instance?
for(Animal animal : animals) {
// ...
}
I do want each Animal to get the benefits of Dependency Injection and other Weld/CDI goodies.
Upvotes: 2
Views: 1793
Reputation: 540
As far as I understand the InjectionPoint concept, you can not use it with Instance in that way. Instance and InjectionPoint with producer-method is used to inject the
Instance<Animal>
into the producer-method with all CDI-animals and the let the producer-method decide, which animal to return, depending on the InjectionPoint:
public Animal make(@Any Instance<Animal> instance, InjectionPoint ip)
Or to produce a configured Object, depending on Qualifier-Config-Inputs like here https://dzone.com/articles/cdi-di-p2
In your case you must tell CDI, how to find the producer-methods:
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface AnimalType {
String value();
}
Then you can write the appropriate producer methods:
@Produces
@AnimalType("Monkey")
public Animal makeAnimalApe() {
return new Animal("Cheetah");
}
@Produces
@AnimalType("Mouse")
public Animal makeAnimalMouse() {
return new Animal("Jerry");
}
@Produces
@AnimalType("Cat")
public Animal makeAnimalCat() {
return new Animal("Tom");
}
And then you can inject it:
@Inject
@Any
private Instance<Animal> anyAnimal;
@Inject
@AnimalType("Monkey")
private Animal monkey;
@PostConstruct
public void create(){
System.out.println(monkey.name);
anyAnimal.forEach((a)->System.out.println(a.name));
}
But in this case you have to write a producer-method for each selection-case. I fear, that's not suitable.
To use the InjectionPoint, you can make the AnimalType NOT a Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface AnimalType {
String value();
}
Now you must use the InjectionPoint:
@Produces
public Animal makeAnimalApe(InjectionPoint p) {
AnimalType t = p.getAnnotated().getAnnotation(AnimalType.class);
if (t != null) {
String s = t.value();
if ("Monkey".equals(s))
return new Animal("Cheetah");
else if ("Mouse".equals(s))
return new Animal("Jerry");
else if ("Cat".equals(s))
return new Animal("Tom");
}
throw new EJBException("Please annotate the animal injection point with AnimalType");
}
But you cannot inject Instance into your bean because lack of the Qualifier AnimalType. So you have to produce a simple List like this:
@Produces
public List<Animal> produceAll(){
List<Animal> all = new ArrayList<>();
all.add(new Animal("Cheetah"));
all.add(new Animal("Jerry"));
all.add(new Animal("Tom"));
return all;
}
So you can inject just one or all
@Inject
@AnimalType("Monkey")
private Animal monkey;
@Inject
private List<Animal> all;
Upvotes: 0
Reputation: 11723
It seems like you might be looking for Unmanaged
Unmanaged<Animal> unmanagedAnimal = new Unmanaged<>(Animal.class);
UnmanagedInstance<Animal> animalInstance = unmanagedAnimal.newInstance();
Animal animal = animalInstance.produce().inject().postConstruct().get();
Its basically a dependent scoped bean, but you need to manually destroy it when done.
Upvotes: 1