For example in this question I see:
#ManagedBean
#SessionScoped
public class LoginBean {
#EJB
private LoginUserLocal loginUser;
private boolean loggedIn = false;
private User user;
private StreamedContent image;
Does #EJB annotation automatically inject these instances to this class?
Thank you.
The #EJB annotation (and #Resource, #WebServiceRef, etc.) serves two purposes:
It declares a reference in the component namespace. For example, #EJB(name="myEJB") creates a reference java:comp/env/myEJB. If you annotate a field and do not specify a name, then it creates a reference java:comp/env/com.example.MyClass/myField.
If the annotation is declared on a field or setter method, then the container performs injection when the component is created.
How the reference is resolved varies, independent of whether the reference is being resolved for a lookup("java:comp/env/myEJB") or due to injection:
If EE 6+ is used, the lookup attribute requires a JNDI lookup to resolve the target.
Some application servers support mappedName, which is specified to be vendor specific. This is usually implemented by performing a lookup.
Application servers support bindings at deployment time. This is usually implemented by performing a lookup.
If no other binding information is provided and the bean interface (beanInterface or the field type) is only implemented by a single EJB in the application, then the EJB specification requires that it fall back to that.
If no other binding information is provided and #4 cannot work, some application servers will attempt to perform a lookup in the server namespace based on the ref name (for example, java:comp/env/myEJB might cause a lookup of myEJB in the server namespace).
Related
I'm trying to setup a Weld-JUnit4 Test for a JavaEE Bean which uses a TimerService. The Application runs in a Wildfly Application Server an So the TimerService is injected into the bean via #ResourceAnnotation.
In Weld-JUnit I have to bind Resources via:
WeldInitiator.from(<Some class).bindResource(nameOfRessource, <TimerServiceMock>)
But this doesn't work. The mock will not be injected.
So I tried #Resouce(name = "myTimer")in the JEE Bean. This doesn't work too.
So I tried #Resouce(lookup = "myTimer")in the JEE Bean. This works in my Testcase. But in ProductionCode this will change the lookupbehaviour. So it is no valid solution.
How it is possible to Mock the TimerService in a WeldJunitTest? Is there any kind of default lookup for the java.ejb.TimerService?
Thank you for your help.
EJB Spec states
16.14 TimerService References
The container must make the TimerService interface available either through injection using the Resource annotation or in JNDI under the name java:comp/TimerService, in addition to through the EJBContext interface. The authenticationType and shareable elements of the Resource annotation must not be specified.
So it should work if you use that name with the lookup attribute.
Alternatively:
16.2.2 Annotations for Environment Entries
[...]
A field of the bean class may be the target of injection. The field must not be final. By default, the name of the field is combined with the name of the class in which the annotation is used and is used directly as the name in the bean’s naming context. For example, a field named myDatabase in the class MySessionBean in the package com.acme.example would correspond to the JNDI name java:comp/env/com.acme.example.MySessionBean/myDatabase. The annotation also allows the JNDI name to be specified explicitly.
So you can also bind the JNDI-name that corresponds to the name of the field. It would allow you to get away with even less overhead in the EJB itself, but at the cost of breaking the test whenever you rename the field.
In my (non-trivial) Spring Boot 1.5.4 application with Spring Data REST and HATEOAS leveraging Spring websockets, I have some custom resource processors, some custom controllers, and some custom repositories. Sadly, when I use constructor injection in one particular Spring #Service class for a MessageSendingOperations dependency, my custom resource processors no longer get invoked. Reverting the constructor injection restores the execution of my custom resource processors, i.e. reverting from:
private final MessageSendingOperations<String> messageTemplate;
#Autowired
public ChannelHandler(MessageSendingOperations<String> messageTemplate) {
this.messageTemplate = messageTemplate;
}
to:
#Autowired
private MessageSendingOperations<String> messageTemplate;
"re-enables" my custom resource processors which results in a null messageTemplate. So, there's a problem somewhere...but where??? Any ideas how to track this down?
Have you tried making messageTemplate a lazily injected proxy? For example:
public ChannelHandler(#Lazy MessageSendingOperations<String> messageTemplate) {
this.messageTemplate = requireNonNull(messageTemplate, "messageTemplate");
}
From the Javadoc:
In addition to its role for component initialization, this annotation
may also be placed on injection points marked with Autowired or
Inject: In that context, it leads to the creation of a lazy-resolution
proxy for all affected dependencies, as an alternative to using
ObjectFactory or Provider.
This usually affects the initialization order of your beans, in this case allowing ChannelHandler to be initialized before MessageSendingOperations. Without #Lazy, MessageSendingOperations will be initialized first.
Also: as of Spring 4.3, #Autowired is no longer required for single argument constructors.
+1 for using constructor injection and final fields.
I'm not sure if this is a generic JEE6 question or if it is a Wildfly 10/JBoss7 EAP implementation specific question.
I'm trying to specify/override the default beanName used in my EJB JNDI mapping to something more meaningful to me.
For example:
LoginManagerBean:
#Stateless
public class LoginManagerBean extends BaseManagerBean implements LoginManager {
....
}
LoginManager:
#Local
public interface LoginManager{
....
}
In this context, WF10 will automatically create a JNDI mapping for this EJB as:
ejb:myApp/myJar/LoginManagerBean!LoginManager
In the Wildfly 10 documentation for EJB naming conventions, it says
For stateless beans:
ejb:<app-name>/<module-name>/<distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface>
.... ....
bean-name : This is the name of the bean for which you are doing the
lookup. The bean name is typically the unqualified classname of the
bean implementation class, but can be overriden through either
ejb-jar.xml or via annotations. The bean name part cannot be an empty
string in the JNDI name.
However, I cannot seem to find which annotation to use to specify the bean name in an annotation. If I read the docs for #EJB it states that the beanName parameter is:
The ejb-name of the Enterprise Java Bean to which this reference is mapped
So from the docs, it does not seem that the beanName is the right parameter to use.
So how can I rename my EJB beanName in the mapping to something of my choice? For instance, what annotation can I use to make the mapping read:
ejb:myApp/myJar/MyReallyCoolName!LoginManager
If you're using JBossEAP 7/WildFly 10.x then this is JavaEE 7, although the same answer applies to Java EE 6.
You only appear to be using Local interfaces, so none of the instructions that you linked apply because they are only for remote EJB clients. Therefore these statements:
In this context, WF10 will automatically create a JNDI mapping for this EJB as:
ejb:myApp/myJar/LoginManagerBean!LoginManager
are completely incorrect.
When you deploy your application all of the JNDI names are logged in the server console:
java:global/serverapp/LoginManagerBean!com.stackoverflow.p43282192.LoginManager
java:app/serverapp/LoginManagerBean!com.stackoverflow.p43282192.LoginManager
java:module/LoginManagerBean!com.stackoverflow.p43282192.LoginManager
java:global/serverapp/LoginManagerBean
java:app/serverapp/LoginManagerBean
java:module/LoginManagerBean
Most of the time you should not care about the JNDI names because in general each EJB is unique and the server will find the right implementation:
public class LoginClient {
#EJB
private LoginManager loginManager;
...
}
If you want to use JNDI lookups and you want to create more work for yourself then you can specify the bean name:
#Stateless(name="Foo")
public class LoginManagerBean implements LoginManager {
...
which yields:
java:global/serverapp/Foo!com.stackoverflow.p43282192.LoginManager
java:app/serverapp/Foo!com.stackoverflow.p43282192.LoginManager
java:module/Foo!com.stackoverflow.p43282192.LoginManager
java:global/serverapp/Foo
java:app/serverapp/Foo
java:module/Foo
and you can look these up if you must:
LoginManager loginManager = (LoginManager)(new InitialContext().lookup("java:app/serverapp/Foo"));
or using injection:
#EJB(beanName="Foo")
private LoginManager loginManager;
BTW, I'm just deploying the sample EJB jar here (serverapp.jar). Some of the names have an additional path element if you're using an EAR file.
For various reasons I need to perform a manual lookup of SessionContext. In JBoss5, the solution
InitialContext initialContext = new InitialContext();
SessionContext sessionContext = (SessionContext) initialContext.lookup("java:comp/EJBContext");
has served med well, but from JBoss 7 I instead get a
javax.naming.NameNotFoundException: EJBContext -- service jboss.naming.context.java.global.EJBContext
Has something changed in how context is looked up in JBoss 7.2, or is my deployment lacking anything vital? For reference, standard injection works fine, this is the only lookup that fails. Or am I doing something terribly wrong (besides performing a manual lookup of SessionContext)?
According to specification of Java EJB (this one is for EJB 3.2. but nothing changed about EJBContext from previous one, EJB 3.x), you can inject EJBContext into your components either using annotation #Resource or manually via lookup (section 11.15):
The container must make a component’s EJBContext interface available either through injection
using the Resource annotation or in JNDI under the name java:comp/EJBContext
Standard way of looking up for EJB resource is via EJBContext.lookup method but there is also JNDI way which is the only possibilities if you don't have already EJBContext:
Context initCtx = new InitialContext();
EJBContext ejbCtx = (EJBContext) initCtx.lookup("java:comp/EJBContext");
This is exactly what you did, so what is wrong? There are two things, which one I'm not sure about. First, with manually lookup it's sometime needed to assign resource to component with annotation at class level:
#Resource(name = "EJBContext", type = javax.ejb.EJBContext)
public class MyComponent {
...
}
but I'm not sure is it needed for EJBContext as well, I guess not. The second thing, more important and critical - according to specification once again:
EJBContext objects accessed through the naming environment are only valid within the bean
instance that performed the lookup.
this one is section 11.15.1, and the next one, section 11.15.2:
The Container Provider is responsible for providing an appropriate EJBContext object to the refer-
encing component. The object returned must be of the appropriate specific type for the bean requesting
injection or performing the lookup—that is, the Container Provider must return an instance of the SessionContext interface to referencing session beans and an instance of the MessageDrivenCon-
text interface to message-driven beans.
Those both mean that injection and lookup for EJBContext are only valid in Enterprise Java Beans, so those which are annotated with #MessageDriven, #Stateful, #Singleton or #Stateless (or described as EJBs in deployment descriptor file, also as EJB 2.x Specification). Maybe your component isn't valid EJB and it's why lookup isn't working? This is only suggestion of course.
There's one more possibilities to get EJBContext (more correctly SessionContext). Your component should implements SessionBean interface which has setSessionContext(SessionContext sessionContext) method. This method should be invoked by EJB container every time when component is used (injected somewhere, invoked by client or timeout, especially when it's created) and inside this method you should assign sessionContext parameter to bean's field.
I have the following configuration:
1 EAR on one GF containing 2 EJB-JARs with EJB components.
1 WAR on another Glassfish server (=> other JVM) containing web components accessing the EJB components.
I have 2 EJB business services in each EJB-JAR of my EAR, and they are all developped like this:
#Remote
public interface ServiceAItf {
...
}
#Stateless
#Local
public class ServiceAImpl implements ServiceAItf {
...
}
In my WAR, I access the EJB components via an explicit "InitialContext.lookup" on the remote interface.
In my EAR, I am quite confused about the best practice for injection, in terms of performance, architecture, and so on...
I have the following questions:
As you can see, I have declared the annotation "#Local" on the service implementation without defining the local interface. Is it correct? At least I have no error at deployment. But maybe I should use the "#LocalBean" annotation instead? I suppose that the "#LocalBean" annotation simply allows to invoke the implementation directly as a "Local" EJB, but you have to use the implementation in your code like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAImpl serviceA;
...
}
What is the best way to inject one EJB into another one?
It works like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#EJB
private ServiceAItf serviceA;
...
}
But from what I noticed, the "serviceA" injected is the remote proxy, while it is in the same JVM within the same EAR file. So I suppose that there will be an impact on the performance. That's why I have tried to inject the service like this:
#Stateless
#Local
public class ServiceBImpl implements ServiceBItf {
#Inject
private ServiceAItf serviceA;
...
}
But it doesn't work in GF, I have the following exception:
WELD-001408 Unsatisfied dependencies for type [...] ...
I then tried to create a local interface, and the injection via the annotation "#Inject" works when both services
Even if I create a local interface like this, the service is not injected via the annotation "#Inject" but is null:
#Local
public interface ServiceALocalItf {
...
}
I read a lot of articles where it is highly recommended to use "#Inject" instead of "#EJB" when it is for a local invocation. That leads me to the following question: in which case the "#Local" EJB invocation is recommended (or simply used)?
After all this analysis, I come to the following conclusion:
For each service, I create a "#Local" and a "#Remote" interface.
From WAR to EJB-JAR of EAR, make a JNDI lookup to the remote interface.
From EJB-JAR to EJB-JAR, make an injection via "#EJB" to the local interface.
For two services within the same EJB-JAR, make an injection via "#Inject" to the local interface.
What do you think about it? Is it correct?
As you can see, I have declared the annotation "#Local" on the service
implementation without defining the local interface. Is it correct?
With EJB 3.1, the requirement for local interfaces was dropped. No need to write them unless you explicitly need them.
What is the best way to inject one EJB into another one?
Couple of things to write here:
With Java EE 6, Java Enterprise has changed. A new JSR defines a so-called managed bean (don't confuse with JSF managed beans) as a sort of minimum component that can still benefit from the container in terms of dependency injection and lifecycle management. This means: If you have a component and "just" want to use DI and let the container control its lifecycle, you do not need to use EJBs for it. You'll end up using EJBs if - and only if - you explicitly need EJB functionality like transaction handling, pooling, passivation and clustering.
This makes the answer to your question come in three parts:
Use #Inject over #EJB, the concept of CDI (a) works for all managed
beans (this includes EJBs) and (b) is stateful and therefore far
superior over pure #EJB DI
Are you sure that you need EJBs for your
components?
It's definitely worthwhile to have a look at the CDI
documentation
#Inject annotation is used for java beans(POJOs) while #EJB annotation is used for enterprise java beans. When a container inject an ejb provided by #EJB annotation to another bean it also controls that ejb's lifecycle, performs pooling for stateless beans and so on(when bean which is going to be injected is not deployed the reference will be null). If you use #Inject annotation CDI mechanism simply find and create an instance of injected resource like with new operator(if the implementation of interface which is going to be injected doesn't exist the reference will be null). You can use qualifiers with #Inject annotation to choose different implementation of injected interface.