I am using code like below:
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
}
When I deploy an application to glassfish (Java EE 6 btw) I get
AmbiguousResolutionException: WELD-001318 Cannot resolve an ambiguous dependency between (...) Car with qualifiers [@Any @Default] (...) Producer Method [Car] with qualifiers [@Any @Default]
I know that when I add @Alternative
to Car class it will work, but I wonder if this is the proper way to do it, and why do I have to do it?
Can you tell me what is the correct usage of @Produces in such case?
I'm using Java EE 6, CDI 1.0, EJB 3.1, Glassfish 3.2
Ambiguous dependency. The dependency relation of certain adjuncts (expressed by adverbs or prepositional phrases) is not always unambiguous: they do not necessarily modifiy only one element within the sentence but they can have a relation to several elements at the same time.
Contexts and Dependency Injection (CDI), specified by JSR-299, is an integral part of Java EE 6 and provides an architecture that allows Java EE components such as servlets, enterprise beans, and JavaBeans to exist within the lifecycle of an application with well-defined scopes.
The error comes from the fact that you have 2 beans of type Car
, one being the class, the other being the producer. You have 2 obvious solutions to resolve the ambiguity:
First, you put the logic behind isBatmanCar
field in the original class (in a constructor or a @PostConstruct
method for instance) and remove your producer. That would left only one Car
bean.
Or if you really want to have 2 bean or can't avoid it you should create a qualifier for your produced bean:
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
@Qualifier
public @interface BatmanChecked {
}
and use it on producer,
@Produces
@BatmanChecked
public Car getCar(Car car) {...}
to be able to inject the type of car
@Inject
Car stdCar;
@Inject
@BatmanChecked
Car batCheckedCar;
Qualifier is the natural option to resolve ambiguous injection. Using @Alternative
also works but it's more a trick here than a good practice.
Last remark: @New
is not necessary here, since your Car
bean has no scope (so is @Dependent
scoped). @New is only useful when a producer inject a bean with a scope that is not @Dependent
. That said, this code is not very useful if your Car
class is in scope @Dependent
.
Using @Alternative works but should only be used if you want to be able to activate it through beans.xml.
Suppressing the default constructor of your bean also works but you won't be able to use your bean in another scope than @RequestScoped.
Using your own qualifier works but isn't very useful if you have only one implementation and just want to be able to instantiate your bean with a producer rather than with its constructor.
The easiest way is to annotate your bean @Any :
@Any
public class Car {
}
...
@Produces
public Car getCar() {
return new Car();
}
...
@Inject
Car car;
Things that you have to keep in mind :
Regarding all this, the same code as above explicitly qualified looks like this :
@Any
public class Car {
}
...
@Produces
@Any
@Default
public Car getCar() {
return new Car();
}
...
@Inject
@Default
Car car;
It becomes more obvious that the bean's default constructor isn't a valid possibility for the injection point and the producer is a valid possibility.
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