题
我有一个CDI生产者方法,该方法 - 取决于与此示例无关的某些条件 - 创建不同类型的对象:
public class TestProducer {
@Produces @TestQualifier
public Object create(InjectionPoint ip) {
if(something) {
return "a String";
} else {
return Integer.valueOf(42);
}
}
但是,当使用此生产者时,我总是会在以下情况下遇到错误:
@Named("test")
public class TestComponent {
...
@Inject public void setA(@TestQualifier String stringValue) {
...
@Inject public void setB(@TestQualifier Integer integerValue) {
它仅在生产者的创建方法中具有方法签名中的预期类型时起作用:
public class TestProducer {
@Produces @SpringBean
public String create(InjectionPoint ip) {
现在,该字符串的注入正确,但是我也无法从生产者方法中生成整数。但这正是我要避免的,因为生产者本身应该是完全通用的。
我是做错了什么还是没有办法实现我想要的行为?
解决方案
所有CDI文档都清楚地表明CDI确实 typesafe 依赖注射 - 它是CDI的崇高特性。恕我直言,您要做的就是CDI试图避免的事情。您希望容器铸造 Object
对于每种类型,CDI都无法正常工作。
注射点 stringValue
和 integerValue
只能收到一个豆子 java.lang.String
和 java.lang.Integer
在其清单中 豆类类型 分别。 java.lang.Object
不满足此标准。
我有两个建议。首先,由于您有两个或多个不同类型的注入点,因此为该类型创建两种或多种生产者方法:
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
}
}
// ...
如果 something
条件只是检查注射点的类型(我押注的情况是这种情况)。
但是,如果 something
条件确实决定使用其他条件以外的其他条件来确定注射点的类型,我建议您自己做“肮脏的工作”:将返回值注入 Object
- 注射点,并手动进行演员表:
@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;
要点是,与其他一些DI框架不同,CDI不适用于Java型系统 - 相反,它大量使用它。不要试图与之抗争,而要利用CDI的这一方面来支持:)
其他提示
生产者 Object
无论如何都很奇怪。我不确定规格是否禁止这是一个错误,但我认为您可以进行一些聪明的解决方法:
public class ValueHolder<T> {
private T value;
public T getValue() {
return value;
}
}
然后注入 ValueHolder<String>
和 ValueHolder<Integer>
它可能使用CDI产生的通用对象会产生这样的对象:
// the wrapper class
public class Wrapper<T> {
public final T bean;
public Wrapper(T bean){
this.bean = bean;
}
}
// the producer inside some class
@Produces
public <T> Wrapper<T> create(InjectionPoint p){
// with parameter 'p', it is possible retrieve the class type of <T>, at runtime
}
// the bean example 1
public class BeanA {
public void doFoo(){
// ...
}
}
// the bean example 2
public class BeanB {
public void doBar(){
// ...
}
}
// the class that uses the produced beans
public class SomeBean{
//// There on producer method, do you can retrieve the Class object of BeanA and BeanB, from type parameters of Wrapper.
@Inject
private Wrapper<BeanA> containerA;
@Inject
private Wrapper<BeanB> containerB;
public void doSomeThing(){
containerA.doFoo();
containerB.doBar();
}
}
在焊接2.2.0上工作。我认为这也适用于以前的一些版本。
您的初始化器方法将寻找具有API类型字符串和整数的托管BEAN,但是您的生产者方法BEAN仅具有API类型(如果是生产者方法,返回类型)对象。
因此,您只能在初始化器方法中使用对象注入字段,然后区分接收器的主体的类型,或者简单地包装它们和可以返回字符串或INT的实际类型中的生产者方法(但是我避免了仿制药)