我有一个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) {
仅当生产者的create方法在方法签名中具有预期类型时才有效:
public class TestProducer {
@Produces @SpringBean
public String create(InjectionPoint ip) {
现在正确地注入了String get,但我无法从producer方法生成一个整数。但这正是我想要避免的,因为制作人本身应该是完全通用的。
我做错了什么或者没有办法实现我想要的行为?
答案 0 :(得分:4)
Object
的制作人无论如何都很奇怪。我不确定这是否被规范禁止,或者它是一个错误,但我认为你可以做一些聪明的解决方法:
public class ValueHolder<T> {
private T value;
public T getValue() {
return value;
}
}
然后注入ValueHolder<String>
和ValueHolder<Integer>
答案 1 :(得分:4)
所有CDI文档都清楚地表明CDI执行 typesafe 依赖注入 - 它是CDI的高级属性。恕我直言,你要做的就是CDI试图避免的。您希望容器将Object
强制转换为每种类型,并且CDI不会以这种方式工作。
注入点stringValue
和integerValue
只能分别接收bean types列表中java.lang.String
和java.lang.Integer
的bean。 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
条件使用除注入点类型之外的其他条件确定类型,我建议自己执行“脏工作”:将返回值注入{{1键入注入点并手动执行转换:
Object
重点在于,与其他一些DI框架不同,CDI不会对Java类型系统起作用 - 相反,它大量使用它。不要试图反对它,但使用CDI的这方面对你有利:)
答案 2 :(得分:2)
可能使用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。 我认为这也适用于以前的某些版本。
答案 3 :(得分:1)
您的初始化方法将查找具有API类型String和Integer的托管bean,但您的生产者方法bean仅具有API类型(在生产者方法,返回类型的情况下)对象。
因此,您只能在初始化方法注入的字段中使用Object,然后区分接收者主体中的类型,或者只是将它们和生成器方法包装在可以返回字符串或Int的实际类型中(但是我' d避免使用泛型)