Is it okay to pass injected EntityManagers to EJB bean's helper classes and use it?
Asked Answered
K

3

6

We have some JavaEE5 stateless EJB bean that passes the injected EntityManager to its helpers.

Is this safe? It has worked well until now, but I found out some Oracle document that states its implementation of EntityManager is thread-safe. Now I wonder whether the reason we did not have issues until now, was only because the implementation we were using happened to be thread-safe (we use Oracle).

@Stateless
class SomeBean {
    @PersistenceContext
    private EntityManager em;

    private SomeHelper helper;

    @PostConstruct
    public void init(){
        helper = new SomeHelper(em);
    }

    @Override
    public void business(){
        helper.doSomethingWithEm();
    }

}

Actually it makes sense.. If EntityManager is thread-unsafe, a container would have to do

inercept business()
this.em = newEntityManager();
business();

which will not propagate to its helper classes.

If so, what is the best practice in this kind of a situation? Passing EntityManagerFactory instead of EntityManager?

EDIT: This question is very interesting so if you are interested in this question, you probably want to check out this one, too:

EDIT: More info. ejb3.0 spec

4.7.11 Non-reentrant Instances The container must ensure that only one thread can be executing an instance at any time. If a client request arrives for an instance while the instance is executing another request, the container may throw the javax.ejb.ConcurrentAccessException to the second client[24]. If the EJB 2.1 client view is used, the container may throw the java.rmi.RemoteException to the second request if the client is a remote client, or the javax.ejb.EJBException if the client is a local client.[25] Note that a session object is intended to support only a single client. Therefore, it would be an application error if two clients attempted to invoke the same session object. One implication of this rule is that an application cannot make loopback calls to a session bean instance.

And,

4.3.2 Dependency Injection A session bean may use dependency injection mechanisms to acquire references to resources or other objects in its environment (see Chapter 16, “Enterprise Bean Environment”). If a session bean makes use of dependency injection, the container injects these references after the bean instance is created, and before any business methods are invoked on the bean instance. If a dependency on the SessionContext is declared, or if the bean class implements the optional SessionBean interface (see Section 4.3.5), the SessionContext is also injected at this time. If dependency injection fails, the bean instance is discarded. Under the EJB 3.0 API, the bean class may acquire the SessionContext interface through dependency injection without having to implement the SessionBean interface. In this case, the Resource annotation (or resource-env-ref deployment descriptor element) is used to denote the bean’s dependency on the SessionContext. See Chapter 16, “Enterprise Bean Environment”.

Kelikeligot answered 8/3, 2010 at 7:1 Comment(3)
Now this is interesting "The EJB 3.1 Spec says that dependency injection is only performed at construction time, so that all callers of MyRepository would use the same instance of EntityManager." :#2015684Kelikeligot
FYI, read also § 4.1.13, or see this answer #1954637. So each helper will be accessed by one thread at a time.Hecto
This is exactly the pattern I was thinking of implementing. I'm very happy to see that it is possible. Great post. Thanks.Sorcim
H
2

I used a similar pattern, but the helper was created in @PostConstruct and the injected entity manager was passed in the constructor as parameter. Each EJB instance had its own helper and thread-safety was guaranteed then.

I also had a variant were the entity manager was not injected (because the EJB wasn't using it altogether), so the helper has to look it up with InitialContext. In this case, the Persistence context must still be "imported" in the parent EJB with @PersistenceContext:

@Stateless 
@PersistenceContext(name="OrderEM") 
public class MySessionBean implements MyInterface { 
  @Resource SessionContext ctx; 
  public void doSomething() { 
     EntityManager em = (EntityManager)ctx.lookup("OrderEM"); 
     ... 
  } 
}

But it's actually easier to inject it (even if the EJB doesn't use it) than to look it up, especially for testability.

But to come back to your main question, I think that the entity manager that is injected or looked up is a wrapper that forwards to the underlying active entity manager that is bound to the transaction.

Hope it helps.

EDIT

The section § 3.3 and § 5.6 in the spec cover a bit the topic.

Hecto answered 8/3, 2010 at 8:49 Comment(1)
Thanks, I'm glad to hear we don't have to dig through our production code!Kelikeligot
B
2

I've been using helper methods and passed the EntityManager there, and it is perfectly OK.

So I'd recommend either passing it to methods whenever needed, or make the helper a bean itself, inject it (using @EJB) and inject the EntityManager there as well.

Blanding answered 8/3, 2010 at 7:13 Comment(0)
H
2

I used a similar pattern, but the helper was created in @PostConstruct and the injected entity manager was passed in the constructor as parameter. Each EJB instance had its own helper and thread-safety was guaranteed then.

I also had a variant were the entity manager was not injected (because the EJB wasn't using it altogether), so the helper has to look it up with InitialContext. In this case, the Persistence context must still be "imported" in the parent EJB with @PersistenceContext:

@Stateless 
@PersistenceContext(name="OrderEM") 
public class MySessionBean implements MyInterface { 
  @Resource SessionContext ctx; 
  public void doSomething() { 
     EntityManager em = (EntityManager)ctx.lookup("OrderEM"); 
     ... 
  } 
}

But it's actually easier to inject it (even if the EJB doesn't use it) than to look it up, especially for testability.

But to come back to your main question, I think that the entity manager that is injected or looked up is a wrapper that forwards to the underlying active entity manager that is bound to the transaction.

Hope it helps.

EDIT

The section § 3.3 and § 5.6 in the spec cover a bit the topic.

Hecto answered 8/3, 2010 at 8:49 Comment(1)
Thanks, I'm glad to hear we don't have to dig through our production code!Kelikeligot
D
0

Well, personally, I wouldn't like to have to pass the Entity Manager to all my POJOs in my constructors or methods. Especially for non-trivial programs where the number of POJOs is large.

I would try to create POJOs/HelperClasses that deal with the Entities returned by the EntityManager, instead of using the entitymanager directly.

If not possible, I guess I'd create a New EJB Bean.

Doe answered 28/10, 2011 at 11:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.