Using injected EntityManager in class hierarchies - java

The following code works:
#Stateless
#LocalBean
public class MyClass
{
#PersistenceContext(name = "MyPU")
EntityManager em;
public void myBusinessMethod(MyEntity e)
{
em.persist(e);
}
}
But the following hierarchy gives a TransactionRequiredException in Glassfish 3.0 (and standard JPA annotations with EclipseLink.) at the line of persist.
#Stateless
#LocalBean
public class MyClass extends MyBaseClass
{
public void myBusinessMethod(MyEntity e)
{
super.update(e);
}
}
public abstract class MyBaseClass
{
#PersistenceContext(name = "MyPU")
EntityManager em;
public void update(Object e)
{
em.persist(e);
}
}
For my EJB's I collected common code in an abstract class for cleaner code. (update also saves who did the operation and when, all my entities implement an interface.)
This problem is not fatal, I can simply copy update and sister methods to subclasses but I would like to keep all of them together in a single place.
I didn't try but this may be because my base class is abstract, but I would like to learn a proper method for such a (IMHO common) use case.

AFAIK, you can't inject into a super class, so you have to inject into a field or method of the actual EJB. You could do something like this:
public class MyBaseEJB {
public abstract EntityManager getEM();
public void update(Object e) {
getEM().persist(e);
}
}
#Stateless
public class MyEJB extends MyBaseEJB {
#PersistenceContext
EntityManager em;
public EntityManager getEM() { return em;}
}
Update: I was wrong, according to the section 5.2.3 of the Java EE 5 platform specification, injection is allowed in super class fields and methods.
I went a bit further and did a small test on my side using similar code, GlassFish v3 and EclipseLink and I can't reproduce your problem. So I suspect some kind of problem with your persistence.xml. Could you provide it? Are you using a transaction-type="JTA"? Just in case, here is the one I used:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence persistence_2_0.xsd" version="2.0">
<persistence-unit name="MyPU" transaction-type="JTA">
<!-- EclipseLink -->
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/q2484443</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.ddl-generation.output-mode" value="database"/>
</properties>
</persistence-unit>
</persistence>
BTW, I think that it's perfectly fine to skip the DAO pattern for simple data access operations. Have a look at this previous answer.

Your approach isn't wrong (if it works)
However it is more common to either use (inject) a Dao and call methods on it, or if the Dao is a redundant layer that only wraps the EntityManager, you can simply call the methods on EntityManager directly. Of course, exposing the EntityManager to subclasses via a protected getter.
getEntityManager().persist(e);

The problem was not using superclass' injected entity manager, but calling another EJB's method: e.g.
#Stateless
#LocalBean
public class MyBean extends MySuperBean
{
#EJB
com.example.project.MyOtherBean otherBean;
public boolean myService(String userName, MyEntity entity)
{
if(otherBean.checkAuthority(userName))
{
super.insert(entity);
}
}
}
I was using this pattern when OtherBean was not a bean and checkAuthority was a static method using (non-JTA) EntityManagerFactory. Then I changed OtherBean to extend MySuperBean too. I think, in this case, when OtherBean ends checkAuthority, JTA ends the transaction and MySuperBean's insert can't find a transaction to persist entity. Understandably Stateless EJB's don't let fellow EJB's to proceed the transaction.
As Pascal, I initially thought that injection does not work with inheritance but this problem continued when I directly called em.persist() in the subclass. After this I finally was able to check other possible causes.
Thanks for all the input.

Related

EntityManager object is not getting injected with Glassfish and Spring

I have been trying to create a job to delete all records from database. This job is deployed with my webservice. In webservice I can easily access my EntityManager and it's having no issues so far. But, whenever I try to access EntityManager in my scheduler then it gives me NullPointerException. Even I have tried to inject a service that I have created and tried to access it's method. The method which have no database related work is working fine and returning me result. But, the method which is using entityManager inside is throwing me the same exception.
While if I directly call the service using URL each and everything works fine in service as well.
#Service
public class DeletionJob {
#PersistenceContext(unitName = "my_pu")
private EntityManager em;
#Autowired
private REST restClass;
#Scheduled(fixedDelay=10000)
public void run() {
boolean flag = false;
System.out.println(restClass.executeWithoutDB());
System.out.println(restClass.executeWithDB());
}
}
Configuration Class:
#EnableWebMvc
#Configuration
#EnableScheduling
#ComponentScan({ "com.jobs.*" })
#javax.ws.rs.ApplicationPath("webresources")
public class AppConfig extends Application {
#Bean
public DeletionJob myDeletionJob() {
return new DeletionJob();
}
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver
= new InternalResourceViewResolver();
return viewResolver;
}
#Bean
public REST restClass(){
return new REST();
}
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
addRestResourceClasses(resources);
return resources;
}
/**
* Do not modify addRestResourceClasses() method.
* It is automatically populated with
* all resources defined in the project.
* If required, comment out calling this method in getClasses().
*/
private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(com.service.REST.class);
// Tried to include deletionjob class here but, no luck still the same.
// resources.add(com.jobs.DeletionJob.class);
}
}
persistance.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="my_pu" transaction-type="JTA">
<jta-data-source>ds</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
I have also tried to use this PersistenceAnnotationBeanPostProcessor component. But after including spring-orm it has even started giving me excpetion of BeanInitializationException. Secondly, I am not fond of using too many libraries. So, would like to do this thing in a simplest possible way. I could do it by looking up JNDI, but, the problem is that I want to use Spring or JAVA EE 6 scheduler API.
Version of GlassFish Server: 4.1
#PersistenceContext is simply getting ignored here.
An entity manager can only be injected in classes running inside a transaction.
Use an EntityManagerFactory to create and destroy an EntityManager.
#PersistenceUnit(unitName = "my_pu")
private EntityManagerFactory entityManagerFactory;
And inside your method use below line to create EntityManager:-
EntityManager entityManager = entityManagerFactory.createEntityManager();
Refer this link:- Injection of Persistence Context in spring
I feel your Persistence Context is not getting initialized properly.

Managing Multiple Database Connections

I've been struggling with this problem for days,
Here is the scenario:
I have several databases, one for each of my customers, all of them with the same
structure(same tables and columns), so my application needs to decide at runtime with which one it needs to connect. I'm using JPA2, EclipseLink and EJB3.
My first attempt was to implement a custom EntityManager with all the logic to performs the operations on the right database, then I configured this EntityManager as an Stateless EBJ in order to make it possible to inject it with the #EBJ annotation (as described at this link: http://www.hostettler.net/blog/2012/11/20/multi-tenancy/). I coundn't make it work because it was throwing an exception when trying to inject the EntityManager.
So I decided to try something else, I've created EntityManagerFactory and I passed the
JTA_DATASOURCE to it(after decide at runtime which one to use), so it could connect to the
right database.
Here is the code:
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class TestEntDAO {
private EntityManager em;
private EntityManagerFactory emf;
#PostConstruct
public void init() {
em = getEntityManager();
}
public EntityManager getEntityManager() {
Map props = new HashMap();
props.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA");
props.put(PersistenceUnitProperties.JTA_DATASOURCE, dataSourceName());
emf = Persistence.createEntityManagerFactory("testePU", props);
em = emf.createEntityManager();
return em;
}
public String dataSourceName(){
if(someCondition){
return "db1";
}else{
return "db2";
}
}
}
This worked perfectly, the only problem is that the transaction is not managed by the
container, so I had to explicitly mark the transaction's boundaries(call begin() and
commit()). I could just use the #PersistenceContext annotation to make it work, but then I
wouldn't have the EntityManagerFactory to pass the datasource.
Does anyone know of a way to use the Container-Managed Transactions(CMT) and still be able
to pass the datasource?
Maybe try to define 3 Data sources and 3 Persistence units.
<persistence-unit name="PU1">
<jta-data-source>jdbc/DS1</jta-data-source>
...
</persistence-unit>
<persistence-unit name="PU2">
<jta-data-source>jdbc/DS2</jta-data-source>
...
</persistence-unit>
<persistence-unit name="PU3">
<jta-data-source>jdbc/DS3</jta-data-source>
...
</persistence-unit>
And inject Entity manager from whatever Persistence unit you want.
#PersistenceContext(unitName = "PU2")
EntityManager em;
This should work, although I didn't test it.

A JTA EntityManager cannot use getTransaction()

How can I use the following code in my non-ejb application. The code works.
#Override
public void saveItems(Collection<T> items) {
synchronized (em) {
EntityTransaction tx = em.getTransaction();
try {
tx.begin();
for (T item : items) {
saveItem_((Class<T>) null, item);
}
tx.commit();
} finally {
if (tx.isActive()) {
tx.rollback();
}
}
}
}
In a new application I'm using EJB3 + JSF and would like to re-use the library containing the code above. My peristence unit for the new application looks like this:
<persistence-unit name="myApp" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>MySQLConnection</jta-data-source>
</persistence-unit>
My new application throw an exception when it hits this line:
EntityTransaction tx = em.getTransaction();
the exception is:
A JTA EntityManager cannot use getTransaction()
Which is clear enough. The question is how would I convert my code to have the transactions managed by the container. Presumably my bean methods need to be annotated appropriately... The question is how?
EntityTransaction is used with entity manager of type resource local. If you want to use JTA, then have to use UserTransaction interface.
From Documentation : EntityTransaction - Interface used to control transactions on resource-local entity managers. The EntityManager.getTransaction() method returns the EntityTransaction interface.
Edit: Added pseudo code.
#Resource
private SessionContext sessionContext;
void execute(){
UserTransaction userTxn = sessionContext.getUserTransaction();
try{
userTxn.begin();
/**
* do-something
*/
userTxn.commit();
} catch(Throwable e){
userTxn.rollback(); //-- Include this in try-catch
}
}
In the simplest case - it just works. If you have your EntityManager injected into EJB and use no special annotations, the transaction will open in the first EJB method entered (this means that if EjbA calls EjbB and that in turn calls EjbC, only one transaction will be used across all the EJB methods). If you want to modify how transactions are controlled, look up #Transaction.
The simplest way to do a rollback is to throw an exception marked with #ApplicationException(rollback=true)
I may be wrong, but judging from your code you should read up on the difference between EXTENDED and NORMAL EntityManager. It looks like you are using an extended em in a very awkward way (moving the loop out of transaction would help you get rid of finally).
Small edit: if you try to use UserTransaction, as the other post suggests, you will get an error, because a standard EntityManager (that you are probably using) uses the so called CMT (Container Managed Transactions). Don't touch it, unless you understand the three basic opositions (if you want, I can elaborate, but frankly, you will NOT need it):
container managed EntityManager versus application managed EntityManager,
container managed transactions versus application managed transactions,
NORMAL EntityManager and EXTENDED EntityManager.
just to summarize the code that works for me on Jboss EAP6 and Hibernate 4.2.18.Final.
May save time for someone.
persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="myApp" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/MySQLConnection</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<!--
<property name="hibernate.show_sql" value="true" />
-->
</properties>
</persistence-unit>
java
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.transaction.UserTransaction;
public class MyClass {
#PersistenceContext(unitName = "myApp")
protected EntityManager em;
#Resource
UserTransaction utx;
public void execute(..) throws Exception {
try {
utx.begin();
em.remove(..);
em.merge(..);
em.persist(..);
utx.commit();
} catch (Exception ex) {
try {
utx.rollback();
} catch (Exception re) {
throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
}
throw ex;
}
}
}
pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<scope>provided</scope>
</dependency>
links:
Application-Managed Entity Managers https://docs.oracle.com/cd/E19798-01/821-1841/bnbra/index.html
How does the UserTransaction and the EntityManager interact?
"May save time for someone."
It sure saved me time! I wish I'd found your solution days ago. I've been struggling with how to handle bean-managed transactions in the context of a JTA persistence unit. Most of our use is only one JPA DML call within a bean method. The problem was that after performing a single DML operation, a subsequent call (within the same bean method) to a stored procedure would fail, complaining about not being able to start another transaction within the running transaction. The documentation is thorough but ponderous.
This was key: #Resource UserTransaction utx;
Thank you!

JPA deceleration exception

I am using jboss5.1.x EJB3.0
I am trying my first time with JPA, and I get this exception when I run the server:
java.lang.IllegalArgumentException: Can't find a persistence unit named 'java:/mracDS'
..
this is my "DAO" entity which is responsible on all the JPA entities:
#Stateless
public class ECMSEntityManagerDao implements ECMSEntityManagerDaoLocal, ECMSEntityManagerDaoRemote
{
#PersistenceContext(unitName = "java:/mracDS")
EntityManager em;
public ArrayList<T01CounterCalls> getClocksDetailsFromVantive() throws SQLException
{
return (ArrayList<T01CounterCalls>) em.createQuery ("from T01CounterCalls as data").getResultList ();
}
}
I looked a bit in the net:
I never declared persistence.xml
and if I do, what should be declared inside?
thanks,
ray.
From the look of it my guess is that you are confusing a persistence unit with a data source.
These two may feel similar, but they aren't. Very simply said a persistence unit is a set of classes plus an associated data source. In the most basic form, a persistence unit merely couples to a data source:
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
>
<persistence-unit name="mracPU">
<jta-data-source>java:/mracDS</jta-data-source>
</<persistence-unit>
</persistence>
Then use the persistence unit name with the injection annotations:
#Stateless
public class ECMSEntityManagerDao implements ECMSEntityManagerDaoLocal, ECMSEntityManagerDaoRemote {
#PersistenceContext(unitName = "mracPU")
EntityManager em;
}

What to put into jta-data-source of persistence.xml?

What value should I place into <jta-data-source> of my persistence.xml?
In glassfish admin panel I created a datasource name "abcDS". In my jndi.properties (inside src/test/resources) I defined it like this:
[...]
abcDS=new://Resource?type=DataSource
abcDS.JdbcDriver=org.hsqldb.jdbcDriver
abcDS.JdbcUrl=jdbc:hsqldb:mem:testdb
abcDS.JtaManaged=true
[...]
What shall I place into persistence.xml? I've found a lot of variants in the Net, like: "jdbc/abcDS", "java:/abcDS", "abcDS". Which one is right? And is there some rule for this? I understand that it's related to JNDI, but...
I'm trying to create EMF in my unit test:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("abc");
This is what I'm getting in log:
[...]
SEVERE: Could not find datasource: abcDS javax.naming.NameNotFoundException:
Name "abcDS" not found.
at org.apache.openejb.core.ivm.naming.IvmContext.federate(IvmContext.java:193)
at org.apache.openejb.core.ivm.naming.IvmContext.lookup(IvmContext.java:150)
at org.apache.openejb.core.ivm.naming.ContextWrapper.lookup(ContextWrapper.java:115)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
[...]
The problem is that Persistence.createEntityManagerFactory("abc") is the "do it yourself" API and doesn't take advantage of the Embedded EJB Container. You can get a container managed EntityManager in your test case very easily.
Just as with the related jndi/datasource question I recommend you check out the examples in the examples.zip. They're all designed to take the struggle out of getting started.
Here's a snippet from the testcase-injection example which shows how you can get an EntityManager and other things from the container for use in a test.
First, add an empty ejb-jar.xml or application-client.xml to your test to turn on scanning for your test code:
src/test/resources/META-INF/application-client.xml
Then, annotate your test case with #org.apache.openejb.api.LocalClient and use the standard JavaEE annotations for the actual injection.
#LocalClient
public class MoviesTest extends TestCase {
#EJB
private Movies movies;
#Resource
private UserTransaction userTransaction;
#PersistenceContext
private EntityManager entityManager;
public void setUp() throws Exception {
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
p.put("movieDatabase", "new://Resource?type=DataSource");
p.put("movieDatabase.JdbcDriver", "org.hsqldb.jdbcDriver");
p.put("movieDatabase.JdbcUrl", "jdbc:hsqldb:mem:moviedb");
InitialContext initialContext = new InitialContext(p);
// Here's the fun part
initialContext.bind("inject", this);
}
As movieDatabase is the only DataSource that we've setup, OpenEJB will automatically assign that DataSource to your persistence unit without the need to modify your persistence.xml. You can even leave the <jta-data-source> or <non-jta-data-source> empty and OpenEJB will still know what to do.
But for the sake of completeness, here's how this particular application has defined the persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="movie-unit">
<jta-data-source>movieDatabase</jta-data-source>
<non-jta-data-source>movieDatabaseUnmanaged</non-jta-data-source>
<class>org.superbiz.testinjection.Movie</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
</properties>
</persistence-unit>
</persistence>
Then the fun part, using it all together in tests
public void test() throws Exception {
userTransaction.begin();
try {
entityManager.persist(new Movie("Quentin Tarantino", "Reservoir Dogs", 1992));
entityManager.persist(new Movie("Joel Coen", "Fargo", 1996));
entityManager.persist(new Movie("Joel Coen", "The Big Lebowski", 1998));
List<Movie> list = movies.getMovies();
assertEquals("List.size()", 3, list.size());
for (Movie movie : list) {
movies.deleteMovie(movie);
}
assertEquals("Movies.getMovies()", 0, movies.getMovies().size());
} finally {
userTransaction.commit();
}
}

Categories

Resources