我使用的代码如下:
public Configuration {
private boolean isBatmanCar = someMethod(...);
@Produces
public Car getCar(@New Car car) {
if(isBatmanCar) {
car.setName("BatmanCar");
}
return car;
}
}
public Car {
private String name = "NormalCar";
public void setName(String name) {
this.name = name;
}
}
public Demo {
@Inject
Car car;
// rest of code
}
当我将应用程序部署到glassfish(Java EE 6顺便说一句)时,我得到了
AmbiguousResolutionException: WELD-001318 Cannot resolve an ambiguous dependency between (...) Car with qualifiers [@Any @Default] (...) Producer Method [Car] with qualifiers [@Any @Default]
我知道当我将@Alternative
添加到Car类时,它会起作用,但我想知道这是否是正确的方法,为什么我必须这样做?
在这种情况下,你能告诉我@Produces的正确用法是什么吗?
我正在使用Java EE 6,CDI 1.0,EJB 3.1,Glassfish 3.2
答案 0 :(得分:12)
错误来自这样一个事实:你有2个类型Car
的bean,一个是类,另一个是生产者。您有2个明显的解决方案来解决歧义:
首先,将逻辑放在原始类中的isBatmanCar
字段(例如,在构造函数或@PostConstruct
方法中)并删除生成器。这只会留下一个Car
bean。
或者如果你真的想拥有2个bean或者无法避免它,你应该为你的生产bean创建一个限定符:
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface BatmanChecked {
}
并在制作人处使用它,
@Produces
@BatmanChecked
public Car getCar(Car car) {...}
能够注入汽车类型
@Inject
Car stdCar;
@Inject
@BatmanChecked
Car batCheckedCar;
限定符是解决模糊注入的自然选择。使用@Alternative
也有效,但这比一个好的做法更具诀窍。
上次评论:此处不需要@New
,因为您的Car
bean没有范围(@Dependent
范围也是@Dependent
。 @New仅在生产者注入范围不是Car
的bean时才有用。也就是说,如果您的@Dependent
类在范围{{1}}中,则此代码不是很有用。
答案 1 :(得分:8)
使用@Alternative工作,但只有在你想通过beans.xml激活时才能使用。
禁止bean的默认构造函数也可以工作,但是你不能在另一个范围内使用你的bean而不是@RequestScoped。
使用自己的限定符可以工作但是如果你只有一个实现并且只想用生产者而不是它的构造函数来实例化bean,那么它就不是很有用。
最简单的方法是注释你的bean @Any:
@Any
public class Car {
}
...
@Produces
public Car getCar() {
return new Car();
}
...
@Inject
Car car;
你必须记住的事情:
关于所有这些,与上面明确限定的相同代码如下所示:
@Any
public class Car {
}
...
@Produces
@Any
@Default
public Car getCar() {
return new Car();
}
...
@Inject
@Default
Car car;
更明显的是,bean的默认构造函数不是注入点的有效可能性,而生产者是有效的可能性。
答案 2 :(得分:5)
另一种可能性是在Car类中创建非默认构造函数,如下所示:
public Car {
private String name = "NormalCar";
public Car(String name) {
this.name = name;
}
...
}
通过删除默认构造函数,Car class不能再用于创建注入使用的实例。
将生产者方法更改为
@Produces
public Car getCar() {
if(isBatmanCar) {
return new Car("BatmanCar");
}
return new Car("NormalCar");
}
然后,生产者方法将是创建汽车的唯一方法。
当你知道你总是需要自定义实例并且你不需要默认构造函数时,可以使用这种方式。但通常Antoine解决方案更有用。