Since the JSR-220 Expert Group introduced annotation-based dependency injection and the Java Persistence API as part of Java EE 1.5, it’s been possible to inject an EntityManager
or EntityManagerFactory
into most Java EE components using the dedicated @PersistenceContext
and @PersistenceUnit
annotations respectively.
Later, my JSR-299 Expert Group introduced a completely new approach to dependency injection, which ultimately came to be named Contexts and Dependency Injection for Java. Initially very controversial, CDI has over time become central to the Java EE platform—oops, I mean, Jakarta EE—and other technologies have adopted CDI, now in its sixth revision, as the base-level component model.
But back in CDI 1.0, I needed a way to bridge the gap between @PersistenceContext
and the @Inject
annotation supported by CDI.
And with CDI itself mired in FUD, I wasn’t exactly in a very strong political position to go asking the EE platform group to redefine their, at the time, pretty much brand-new dependency injection annotations in terms of the crazy new direction we were taking with CDI.
So my solution—which I considered quite elegant at the time—was to let you define a mapping in Java. For example, we may define the following mappings:
public class Databases {
@Produces @PersistenceContext(unitName="UserData")
@Users EntityManager userDatabaseEntityManager;
@Produces @PersistenceContext(unitName="DocumentData")
@Documents EntityManager docDatabaseEntityManager;
}
And then inject the EntityManager
s as follows:
@Inject @Users EntityManager userDatabaseEntityManager;
@Inject @Documents EntityManager docDatabaseEntityManager;
More recently, it came to my attention that some people have never loved my elegant solution; that, indeed, most people appear to view it as a "hack"; and that such people do not appear to be easily dislodgeable from this position. 😭
Therefore, we’ve proposed something different for Jakarta EE 11. You can read the specification here.
The idea is that if you have just one persistence unit, you’ll be able to inject its EntityManager
or EntityManagerFactory
just like this:
@Inject EntityManager em;
@Inject EntityManagerFactory emf;
If you have more than one persistence unit, then you may assign a CDI qualifier annotation to the unit using the new <qualifier>
XML element in persistence.xml
.
<persistence-unit name="UserData">
...
<qualifier>my.program.Users</qualifier>
...
<persistence-unit name="DocumentData">
...
<qualifier>my.program.Documents</qualifier>
...
And then you may write, as before:
@Inject @Users EntityManager userDatabaseEntityManager;
@Inject @Documents EntityManager docDatabaseEntityManager;
By default, such an injected EntityManager
has scope @TransactionScoped
.
But occasionally we would like more flexibility here.
How can we get something like a JPA extended persistence context?
Well, we’ve also decided to hand you the following weapon, one that’s easily-orientable along the negative-y axis:
<persistence-unit name="UserData">
...
<qualifier>my.program.Users</qualifier>
<scope>javax.enterprise.context.RequestScoped</scope>
...
<persistence-unit name="DocumentData">
...
<qualifier>my.program.Documents</qualifier>
<scope>javax.enterprise.context.ConversationScoped</scope>
...
Please, please understand that absolutely nothing about the existence of the <scope> element gives you permission to start sharing a stateful persistence context between concurrently-executing code.
|
Naturally, the EntityManagerFactory
is always @ApplicationScoped
.
The new functionality even goes a bit beyond this: not only can we inject an EntityManager
or EntityManagerFactory
, but, for convenience, we can even inject certain helper objects: CriteriaBuilder
, PersistenceUnitUtil
, Cache
, SchemaManager
, and Metamodel
using the same annotations.
I hope you like it!