Why do I get an "Ambiguous dependencies for interface" Exception when I'm already uses the #Produces annotation? - ejb

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:
a ConsumerKafka EJB
a ConsumerRabbitMQ EJB
an #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.

Related

Mixing CDI and EJB results in error at start

we have mixed the usage of CDI and EJB in our application. At startup, we receive the error Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.RequestScoped.
We don't understand where exactly the problem is, so here is just the overall structure of the code:
#Stateless
public class SomeFacade {
#Inject
private SomeService someService;
}
#Stateless
public class SomeService {
#Inject
private SomeDao someDao;
}
#Stateless
public class SomeDao {
#Inject
private EntityManager entityManager;
}
#ApplicationScoped
public class EntityManagerProducer {
#Produces
#ApplicationScoped
public EntityManagerFactory createEntityManagerFactory() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("one");
return emf;
}
public void close(#Disposes EntityManagerFactory entityManagerFactory) {
entityManagerFactory.close();
}
#Produces
public EntityManager createEntityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
}
Is there something we can change in general?
The error is raised because your code tries to access a request-scoped CDI bean in a moment when there's no request scope. Request scope is only created for incoming requests (HTTP requests via Servlet or JAX-RS, JMS MDBs, asynchronous EJB calls, etc.).
If you get this error during startup, I guess you access a request-scoped bean before CDI is fully started, e.g. from a singleton EJB. Try moving your code into a CDI that starts on start-up after CDI is initialized with:
#Dependent
public class CDIStartupBean {
public void startup(#Observes #Initialized(ApplicationScoped.class) Object event) {
// Start-up code here. The CDIStartupBean can inject request-scoped beans
}
}
Ondrej, your answer was helpful but was not quite the solution in my case.
First, I somehow resolved the start-up issues, but received the same error when handling arriving messages / REST requests. The solution was to annotate the service class with #ActivateRequestContext. This enabled CDI injections in all classes that are used by the servive.

#EJB inject does not work when you have interface inheritance

I have the following code.
public interface Multiplier {
void multiply();
}
#Local
public interface MultiplierLocal extends Multiplier{
}
#Remote
public interface MultiplierRemote extends Multiplier {
}
#Stateless
public class MultiplierImpl implements MultiplierLocal,MultiplierRemote{
#Override
public void multiply() {
System.out.println(" called multiplier ");
}
}
Now when I inject this EJB like below into another ejb, it does not work. But it works when I have the Local interface type.
#Stateless
public class AdderImpl implements AdderLocal,AdderRemote {
// This does not work.
#EJB
Multiplier mul;
// This works.
/*#EJB
MultiplierLocal mul;*/
#Override
public void add() {
System.out.println(" Adder Imple called");
mul.multiply();
}
}
The error I get is in wildfly13.
Caused by:
org.jboss.as.server.deployment.DeploymentUnitProcessingException:
WFLYEJB0406: No EJB found with interface of type
'com.libin.ejb.Multiplier' for binding com.libin.ejb.AdderImpl/mul
All the EJB examples that I see does not have a base interface which is extended by local and remote interfaces. Is there a way to make this work ?
The idea of #Remote interfaces is to define all methods that can be invoked by a "remote client", while an #Local interface can have more methods that maybe used only inside the same application. This means that your #Local interface normally extends your #Remote interface. Hence, you inheritance hierarchy should look like this:
#Remote
public interface Multiplier {
void multiply();
}
#Local
public interface MultiplierLocal extends Multiplier{
}
#Stateless
public class MultiplierBean implements MultiplierLocal {
#Override
public void multiply() {
System.out.println(" called multiplier ");
}
}
In this case you can inject Multiplier, because it is a valid EJB interface.
Having an additional interface above the #Remote interface does not make much sense.
Additionally, you can also omit the MultiplierLocal interface, because it does not offer any value and the EJB spec says, that all public methods of a bean are automatically local. Hence, no need to specify an additional #Local interface.

Error creating a base repository class

import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.QueryDslJpaRepository;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
#NoRepositoryBean
public class RepositorySupportImpl<T> extends QueryDslJpaRepository<T, Integer> implements RepositorySupport<T> {
private EntityManager entityManager;
public RepositorySupportImpl(JpaEntityInformation<T, Integer> entityInformation, EntityManager entityManager, EntityManager entityManager1) {
super(entityInformation, entityManager);
this.entityManager = entityManager1;
}
public RepositorySupportImpl(JpaEntityInformation<T, Integer> entityInformation, EntityManager entityManager, EntityPathResolver resolver, EntityManager entityManager1) {
super(entityInformation, entityManager, resolver);
this.entityManager = entityManager1;
}
#Override
public EntityManager getEntityManager() {
return this.entityManager;
}
#Transactional
#Override
public <S extends T> S save(final S entity) {
this.getEntityManager().persist(entity);
return entity;
}
}
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import javax.persistence.EntityManager;
public interface RepositorySupport<T> extends JpaRepository<T, Integer>, QueryDslPredicateExecutor<T> {
EntityManager getEntityManager();
}
in my config class i have repositoryBaseClass = RepositorySupportImpl.class
But I get this error:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'registerService': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is java.lang.IllegalStateException: No suitable constructor found on class ca.lighthouse.repository.RepositorySupportImpl to match the given arguments: [class org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation, class com.sun.proxy.$Proxy52]. Make sure you implement a constructor taking these
I had the same problem just now and after some debugging I figured out the solution:
Make sure you only have one EnableJpaRepositories annotation and that it's pointing to the implementation class (not to the interface):
#EnableJpaRepositories(repositoryBaseClass = GenericJpaRepositoryImpl.class)
I hope it helps someone in the future ;)
I already had the same problem, and the solution was to create the right constructor for implementing the repository.
public RepositorySupportImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
}
You have to use both constructors in the Impl class:
public GenericRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.em = entityManager;
domainClass = null;
}
public GenericRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.em = entityManager;
this.domainClass = domainClass;
}
Thanks for all your comments, its working now. I wish I could definitively pin point the problem, but I can't. Here is the scenario, I have a spring mvc application, with controllers, entities, business services, jsps, and I wanted to clean things up so I decided to break the project down into modules. So I created a new project, added the modules and then copied the files from the old project into the new project. When I copied the RepositorySupport class and interface I thought I should rename it, to what you see above. That resulted in this error and after a few days of researching and trying different things I decided to copy in the original files and it worked. That's all I did, copy in the files and updated the references.

CDI + EJB 3 + EJB Transaction

I need to audit invocations of ejb beans. Saying audit I mean write informations such as current logged user, method name, additional description to a database. I decided to do it by use of CDI decorator:
#Decorator
public class AccountServiceBeanDecorator implements AccountService {
#Inject
#Delegate
#Any
AccountService accountService;
#EJB
private AuditService auditService;
#Override
public Account createAccount(Account account) {
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
and the decorated class:
#Stateless
public class AccountServiceBean implements AccountService {
#Override
public Account createAccount(Account account) {
...
}
}
Now if I call AccountService from another ejb stateless bean, what will happen with transaction?:
#Stateless
public ApplicationFacadeBean implements ApplicationFacade {
#EJB
private AccountService accountService;
#Override
public Account createAccount(Account account) {
return accountService.createAccount(account);
}
}
I wanted to log transaction status in decorator (AccountServiceBeanDecorator) and decorated class (AccountServiceBean), so I injected TransactionSynchronizationRegistry as a resource in both classes:
#Decorator
public class AccountServiceBeanDecorator implements AccountService {
#Inject
#Delegate
#Any
AccountService accountService;
#EJB
private AuditService auditService;
#Resource
private TransactionSynchronizationRegistry reg;
#Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
auditService.saveAudit("Method: createAccount", currentUser, "Creating account by admin");
return accountService.createAccount(account);
}
}
and
#Stateless
public class AccountServiceBean implements AccountService {
#Resource
private TransactionSynchronizationRegistry reg;
#Override
public Account createAccount(Account account) {
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
log.info("tx ({}): {}", new Object[] {reg.getTransactionStatus(), reg.getTransactionKey()});
log.info("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
...
}
}
I received strange behavior:
log from decorator
tx (0): JavaEETransactionImpl: txId=6 nonXAResource=null jtsTx=null localTxStatus=0 syncs=[com.sun.ejb.containers.ContainerSynchronization#68fb15d0]]]
NullPointerException on second log (reg is null).
Can anybody explain it to me? Wheter AccountServiceBean class is called within the same transaction as ApplicationFacade?
Thank you
first: i would not mixing ejbs with cdi interceptors. ejbs has it on interceptor implementations.
second: interceptors are executed in the same transaction as the ejb where the interceptor is around.
possible solution:
create a correct ejb interceptor
put the interceptor around the method / class
create a second ejb (MyLoggerBean) with a method like this logToDatabase(String message) and annotate this method with #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
inside the interceptor create a class member like this: #EJB private MyLoggerBean loggerBean
inside your #AroundInvoke annotated method you could call loggerBean. logToDatabase(...)
this would create a new transaction from inside the current transaction of the ejb where the interceptor is around
--> i know my english is not very good. but i hope that you understand what i think should work. if i have the time, i make e example on github...
Hmm... what container are you using? Generally I wouldn't suspect a CDI decorator to work on an EJB... I can't think of anything in the JEE spec that I've encountered that would give evidence either way.
Faced with your problem though, I did this with an interceptor, not a decorator. These are supported by the EJB spec... Anyway, here's my code, you would need to grab the variables from the context in your case:
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
public class InvocationCountInterceptor {
#Inject
private InvocationCounter counter;
#AroundInvoke
public Object intercept(InvocationContext ctx) throws Exception {
Object returnValue = ctx.proceed();
Class<? extends Object> className = ctx.getTarget().getClass();
Method methodName = ctx.getMethod();
counter.incrementCounter(className, methodName);
return returnValue;
}
}
Then whatever EJB or EJB Method you want to audit, I just added this: #Interceptors(InvocationCountInterceptor.class)

EJB 3.1. Is #Local annotation needed?

So far, I almost always worked with no-interface EJBs and have a slight understanding about the need of #Local annotation. Consider this example:
public interface MyBeanIntf { void doStuff(); }
#Stateless
public class MyBean implements MyBeanIntf { public void doStuff(){ } }
Should the MyBeanIntf be marked as #Local? I don't see any benefit from that, because even when I don't annotate it as #Local, I still can use DI to properly inject it into UI Controller:
#Named
#SessionScoped
public class TestController implements Serializable {
// injection works perfectly, even when MyBeanIntf is not marked as #Local
#Inject
private MyBeanIntf myBean;
// or even like this:
// #EJB
// private MyBeanIntf myBean;
}
Let's make it more complex:
public interface MyBeanIntf { void doStuff(); }
public class MySuperBean implements MyBeanIntf { public void doStuff() { } }
#Stateless
public class MyBean extends MySuperBean { }
Is MyBean now considered a valid Local EJB bean? I have some doubts because it implements the interface indirectly.
If your EJB implements some interface but you don't specify (neither on the EJB nor the interface itself) which interface it is (#Remote, #Local) than it's assumed that it's a #Local one.
Therefore your code:
public interface MyBeanIntf { void doStuff(); }
#Stateless
public class MyBean implements MyBeanIntf { public void doStuff(){ } }
is semantically identical to the following:
#Local
public interface MyBeanIntf { void doStuff(); }
#Stateless
public class MyBean implements MyBeanIntf { public void doStuff(){ } }
When it comes to the second part of your question, I think that section 4.9.2.1 Session Bean Superclasses from EJB 3.1 FR spec would be interesting for you. From my understanding (so it might not be correct), it seems that your bean should not be considered as exposing a valid Local interface because of the following excerpt:
#Stateless
public class A implements Foo { ... }
#Stateless
public class B extends A implements Bar { ... }
Assuming Foo and Bar are local business interfaces and there is no
associated deployment descriptor, session bean A exposes local
business interface Foo and session bean B exposes local business
interface Bar, but not Foo.
Session bean B would need to explicitly include Foo in its set of
exposed views for that interface to apply.
Update:
As an addition one more excerpt from the spec:
A session bean class is permitted to have superclasses that are
themselves session bean classes. However, there are no special rules
that apply to the processing of annotations or the deployment
descriptor for this case. For the purposes of processing a particular
session bean class, all superclass processing is identical regardless
of whether the superclasses are themselves session bean classes.

Resources