I have a CDI producer method which - depending on some conditions not relevant to this example - creates objects of different types:
public class TestProducer {
@Produces @TestQualifier
public Object create(InjectionPoint ip) {
if(something) {
return "a String";
} else {
return Integer.valueOf(42);
}
}
but when using this producer, I always get an error in the followin situation:
@Named("test")
public class TestComponent {
...
@Inject public void setA(@TestQualifier String stringValue) {
...
@Inject public void setB(@TestQualifier Integer integerValue) {
It only works when the create method of the producer has the expected type in the method signature:
public class TestProducer {
@Produces @SpringBean
public String create(InjectionPoint ip) {
Now the String get's injected correctly, but I have no way to also generate an integer from the producer method. But this is exactly what I want to avoid, since the producer itself should be completely generic.
Am I doing something wrong or is there no way to achieve the behaviour I want?
All CDI documentation makes it clear that CDI does typesafe dependency injection - and it is an exalted property of CDI. IMHO, what you are trying to do is just what CDI tries to avoid. You want the container to cast Object
to each type and CDI does not work that way.
The injections points stringValue
and integerValue
can only receive a bean which has java.lang.String
and java.lang.Integer
in its list of bean types respectively. java.lang.Object
does not satisfy this criterion.
I have two suggestions. First, since you have two or more injection points of different types, create two or more producer methods for that types:
public class TestProducer {
@Produces @TestQualifier
public String createString(InjectionPoint ip) {
if(something) {
return "a String";
} else {
// Some other value
}
}
@Produces @TestQualifier
public int createInt(InjectionPoint ip) {
if(something) {
return 42;
} else {
// Some other value
}
}
// ...
It works if the something
condition is just to check the type of the injection point (what I am betting is the case).
However, if the something
condition does decide the type using other criteria than the type of the injection point, I'd suggestion to do the "dirty job" yourself: inject the returned value in an Object
-typed injection point and does the cast manually:
@Named("test")
public class TestComponent {
...
@Inject public void setA(@TestQualifier Object value) {
String stringValue = (String) value;
...
@Inject public void setB(@TestQualifier Object value) {
int intValue = (Integer) value;
The main point is that, unlike some other DI frameworks, CDI does not work against the Java type system - on the contrary, it heavily uses it. Do not try to fight against it but use this aspect of CDI in your favor :)
A producer for Object
is strange anyway. I'm not sure if this is forbidden by the spec, or it's a bug, but I think you can make some clever workaround:
public class ValueHolder<T> {
private T value;
public T getValue() {
return value;
}
}
And then inject a ValueHolder<String>
and ValueHolder<Integer>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With