Mind thread-safety when injecting EntityManager (2)

Continuing from the post Mind thread-safety when injecting EntityManager, here is a second part: container-managed EntityManager vs application-managed EntityManager.

There are important differences between the injected EntityManager, and the EntityManager created from an injected EntityManagerFactory. Basically, injected EntityManager is container-managed, meaning all of its lifecycle is controlled by the container (web container or EJB container). Application code cannot close it, or otherwise interfere with its life.

In addition, for a container-managed EntityManager, its associated PersistenceContext is automatically propagated along with the underlying JTA, from servlet A to servlet B, from servlet to EJB, from EJB a to EJB B, and so on. As such, EntityManager of the same configuration injected into various classes can share the same PersistenceContext in a call stack.

On the other hand, EntityManager created from EntityManagerFactory is application-managed EntityManager. Application code is responsible for managing its whole lifecycle. And there is no PersistenceContext propagation for application-managed EntityManager.

Are all EntityManager's obtained from EntityManagerFactory application-managed EntityManager? Yes.

Is it possible to get a container-managed EntityManager from EntityManagerFactory? No.

You may have read about the method EntityManagerFactory.getEntityManager(), which returns a container-managed EntityManager. This method was considered and included in the early draft version of Java Persistence API, but was eventually removed from its final release.

Mind thread-safety when injecting EntityManager

As I wrote in post Why we need type-level injections in JavaEE, injecting EJB 3 stateful beans into servlet instance fields is not thread-safe. Along the same line, injecting EntityManager with @PersistenceContext into servlet instance variables is not thread-safe, either. EntityManager is just not designed to be thread-safe.

For example, the following code snippet of a servlet class is incorrect:
public class FooServlet extends HttpServlet {
//This field injection is not thread-safe.
//FIXME
@PersistenceContext
private EntityManager em;
...
}
One way to fix this is to inject EntityManagerFactory instead. EntityManagerFactory is guaranteed to be thread-safe. For example:
public class FooServlet extends HttpServlet {
//This field injection is thread-safe
@PersistenceUnit
private EntityManagerFactory emf;

protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
EntityManager em = emf.createEntityManager();
//work with em
}
}

Resource Injection and Findbugs

Findbugs should have a place in every Java developer's toolbox. But it doesn't seem to understand Java EE resource injection yet, giving some false alarms.

If I run findbugs on this simple JavaEE application client code:
public class AppClientMain {
@EJB
protected static CalculatorRemote calc;

public static void main(String[] args) {
AppClientMain main = new AppClientMain();
main.calculate();
}

public void calculate() {
calc.calculate();
}
}
FindBugs will emit at least 2 false alarms:
1. Class AppClientMain(Priority 1, Category MALICIOUS_CODE)
MS_SHOULD_BE_FINAL: AppClientMain.calc isn't final but should be

A mutable static field could be changed by malicious code or by
accident from another package. The field could be made final to
avoid this vulnerability.
The injection field in application client main class must be declared static, though it can use any access modifier like public, protected, package private, or private. That's the rule. If I change the field to final, as suggested by findbugs, the container (application client container) won't be able to inject anything into it. However, once I change the field to private, findbugs is happy.

BTW, just to be clear, injection fields in all components other than application client main class or its superclass must not be static. In all cases, injection fields must not be final. But I don't think findbugs need to complain about non-final instance fields.
2. Class AppClientMain(Priority 2, Category CORRECTNESS)
NP_UNWRITTEN_FIELD: Read of unwritten field calc in
AppClientMain.calculate()

The program is dereferencing a field that does not seem to ever
have a non-null value written to it. Dereferencing this value
will generate a null pointer exception.
Another variant of this warning is:
UWF_UNWRITTEN_FIELD: Unwritten field:...This field is never written.
All reads of it will return the default value. Check for errors
(should it have been initialized?), or remove it if it is useless.
No, this shouldn't result in NPE. If you do see NPE at runtime, it can only mean one of the following:

1. Your application is not properly configured. For instance, the @EJB reference cannot be resolved to a deployed EJB. Then you need to make sure the @EJB reference is correctly mapped via @EJB(mappedName) attribute, mapped-name, ejb-link, or jndi-name elements in descriptors and deployment plans. Most likely, your server should already reported a NameNotFoundException in server log.

2. A bug in your application server, which is much less likely than (1) but still possible.

Why we need type-level injections in JavaEE?

As I wrote in the previous post, JavaEE type-level injection is more verbose than field and setter injections. So why don't we just all use the simple field or setter injections? Well, there are some times a type-level injection is more appropriate

1. You want to lazily initialize a field such as a data source or bean. Having the container to initialize a field via field injection or setter injection has its overhead. With type-level injection, you have the resource and EJB reference fully configured without descriptors, but defer the actual initialization. Whenever you need the resource, just look it up.

Type-level injection also works well if you want to reference the injected resource in some non-component utility classes that are in the same naming context. Since only JavaEE component classes can take injections, you can't inject into POJO utility classes. For example, you can
@Resource(type=javax.sql.DataSource.class, 
name="jdbc/defaultDataSource,
mappedName="jdbc/__default")

public class FooServlet extends HttpServlet {
//the service method, or doGet, doPost, etc, references ServletUtil
}

public class ServletUtil {
private void help() throws ServletException {
//This is how to use the resource injected at type-level in FooServlet
Connection con = null;
try {
InitialContext ic = new InitialContext();
DataSource ds =
(DataSource) ic.lookup("java:comp/env/jdbc/defaultDataSource");
con = ds.getConnection();
} catch (NamingException ex) {
throw new ServletException(ex);
} catch (SQLException ex) {
throw new ServletException(ex);
} finally {
//close connection here
}
}
The above example will also if we instead use field or setter injection. But the instance filed in FooServlet class that takes the injection may not be used at all. Another approach is to pass the data source reference injected into FooServlet as method parameters to ServletHelper. But it pollutes the API. It appears more natural, at least to me, to use type-level injection in this case.

2. You want to restrict the scope or sharing of the variable that references the resource. Field and setter injections both use instance variables, which are accessible to all methods and all threads of the current component instance. Instance variables represent shared states. With type-level injections, you typically assign the resource to a local variable and thus is thread-safe.

This is the reason why you shouldn't inject an EJB 3 stateful session bean into a servlet class variable. In so doing, this stateful bean variable will be shared by all request-processing threads running inside the servlet's service method. Servlet is stateless, so it should not keep state (the stateful session bean reference).

Type-level injection in JavaEE

There are 3 types of resource injections in JavaEE: field injection, setter injection, and type-level injection, in the order of usage frequency.

Unlike field and setter injections, type-level injections are not really injection. It does not inject anything into anywhere; it just declares a resource reference in a descriptor-free manner.

To use resource injected at type-level, you will need to do a traditional JNDI lookup. What we have saved here, compared to pre-JavaEE-5, is there is no need for deployment descriptors.

A servlet example in glassfish:
@Resource(type=javax.sql.DataSource.class, 
name="jdbc/defaultDataSource,
mappedName="jdbc/__default")

public class FooServlet extends HttpServlet {
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
//This is how to use the resource injected at type-level
Connection con = null;
try {
InitialContext ic = new InitialContext();
DataSource ds =
(DataSource) ic.lookup("java:comp/env/jdbc/defaultDataSource");
con = ds.getConnection();
} catch (NamingException ex) {
throw new ServletException(ex);
} catch (SQLException ex) {
throw new ServletException(ex);
} finally {
//close connection here
}
}
Type-level injections are inherently verbose, compared to field and setter injections, where a bare @EJB or @Resource is sufficient in some cases. Field and setter injections can use the field type and parameter type to infer the resource type, respectively. Type-level injections can't. All the necessary attributes must be present.

For @Resource, you must specify at least name and type. For @EJB, you must have at least beanInterface and name.

Followers

Pageviews Last 7 Days