I'm working on a large Java EE 6 application that is deployed on JBoss 6 Final. My current tasks involve using #Inject consistently instead of #EJB, but I'm running into some problems on some types of beans, specifically #MessageDriven beans and beans with #Scheduled methods.
What happens is that if I'm unlucky with the timing (for #Schedule) or if there are messages in the MDBs' queues at startup, instantiation of the beans will fail because the injected resources (which are EJBs themselves) are not bound yet.
Because I use #Inject, I'm guessing that the EJB container considers my beans to be ready, since the container itself does not care about #Inject; it probably simply assumes that since there are no #EJB injections, the beans are ready for use. The injected CDI proxies will then fail because the resources to inject aren't actually bound yet.
Tiny example:
#Stateless
#LocalBean
public class MySupportingBean {
public void doSomething() {
...
}
}
#Singleton
public class MyScheduledBean {
#Inject
private MySupportingBean supportingBean;
#Schedule(second = "*/1", hour = "*", minute = "*", persistent = false)
public void onTimeout() {
supportingBean.doSomething();
}
}
The above example will probably not fail often because there are only two beans, but the project I'm working on binds lots of EJBs, which will amplify the problem. But it might fail because there is no guarantee that MySupportingBean is bound first, and if onTimeout is invoked before MySupportingBean is bound, then instantiation of MyScheduledBean will fail. If I used #EJB instead, MyScheduledBean wouldn't be bound until the dependency to MySupportingBean was satisfied.
Note that the example will not fail in onTimeout itself, but when CDI attempts to inject MySupportingBean.
I've read a lot of posts on different forums where many people argue that #Inject is always better. Generally, I agree, but how do they handle #Schedule or #MessageDriven combined with #Inject? In my experience, it comes down to dumb luck whether the beans will work or not in those cases, and the beans will fail arbitrarily, depending on which order the EJBs are deployed in, and when #Schedule or onMessage are invoked.
It might help to explicitly define the dependencies using the JBoss proprietary annotation #Depends or using the jboss.xml file.
See this for a somewhat similar question: How to order deployment of EJBs and JMS queue config in JBoss 5?
Related
With JEE 5 / EJB 3.0 life of Java developers became much more easier. Later, influenced by Spring and CDI, similar approaches were also adopted in JEE.
Now, I hope I am doing it right, but just to be sure:
I have several Stateless EJBs, which all query and / or modify the database. An example is
#Stateless
public class AddressDBService {
#PersistenceContext
protected EntityManager em;
Some of the Stateless EJB refer the other services like this:
#Stateless
public class AVeDBService {
#PersistenceContext
protected EntityManager em;
#Inject
private HomeToDealDBService homeToDealDBService;
#Inject
private AddressDBService addressDBservice;
and in the Stateless EJBs I have public methods like the ones below:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void saveEntity(Home home) throws EntityExistsException {
this.em.persist(home);
addressDBservice.saveAddress(home.getMainAddress(), home);
}
While I am almost certain this usage is correct and thread-safe (the above services are in turn injected into JSF Managed Beans).
Could somebody confirm that my usage is correct, thread-safe and conforms good practices?
My usage seems to be conform with the following questions:
Is EntityManager really thread-safe?
Stateless EJB with more injected EJBs instances
The "is correct?" question can't be answered without know the goal of the project.
It could works? Yes, you have posted java-ee code that could deploy, but is not enough.
I usually use BCE (Boundary Control Entity) pattern and Domain Driven pattern.
In this pattern we use EJB for business logic services or endpoint (JAX-RS) and all other injections, that are the Control part, are CDI objects.
Entities (JPA) could use cascade to avoid to manually save related entities:
addressDBservice.saveAddress(home.getMainAddress(), home);
can be avoided if you define the entity like this:
#Entity
public class Home {
#ManyToOne(cascade=ALL)
private Address mainAddress;
}
The #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) annotation usually respond to a specific transactions behavior, is not required, so is correct only if is what you want to do.
I am trying to use a #Transactional method inside a CDI class, instead of an EJB:
#javax.inject.Named
// fails #javax.enterprise.context.ApplicationScoped
// fails #javax.enterprise.context.SessionScoped
// works #javax.ejb.Singleton
// works #javax.ejb.Stateless
public class SomeClass {
#javax.persistence.PersistenceContext
private EntityManager em;
#javax.annotation.PostConstruct
#javax.transaction.Transactional
public void someMethod() {
em.persist(someEntity);
}
}
When I annotate SomeClass with #Singleton or #Stateless, everything works.
When I annotate SomeClass with #ApplicationScoped or #SessionScoped, WildFly 13 displays the following error message:
Transaction is required to perform this operation (either use a transaction or extended persistence context)
I was under the impression that #Transactional works with CDI since Java EE 7. Have I been mistaken? Or am I simply missing some additional configuration?
I'll try to give a short list of things to look when trying to make #Transactional work with CDI, so as to give the answer a bit more value than the comment:
We are discussing javax.transaction.Transactional, not javax.ejb.TransactionAttribute, which works for EJBs!
It does NOT work out-of-the-box in non-JEE applications!
And by JEE applications we mean those running a full JEE application server; Tomcat out-of-the-box does NOT support it!
Beware of classpath problems, specifically make sure no jar containing the annotation javax.transaction.Transactional exists e.g. in WEB-INF/lib, when running in a full JEE application server. If you want to utilize it in a non-full-JEE environment, you will need to have it in the classpath.
#Transactional is implemented as a CDI interceptor by the latest JTA specifications. As such:
It's not there in JEE < 7!
It has the same limitations as any interceptor. E.g. it cannot be called for initializer methods - #PostConstruct [THIS WAS THE PROBLEM IN THIS QUESTION], and it is NOT activated when invoking methods of this object, BEWARE!!!
I am quite confident that more errors may exist!!!
Looking at this answer, it says:
If you don't want to use an Application Client Container and instead just run the application client class through a java command, injection won't be possible and you'll have to perform a JNDI lookup.
However, given that I am trying to inject a DAO bean like the example shown here, if I cannot do the automatic injecting, it means my application must manually do the JNDI lookup and all the transaction begin/end that I would get for free if the #EJB actually worked.
However, since everything is all within the same Eclipse EJB Project (it also failed with the same null handle when I had my client code in a Dynamic Web Project), surely there must be an easy way to get it all working? Can anyone suggest what I am doing wrong?
Finally, this article suggests that DAOs are not needed, but if I replace within my EJB:
#EJB MyDao dao;
with the more direct:
#PersistenceContext private EntityManager em;
I still get the similar null value; is this the same injection failure problem?
NB: I have just noticed this answer:
This is a bug in Glassfish (apparently in the web services stack).
I am running v4.0 Build 89, which still has this bug? Does this mean I have to do all JPA actions the long-winded way?
I eventually found out that the problem/issue is that in order to use injection of the #PersistenceContext the class MUST be a bean itself. This is hinted at in the example on Wikipedia:
#Stateless
public class CustomerService {
#PersistenceContext
private EntityManager entityManager;
public void addCustomer(Customer customer) {
entityManager.persist(customer);
}
}
I could delete this question, but perhaps leaving this answer might provide a hint to someone, or at least show them a minimal working example of EJB and JPA.
I just started playing around with OSGi services and have the following situation. I have a project which contains 2 services. Service A requires Service B, so I tried to inject the dependent service using
#Inject
private ServiceB svc;
but the framework wont inject. If I setup the following two methods in Service A
and set these methods as "bind / undbind" in my OSGi componentA.xml the framework calls
these methods and I can use Service B in Service A.
public synchronized void bind(IServiceB service)
{
this.svc = service;
}
public synchronized void unbind(IServiceB service)
{
if (this.svc == service)
{
this.svc = null;
}
}
The question is, why does it not work with #Inject ? Sorry if this is a stupid question, I'm quite new to this whole topic. Many thanks in advance!
It looks like you are using Declarative Services, which does not support field injection or the JSR-330 annotations. Field injection has limited utility in OSGi, where services may be injected or "un-injected" at any time. Method injection is more generally useful because it gives you an opportunity to do something when this happens.
However I do urge you to use the annotations for Declarative Services. This will save you from having to write the component.xml by hand.
I would like to have the following kind of resource class work when deployed under RestEasy in JBoss 6:
#Path("Something")
public class Foo {
#EJB
private SomeService service
#GET
public Object frobnicate() {
assert service != null;
// JBoss blows up here
return result;
}
}
Two questions:
It is a limitation of RestEasy, not of the Java EE specification, right, that RestEasy can't inject anything annotated with #EJB?
What have people done to work around this limitation?
My developers are about to surge forward with hard-coded JNDI lookups (e.g. context.lookup(someHardCodedNameHere)) because no one can find a workaround to this specification violation at the present time. I really want to avoid this.
Lastly, I've looked at using CDI, but the story here isn't much better as RestEasy and CDI still aren't talking to each other.
Thanks in advance for any pointers.
The JBoss guys tell me this is being worked on on the trunk. So as of JBoss 6 milestone 3 this is impossible.