After the migration of a JEE application (from JBoss 7.1.1 to WildFly 8.2.1) our method to get CDI Beans stopped working. The application have several modules (independent JAR files) grouped into one WAR file deployed now on WildFly.
The Bean to be injected is in the module service and it is implementing the interface IProcessor:
#Loggable
#Monitorable
#Singleton
#ConcurrencyManagement(CONTAINER)
#Lock(READ)
#LocalBean
#ApplicationScoped
public class Processor implements IProcessor {
[...]
In another module of the application (common) there is the rest of the logic: the interface IProcessor and the class where we search for it.
This is how the BeanManager is retrieved:
public void keepBeanManager(#Observes AfterBeanDiscovery abd, BeanManager beanManager) {
bm = beanManager;
}
And this is how the call is done:
Set<Bean<?>> jobBeans = bm.getBeans(IProcessor.class);
I've tried printing out all deployed beans using Adam Bien's sample, at the same point as the getBeans method is called, and I can see the Processor in them. Also, if providing the full package and class name of the Processor works as a temporal hack, but using the IProcessor interface never works, jobBeans is always empty.
The module service is not visible to the module common, and this is why the injection is done using the interface.
As it was working before in JBoss and not in WildFly I assume it is related with the way the AS is handling the Beans, could it be something missing in the configuration of WildFly after the migration?
As pointed by Xavier Dury in the comments, the Bean was not found because it was annotated as #LocalBean. Removing the #LocalBean annotation fixed the issue.
From the JEE definition of LocalBean:
Designates that a session bean exposes a no-interface view
As Processor is implementing the interface IProcessor, the annotation #LocalBean should not be used.
What is strange still for me is why this was working on JBoss...
Related
I was wondering if EJB specifications allow to access a stateful session bean over a looked up stateful session bean.
The reason why I'm asking is, that Jboss EAP 7.0 has no problems with it, but Websphere throws a NullPointerException when I try to access the bean.
For example:
#Stateful
public class SampleServiceRoot implements SampleServiceRootRemote {
#EJB
protected SampleServiceChildLocal servicechild;
#Override
public SampleServiceChildLocal getServiceChild(){
return servicechild;
}
}
#Stateful
public class SampleServiceChild implements SampleServiceChildLocal,SampleServiceChildRemote{
#Override
public void anyMethod(){
//DO Anything
}
}
When I do a remote lookup to the SampleServiceRootRemote and call "getServiceChild()" and try to call "anyMethod()" on it, it works on JBoss EAP 7.0 but on Websphere I get a NullPointerException.
So I was wondering if this is a Bug in Websphere or is it forbidden by EJB Specification and I was just lucky with JBoss EAP 7.0?
The EJB specification does require this scenario to work, depending on some configuration options; there are configuration options that may disable it.
The fact that you are seeing a NullPointerException indicates that WebSphere is not aware of the #EJB annotation on the field in the SampleServiceRoot class. Per the EJB specification, an instance of SampleServiceRoot cannot be created if the #EJB annotation cannot be resolved. Since an instance of SampleServiceRoot has been created, then one of the following has likely occurred:
1 - The application performed a new SampleServiceRoot rather than looking it up in JNDI. This doesn't sound like your problem, but good to double check.
2 - The application contains an ejb-jar.xml with the setting metadata-complete="true". When this is set, WebSphere will not look for annotations, and so will not see or process the #EJB annotation. Either change the setting to "false" or add the <ejb-ref> or <ejb-local-ref> to the ejb-jar.xml file.
3 - The application does not have metadata-complete="true", however when the application is deployed to WebSphere the option to set metadata-complete was selected.
This option will change the metadata-complete setting to "true". Stop using this option, or add the <ejb-ref> or <ejb-local-ref> to the ejb-jar.xml file.
4 - The EJB is contained in a WAR module at level 2.4 or older. In WebSphere, annotations for older modules are not processed.
5 - The application includes a copy of the javax.ejb.EJB class. WebSphere provides the javax.ejb.EJB class, and it is loaded by the WebSphere runtime classloader. If the application also contains the javax.ejb.EJB class on the application classpath, then another instance will be loaded by the application classloader, and it will not match the instance used by the EJB Container. There should be a warning in the logs if this has occurred.
So yes, your scenario is required to be supported; however the specification does allow configurations that disable it. You just need to identify which configuration / packaging option has caused WebSphere to not see the #EJB annotation.
Thanks for the answer,
we tried to move the declarations of the Local-Interface to the Remote Interface of the SampleServiceChild. Also we did not use #EJB annotation. We managed it with doing a lookup of the SampleServiceChild over the InitialContext.
Now it works
I am working on an old project developed in EJB.
I have serviceImpl as #Stateless(mappedName = "adminService"). I have seen in my project injecting this class in other classes by
#EJB(mappedName = "java:app/adminServices/adminServiceImpl")
and other classes are part of the same EAR but different modules. This serviceImpl class is being used only in this EAR.
So my question is if we have a class that is declared as #Stateless and is not being used in other EAR. This class is being used in same EAR modules. So can't we directly use #Inject without declaring it #Stateless?
I have known for three JNDI syntax for EJB
java:global[/application name]/module name/enterprise bean name[/interface name]
java:module/enterprise bean name/[interface name]
java:app[/module name]/enterprise bean name[/interface name]
Can't I use #Inject for java:app?
Why do I need java:module in the same modules, I can directly create an object or use #Inject.
In case of java:global I can understand if you are in other JVM then you need to make RMI call to get an object if stateless bean instance is in other JVM. So I have to use java:global syntax to get stateless bean instance from other JVM even in same JVM. Because I don't think We can use #Inject to get the instance from another EAR project into your EAR.
But in same JVM and same EAR, what is need of java:app and java:module JNDI syntax to get the instance by #EJB annotation if the bean is not singleton.
I can directly use #Inject.
I am learning javaEE and I read somewhere about the main usage of cdi's was back then first in jsf-managed beans with annotations like #requestscope, #applicationscope, etc.. now in newer javaEE versions the cdi got available everywhere (even in ejb beans) so the question is, how do I have to annotate a class which shall be injected inside my local stateless ejb? I am asking this because the annotations like #RequestScope and all those are from jsf but I am not using jsf. Is #Default enough since its marked as default anyway? Is #Dependent better choice?
#Stateless
public class FooEjb{
#Inject Bar b;
}
// what annotation to put here?
public class Bar {
...
}
Yes you don't need JSF to use CDI in JavaEE.
If you are using CDI without using JSF, use the scope annotations from the javax.enterprise.context package.
#Default is a qualifier which as the name suggests the default qualifier. If you have multiple implementations/instances of the same class in your container, then you can use qualifiers to distinguish.
#Dependent is a scope which is the default scope. This means it will depend on the scope of the class it's injected in. A new instance of a #Dependent class will be injected every time a new instance of the class in which it is injected is created.
To enable CDI you need to put a beans.xml file in WEB-INF directory of your web project or META-INF directory of your EAR or EJB project.
According to the java ee documentation, no annotation is required in your case. A simple POJO is an injectable bean and receive the #Default annotation. No need to use JSF.
After forced switching from Spring to EJB (EJB3) in my workspace, I find it problematic to rewrite the utility functions, that made some manual tasks like creating a few records or importing some dictionaries into database.
In Spring I could easily initialize the application by calling new ClassPathAXmlApplicationContext('spring.xml'). Is there any similar utility class for EJB? I'm using EJB implementation from Websphere 8, to be more specific.
Asking google for "Initializing EJB context" gave me nothing useful, maybe it was not correct search phrase?
In case you're starting (embeded) EJB container or doing something of this kind, singleton session bean can be annotated with #Startup annotation and it's #PostConstruct life cycle method will be invoked after container startup.
#Startup
#Singleton
public class StartupBean {
#PostConstruct
void init {
...
}
...
}
EDIT:
There's WebSpehere documentation on how to run embeded container and invoke EJB's. But note that embeded container has to support only EJB Lite specification:
The embeddable container does not support the use of Contexts and
Dependency Injection (CDI).
I'm trying to inject an EJB to a servlet using JBoss7 and its not working. The code works fine on JBoss 6 I package the EJB code out of the WAR, and the interfaces with the WAR but I don't get injection in the SERVLETS(GWT Servlets).
My code looks like
Interface:
#Local
public interface MyService{
}
Implementation:
#Stateless(name = "MyService")
#TransactionManagement(TransactionManagementType.CONTAINER)
public class MyServiceImpl implements MyService {
}
Servlet
#EJB(name = "MyService")
private MyService service;
The same implementation was working fine in JBoss AS 6. I ran out of ideas. Please help.
If your EJB is only a local one, you can put every thing in the war.
If there is only one implementation of the interface you can remove the name of the EJB, the container will resolve the EJB injection base on the type. (You can remove the the interface all together with EJB 3.1).
If you need more, you should provide the archive (EAR or WAR) structure and some log entry (EJB list + error when making the injection).