I am using CDI as injection framework, but I have found some limitations in its usage, and this is one of them. I am trying to initialize the creation of a bean instance with runtime values. Example:
@RequestScoped
public class MyNumber {
int number;
public MyNumber(int number) {
this.number = number;
}
public String toString() {
return "Your number is: " + number;
}
}
public class UseNumber {
@Inject
Instance<MyNumber> number;
public void doStuff() {
int a = 8;
MyNumber mN = number.select(a).get(); // ?? - Obviously this does not work.
System.out.print(mN); // Should print: "Your number is: 8"
}
}
Please, notice that "a" is a constant in the example, but in practice it is a variable; I clarify this so you don't post an answer with a @Producer
to inject the value then in the constructor of MyNumber
.
Now, anybody has an idea about how can I do that?
I'm not sure what you're trying to do, but from what I understand you want to initialize your bean with data in injection point annotation or at runtime thru programmatic lookup. You can do this by using InjectionPoint
meta data in your bean (the only constraint will be to put your bean in dependent scope)
You can do something like this.
First create a qualifier with a non binding value.
@Qualifier
@Target({TYPE, METHOD, PARAMETER, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Initialized {
@Nonbinding int value() default 0; // int value will be store here
}
You have to add this qualifier on your bean and analyze InjectionPoint
at creation time.
@Initialized
public class MyNumber {
int number;
private int extractValue(InjectionPoint ip) {
for (Annotation annotation : ip.getQualifiers()) {
if (annotation.annotationType().equals(Initialized.class))
return ((Initialized) annotation).value();
}
throw new IllegalStateException("No @Initialized on InjectionPoint");
}
@Inject
public MyNumber(InjectionPoint ip) {
this.number = extractValue(ip);
}
public String toString() {
return "Your number is: " + number;
}
}
You can now inject an initialized number like this:
@Inject
@Initialized(8)
MyNumber number;
If you want to decide the initialization value at runtime, you'll have to use programmatic lookup:
First create the annotation literal for `@Initialized``
public class InitializedLiteral extends AnnotationLiteral<Initialized> implements Initialized {
private int value;
public InitializedLiteral(int value) {
this.value = value;
}
@Override
public int value() {
return value;
}
}
Then you can use Instance
to create your bean.
public class ConsumingBean {
@Inject
@Any
Instance<MyNumber> myNumberInstance;
public MyNumber getMyNumberBeanFor(int value) {
return myNumberInstance.select(new InitializedLiteral(value)).get();
}
...
}
Remember this works only if MyNumber
is in dependent scope which makes sense because it's the only way to change initialization value at each injection.