I'm using two Messaging Oriented Middleware in my project. RabbitMQ and Apache Kafka. I have an consumer interface IConsume which are implemented by ConsumerRabbitMQ and ConsumerKafka. At startup going through some conditions I use the @Produces annotation to choose an implementation for the Interface Bean that I will inject, but it gives me this error.
Exception 1:
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type IConsume with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private com.mycompany.chatapp.startup.RunConsumers.ct
at com.mycompany.chatapp.startup.RunConsumers.ct(RunConsumers.java:0)
Possible dependencies:
- Session bean [class com.mycompany.chatapp.messagegateway.ConsumerRabbitMQ with qualifiers [@Any @Default]; local interfaces are [IConsume],
- Producer Method [IConsume] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces public com.mycompany.chatapp.startup.MOMConfigBean.produceIConsume()],
- Session bean [class com.mycompany.chatapp.messagegateway.ConsumerKafka with qualifiers [@Any @Default]; local interfaces are [IConsume]
@Default and @Alternative works, but I want it to choose by checking which of the Middleware is running.
The lookup works, I also tried beanName. I think the problem is with the @Produces, but I can't find to seem what.
import javax.enterprise.inject.Produces;
@Singleton
@Startup
public class MOMConfigBean {
private String mom;
@PostConstruct
public void init() {
mom = "Kafka";
}
@EJB(lookup = "java:global/Chatapp/ConsumerKafka!com.mycompany.chatapp.messagegateway.IConsume")
IConsume kafkaConsumer;
@EJB(lookup = "java:global/Chatapp/ConsumerRabbitMQ!com.mycompany.chatapp.messagegateway.IConsume")
IConsume rabbitConsumer;
@Produces
public IConsume produceIConsume() {
if ("Kafka".equals(mom)) {
return kafkaConsumer;
} else {
return rabbitConsumer;
}
}
public interface IConsume {
// some code
}
@Stateless
public class ConsumerKafka implements IConsume{
// some code
}
@Stateless
public class ConsumerRabbitMQ implements IConsume {
// some code
}
public class runConsumers{
@Inject
private IConsume ct;
}
You have three ambiguous sources of IConsume
instances:
ConsumerKafka
EJBConsumerRabbitMQ
EJB@Produces public IConsume produceIConsume()
method.You need to disambiguate the source of the IConsume
instances using a qualifier.
This qualifier would look something like:
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.inject.Qualifier;
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD})
public @interface ConditionalMom {
}
Then qualify the producer:
@Produces
@ConditionalMom
public IConsume produceIConsume() {
if ("Kafka".equals(mom)) {
return kafkaConsumer;
} else {
return rabbitConsumer;
}
}
and the injection site:
public class runConsumers{
@Inject
@ConditionalMom
private IConsume ct;
}
Now you have a single source of @ConditionalMom IConsume
instances so it is no longer ambiguous.
You will find that you will be using qualifiers all over the place as you start to further exploit CDI features.