#EJB inject does not work when you have interface inheritance - ejb

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.

Related

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

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.

Annotations on Interfaces in Spring

I have problems autowiring beans which are derived from interfaces with annotations.
#Component
#EnableAsync
public interface Calculator {
#Async
public Future<String> calculate();
}
public interface SpecificCalculator extends Calculator {
}
public class ConcreteSpecificCalculator implements SpecificCalculator {
#Override
public Future<String> calculate() {
// do calculation here
return new AsyncResult<String>("hello");
}
}
From what I understood from: Annotations on Interfaces? the #Component Annotation should also apply to all subclasses. Now I have a Mapper class returning all types that are derived from SpecificCalculator.
#Component
public class CalculatorMapper {
#Autowired
private List<SpecificCalculator> specificCalculators;
public List<Calculator> retrieveCalculatorsByModuleId(Integer moduleId) {
if(moduleId==...){
return specificCalculators;
}else{
...
}
}
This is not working. Spring does not find the ConcreteSpecificCalculator and is not injecting it. If I Annotate ConcreteSpecificCalculator with #Component again, it is working. Can anybody explain this to me?

autowiring selective beans into a list reference

I have a service interface I with implementaions I1,I2,I3...I10 out of which I want to use I1-I5 to be autowired as a List<I> in controller class C. The I6-I10 should not be be autowired. How can I achieve this. Moreover the I implementations are annotated #Service beans. I do not want to move them to xml declarations.
Based on the comment by mvb13 I have tried to weave a solution for the problem....
So I write a class extending ArrayList and mark it a Component
#Component("mysublist")
public class MyList extends ArrayList implements ApplicationContextAware
{
#Value("comma.sep.eligible.beans.classnames")
private String eligibles;
private ApplicationContext appCtx;
#PostConstruct
public void init()
{
Map allBeans = appCtx.getBeansOfType(I.class);
for(Object bean:allBeans.values())
{
if(eligibles.contains(bean.getClass().getSimpleName()))
{
add(bean);
}
}
}
public void setApplicationContext(ApplicationContext appCtx)
{
this.appCtx = appCtx;
}
}
Now I can autowire the above bean in my required class definition as:
#Service
public class MyService
{
#Resource(name="mysublist")
private List<I> myReqdBeans;
......
}
*Please ignore the generics related implications in the code.
You should use #Qualifier. It defines any subset that you need.
#Autowired
#Qualifier("MySubset")
private List<I> list;
But I think you should move your bean definitions in xml to use <qualifier ... /> property. I think you haven't another option to specify qualifier.
The #Qualifier annotation should give you what you need. You need to apply it in two places:
On the #Service beans that you wish to include in the sub-list
On the #Autowired list injected into your controller
So addressing the #Service beans first:
#Service
#Qualifier("MySubList")
public class MyService implements IMyService
{
}
And then within your Controller:
#Controller
public class MyController
{
#Qualifier("MySubList")
#AutoWired
private List<IMyService> myServices;
}
This instructs Spring to #AutoWire all IMyService implementations #Qualified as "MySubList"

The CDI Stereotype is not worked with EJB Session Bean

I've a CDI Sterotypes which contains some of InterceptorBinding as the following: -
#Inherited
#InterceptorBinding
#Retention(RetentionPolicy.RUNTIME)
#Target({
ElementType.METHOD,
ElementType.TYPE})
#Documented
public #interface MyInterceptable {
}
#Interceptor
#MyInterceptable
public class MyInterceptor {
#AroundInvoke
public Object perform(InvocationContext context) throws Exception {
log.info("My Interceptor begin.");
Object result =context.proceed();
log.info("My Interceptor end.");
return result;
}
}
#Stereotype
#MyInterceptable
#Retention(RetentionPolicy.RUNTIME)
#Target({
ElementType.TYPE
})
#Documented
public #interface MyStereoable {
}
When I define this Sterotype at the non-EJB it is worked correctly. The message is printed before and after the doing1() execution.
#Singleton
#MyStereoable
public class MyCustomized {
public void doning1(){
//print something.
}
}
Anyhow, when I've tried to use this with the Stateless EJB, it is not worked. There is no any message printed by the Interceptor.
#Remote
public interface HelloServiceable extends Serializable {
void doning2();
}
#Stateless
#MyStereoable
public class HelloService implements HelloServiceable {
public void doing2() {
//Print something
}
}
Then I mix the case 1 and case2 as the following: -
#Stateless
#MyStereoable
public class HelloService implements HelloServiceable {
#Inject
private MyCustomized myBean;
public void doing2() {
this.myBean.doing1();
//Print something
}
}
The MyCustomized can be intercepted and the message is printed, but not for the Stateless EJB.
I'm not sure if I am misunderstand or confused about the CDI and EJB or not. Could you please help to advise further? Thank you very much for your help in advance. I'm looking forward to hearing from you soon.
Regards,
Charlee Ch.
I've changed my project from EAR/EJB project to standalone Web project. The CDI Stereotype is now worked with EJB Session Bean.
I've created a small demonstration at github. Please take note, It uses the JBoss Arquillian for testing.
I hope this information maybe useful.
Regards,
Charlee Ch.

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