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.
Related
I have a bean defined in a appContext named MyBean in MyProject1.
I have in other app that injects all the bean definitions of MyProject1 (including MyBean).
Now I need to override that bean but there is no easy way , so in MyProject2 I make
<bean primary="true" class=MyBean />
It works great, my question is....
What will happen with all others that were using MyBean? Will now use the new bean with the primary=true or how can I specify which should use this new bean and which should keep using the old one?
Following spring documentation primary bean is used only if there are some candidates to be injected. All created beans are in the context.
If you need only your primary bean to be injected, you can use:
#Autowired
private MyBean myBean;
So all your old beans will be replaced with primary one.
If you need to handle all MyBean beans (for example you do Chain Of Responsibilities) you can inject:
#Autowired
private List<MyBean> myBeans;
and injected object would contain all your bean instances (primary and nonprimary). As Usual primary bean can be accessed from list by 0 index: myBeans.get(0). All alternative markers (for example filter by vendorType...) to detect bean that you needs you should specify and handle in you code filtering collection, but in usual way if project architecture doesn't have issues you have no needs make alternative markers filtering bean objects in collection.
Do not forget about singleton if you need only one bean in your context.
If you have specified different bean unique names you can inject with #Qualifier (sometimes using #Resource from java API javax.annotation.Resource) specifying correspond name as parameter to detect bean by name.
Spring provides ability to inject properties using SpEL. May be they'll provide new functionality to inject beans using SpEL also (it could help you in your issue in best way).
Use profiles or #Conditional. #Qualifier is meant for resolving conflict for autowire, not for deactivating all but one. When using #Qualifier, all the candidate beans are still active.
Using profiles, when you want to use the bean from project2, simply start the app with a profile=project2; the link above describes multiple ways to do that.
See my answer here for a complete example of using #Conditional.
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.
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).
I'm writing a service registry class. This service registry will scan packages for annotated classes and then populate some internal map. What I need then, is to be able to query for services (by String name) using some method (let's say Object get(String name)). This method will then search internal map for a service with such name and returns instance.
What I'm doing right now, is having this ServiceRegistryBean implement ApplicationContextAware and BeanDefinitionRegistryPostProcessor and a list of Strings (package names) given on construct.
Then, as soon as the bean is constructed, registry post processor kicks in (see note) and the registry class adds the service classes as new beans (singleton, lazy loaded) to the spring bean registry. Then, getting the service instance is as simple as requesting a bean from context, returning singleton instance.
My question is: is there a better way in Spring to do this? I've looked into bean factories, but it does not seem to me the same. Support for auto-wiring and DI in service instances is essential, that's why I want Spring to instantiate it. Also, I like the idea of Spring taking care of singletons.
Note: I've found out, that when I inline the bean creation in <constructor-arg> (that is, bean is not named and is just an instance passed as constructor argument of other bean - in my case, I'm passing registry as a parameter to other constructor), BeanDefinitionRegistryPostProcessor interface methods (namely public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)) is not called at all! I'm quite sure, it is some behavior of Spring I don't know about, but I was not able to find proper documentation for the post-processor.
Thank you for any hints or insights!
Scanning for custom annotations it's already supported, you only need to add a include-filter to <context:component-scan> tag, ie
<context:component-scan base-package="org.example">
<context:include-filter type="annotation" expression="some.Annotation"/>
</context:component-scan>
see http://static.springsource.org/spring/docs/current/spring-framework-reference/html/beans.html#beans-scanning-filters
If you turn on default-lazy-init I suppose that the DI Container is ready to use as Service Locator Registry.
About the note, only root bean definitions are taken into account when looking for BeanFactoryPostProcessors, inner beans are ignored.
Usually, scanning and registering beans is done by BeanDefinitionParsers instead because you known when the beans are registered and beans are visible for tools, like STS Spring Bean Explorer, but using a BeanDefinitionRegistryPostProcessor is correct. The interface ensures that beans are defined before other BeanFactoryPostProcessors run.
The Java EE specification states that an EJB injection like this:
#EJB MyInterface myBean;
will create en entry in the Enterprise Naming Context, viz. java:comp/env/<FQN>.MyInterface/myBean. It is up to the deployer to bind this context entry to a real value and to inject this value in the myBean field.
Now I have the feeling I am missing something here:
Why is the context entry necessary? An instance of the requested EJB will be injected, so why is the entry in the context needed? Why does the injection has to happen via the context entry?
All the received answers did not address the issue: why is an ENC entry needed if the injection annotation gives enough information to resolve the injection (so my first thought was that it was redundant).
The answer is that the injection can be overridden in the deployment descriptor. This is because the EJB standard defines developer roles.
It assumes that the "bean provider" can request an injection, even provide default values. But the "application assembler" can override these values. The "bean provider" is assumed to use annotations or XML, and the "assembler" is assumed to mainly use the XML.
That is why the EJB standard defines this relation between the ENC and an injection.
I think if you need to inject an Stateful Session Bean you gonna need some context that knows the relation between your EJB instance and some previously injected EJB dependency (to that instance).
It is to allow you lookups by somehow obtained string.