My project techstack is: JavaEE 8, Wildfly, Jboss
and structure like this:
companycontext
- company
- workplace
- employee
- web (beans.xml here)
I have EmployeeAdapter interface in both company and workplace project.
Because CDI will discover every bean in every project so I'll get an error
A component named 'EmployeeAdapterImpl' is already defined in this module
For now my solution is name like: ComEmployeeAdapter, WorkEmployeeAdapter...
Can I use something like #Named
// Implement
#Stateless #Named("company")
EmployeeAdapterImpl implement EmployeeAdapter
// Using
#Inject #Named("company") private EmployeeAdapter
// Implement
#Stateless #Named("workplace")
EmployeeAdapterImpl implement EmployeeAdapter
// Using
#Inject #Named("workplace") private EmployeeAdapter
I think it's much better than a rule to name our adapters.
Thank you very much.
This is an EJB issue, not a CDI issue.
CDI bean type are defined by a fully-qualified class name, so there is no problem having two beans with the same name in different packages.
Since your two EmployeeAdapterImpl beans are stateless session beans, the EJB container will generate JNDI names for them. You can see them in the WildFly logs in a message like
16:09:39.812 [MSC service thread 1-8] INFO org.jboss.as.ejb3.deployment - WFLYEJB0473: JNDI bindings for session bean named 'Foo' in deployment unit 'deployment "myapp.war"' are as follows:
One of the generated names has the form
java:module/EmployeeAdapterImpl
taking only the simple class name, so this is causing a conflict in your case.
You might want to try the name or mappedName element of the #Stateless annotation.
Related
I have 2 projects. The first uses Spring 4 and the second uses jBoss 7.
I'm creating a dependency that given a Class name (like "com.foo.Bar") will get the instance from the injection context.
The classes will implement an interface (TransitionRule), so my method would be like:
public TransitionRule getRule(String className) {
//... Magic goes here!
//get the instance of "className" from any container that the imported project is using.
}
Can i do that with only one implementation or i will to create a different implementation to get from Spring and from Jboss context?
You can do a bean lookup by name or type in Spring if you have access to the relevant Spring Context.
You can perform a JNDI lookup in a running JBoss container if the object has been registered in JNDI, for example, an EJB is generally registered in JNDI for you.
Both of these methods follow the Lookup or Service-Locator pattern. These are NOT injections.
I am trying to port 2 EJB modules in my application from EJB2.1 to EJB3.0. I am using the Eclipse Kepler IDE and regenerated the session beans using an EJB3.0 configuration. I am not using an ejb-jar.xml because in EJB 3.0 that is supposed to be redundant. I have instead used annotations for marking my bean as Stateless and specifying the Local and Local Home Interfaces. I have still kept the Local Home interface since I wanted the basic structure of my project to be similar to what it was in EJB2.1. I have also done away with the xml bindings for the EJB while migrating.
We are using a WAS 7 application server for deployment and while the EJB is getting successfully deployed without errors, I am getting a naming Exception while looking up my Local Home interface from a separate POJO class of a different web application it is required in. I basically want to call the create() method of the Local Home interface after referencing the EJB Local Home. Adding code samples below:
Session Bean:
#Stateless
#Local(AccessLDAPSessionLocal.class)
#LocalHome(AccessLDAPSessionLocalHome.class)
public class AccessLDAPSessionBean implements AccessLDAPSessionLocal {
//Business Logic
}
Local Interface:
public interface AccessLDAPSessionLocal {
//business Interface
}
Local Home Interface:
public interface AccessLDAPSessionLocalHome extends EJBLocalHome {
public AccessLDAPSessionLocal create() throws CreateException;
}
Pojo class referencing the Local Home interface:
public static AccessLDAPSessionLocal getAccessLDAPSessionBean() throws NamingException, CreateException {
if (accessLDAPSessionBean == null) {
InitialContext context = new InitialContext();
Object obj = context.lookup("java:global/AccessLDAP/AccessLDAPSessionBean!com.ibm.asset.hrportal.core.ejb.ldap.AccessLDAPSessionLocalHome");
accessLDAPSessionBean = ((AccessLDAPSessionLocalHome) obj).create();
}
return accessLDAPSessionBean;
}
Also my Local and Local Home interfaces are inside my EJB client which I use as a jar file, while my Session Bean is inside the actual EJB which is used as an EAR.
Following is the error I am getting:
NamingException::javax.naming.NameNotFoundException: Name global not found in context "java:".
Am I missing some configuration resulting in the failure of JNDI lookup? Any help would be gratefully appreciated. Thanks in advance.
WebSphere Application Server 7.0 is only an implementation of EJB 3.0, but the java:global namespace wasn't added until EJB 3.1, which wasn't implemented in WebSphere Application Server until 8.0. As with all EJB 3.0 implementations, you will need to lookup a vendor-specific binding name. You can find the WebSphere Application Server binding name by looking at the CNTR0167I messages in SystemOut.log. See the EJB 3.0 application bindings overview topic in the Knowledge Center if you would like to customize this binding name.
Regardless, it is not a best practice to directly lookup EJBs by their binding name. Instead, you should use an EJB reference. In EJB 3.0, that means using an annotation like this in an EE managed object (such as a servlet or another EJB):
#EJB
private AccessLDAPSessionLocalHome home;
In this case, the EJB container is required to find a target EJB within the same application that contains the EJB reference, so you do not need to explicitly configure a target binding name for the EJB reference.
If you need to access the EJB reference from a utility class rather than an EE managed class, then declare the EJB reference with a name on a managed class (such as a servlet or another EJB), and look it up from the utility class:
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class)
public class MyServlet { ... }
public class MyUtility {
...
InitialContext context = new InitialContext();
Object obj = context.lookup("java:comp/env/ejb/accessHome");
...
}
You can configure multiple such EJB references on the same managed EE class using the #EJBs annotation:
#EJBs({
#EJB(name = "ejb/accessHome", beanInterface = AccessLDAPSessionLocalHome.class),
#EJB(name = "ejb/other" beanInterface = Other.class)
})
public class MyServlet { ... }
If your EJB is packaged in a separate EAR, then note that this is not a portable configuration. See the "Local client views" section of the EJB modules topic in the Knowledge Center. Additionally, you will need to explicitly configure a binding name for the EJB reference.
I think the way you are looking up the ejb is not correct. The JNDI name would be something like "java:comp/env/". ejb-ref-name would be part of your web.xml
Also, you will need to give providerURL and factoryName to the context object before doing the lookup.
Is there any way to initialize Named Bean annotaded by javax.inject.Named/javax.enterprise.context.ApplicationScoped like #ManagedBean(eager=true) from javax.faces package?
#Named
#ApplicationScoped
public Mail() { ... }
I want to load this class when application starts, not when webapplication refers to this bean.
ps. JSF 2.1
Bean Injected by Glassfish 3.1
You can create a CDI extension that has the #Observes AfterBeanDiscovery parameter on one of his methods. There you can instantiate the bean and thus initialize it when the container starts up.
CODI has made those things easier for you, see https://cwiki.apache.org/confluence/display/EXTCDI/Core+Usage#CoreUsage-Startup
If I create an EJB3 bean (say a stateless session bean) in an application using Spring 2.5 for DI, how should I inject dependencies from Spring into the bean without coupling the bean to Spring?
I don't know if you consider applying an interceptor as coupling but that's to my knowledge the standard approach. From the Chapter 18. Enterprise Java Beans (EJB) integration of the documentation:
18.3.2. EJB 3 injection interceptor
For EJB 3 Session Beans and
Message-Driven Beans, Spring provides
a convenient interceptor that resolves
Spring 2.5's #Autowired annotation
in the EJB component class:
org.springframework.ejb.interceptor.SpringBeanAutowiringInterceptor.
This interceptor can be applied
through an
#Interceptors
annotation in the EJB component class,
or through an interceptor-binding XML
element in the EJB deployment
descriptor.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
public class MyFacadeEJB implements MyFacadeLocal {
// automatically injected with a matching Spring bean
#Autowired
private MyComponent myComp;
// for business method, delegate to POJO service impl.
public String myFacadeMethod(...) {
return myComp.myMethod(...);
}
...
}
SpringBeanAutowiringInterceptor by
default obtains target beans from a
ContextSingletonBeanFactoryLocator,
with the context defined in a bean
definition file named
beanRefContext.xml. By default, a
single context definition is expected,
which is obtained by type rather than
by name. However, if you need to
choose between multiple context
definitions, a specific locator key is
required. The locator key (i.e. the
name of the context definition in
beanRefContext.xml) can be
explicitly specified either through
overriding the
getBeanFactoryLocatorKey method in a
custom
SpringBeanAutowiringInterceptor
subclass.
The only other option I'm aware of (extending the EJB 2.x support classes) is much worse from a coupling point of view (and thus doesn't answer your question).
See also
Default Injecting Spring bean to EJB3 SLSB without #Autowired Annotation
I am getting following exception when a Local Interface is implemented by two Stateless beans, in which one having normal functionality and other having some enhanced functionality in it.
java.lang.RuntimeException: could not
resolve global JNDI name for #EJB for
container UserBean: reference class:
org.app.SecurityServiceLocal ejbLink:
duplicated in Some.jar
Finally I came to know why I am getting this exception
I have used #EJB annotation to inject a Stateless bean into another Stateless bean Name UserBean with following code
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class)
public class UserBean implements UserRemote{
}
If you check the injection details I was injecting SecurityServiceLocal, which was implemented by two Stateless bean classes name SercurityServiceBean and SecurityServiceEnhaBean. So, container is in ambiguity state to decide which bean to inject in as both are implementing same interface.
This can be resolved by specifying some more information like beanName property value in #EJB annotation. There you need to provide which stateless bean class needs to be injected by using bean name(declared at that bean level (or) in ejb-jar.xml). check the code to identify the change in the injection mapping
#Stateless(name="UserBean")
#EJB(name="app/SecurityService",
beanInterface=SecurityServiceLocal.class,
beanName="SecurityServiceEnha")
public class UserBean implements UserRemote{
}
It's hard to say for sure without seeing code. A good first step would be to use the optional mappedName="" attribute on your session beans' annotion to give each a unique JNDI name. You'll have to use an equivalent mappedName attribute in your client to make sure you are using the bean that you intent.