LazyInitializationException in SpringMVC frontend with EJB backend - java

I have an EJB application on JBoss AS 7.1.1, that use Hibernate 4.3 for database connection via jta-data-source. My persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
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">
<persistence-unit name="primary" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/postds</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.ProgressDialect" />
<property name="hibernate.connection.charSet" value="UTF-8" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
I use DAO pattern like this:
#Stateless
public abstract class GenericHibernateDAO<T, ID extends Serializable>
implements GenericDAO<T, ID> {
private Class<T> persistentClass;
#PersistenceContext
private EntityManager em;
protected Session getSession() {
return em.unwrap(Session.class);
}
public T save(T entity) {
getSession().saveOrUpdate(entity);
return entity;
}
...
In EJB backend all Lazy-initialized fields work fine. Now I need a small web admin panel for my backend. I am familiar with Spring MVC and decided use it. In Spring MVC is not a problem use EJB beans. But Lazy-initialized fields don't work in Spring controllers and I get:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
I tried to use OpenSessionInViewFilter in web.xml:
<filter>
<filter-name>openSessionFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSessionFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
OpenSessionInViewFilter needs sessionFactory bean. I added it's definition into applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">
<jee:jndi-lookup id="dataSource" jndi-name="java:/postds"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
But it did not solve my problem... Have you any advice?
Thanks a lot!

If you use EJB container manages transactions and sessions for you. After transaction commit (by default all EJB methods are transactional) container destroy the session. If you use lazy loading then you get the org.hibernate.LazyInitializationException.
Try use fetch join lazy loaded fields via HQL or Criteria API.
Please see this answer for more information.

Related

org.apache.openjpa.persistence.PersistenceException: Cannot set auto-commit mode when using distributed transactions

I setup simple java ee project and using jta transaction and using OpenJpa 2.4.2 as Jpa provider, maven 3.3, eclipse 2020-06, jdk 8U2002, weblogic 12.4.2 and java ee 6 and get this exception:
javax.ejb.EJBException: EJB Exception: : <openjpa-2.4.2-r422266:1777108 nonfatal general error> org.apache.openjpa.persistence.PersistenceException: Cannot set auto-commit mode when using distributed transactions
at org.apache.openjpa.jdbc.meta.MappingTool.record(MappingTool.java:571)
at org.apache.openjpa.jdbc.meta.MappingTool.record(MappingTool.java:467)
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:160)
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:164)
at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:122)
and this is my persistence.xml:
<?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
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="batch" transaction-type="JTA" >
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl </provider>
<jta-data-source>jdbc/new</jta-data-source>
<class>com.smartsoft.persistence.Person</class>
<validation-mode>NONE</validation-mode>
<properties>
<property name="openjpa.DynamicEnhancementAgent" value="false"/>
<property name="openjpa.RuntimeUnenhancedClasses" value="unsupported"/>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
<property name="openjpa.Log" value="DefaultLevel=TRACE"/>
</properties>
</persistence-unit>
</persistence>
I have a simple Entity class that has firstName and lastName and age fields and setter getter methods.
and an Stateless Ejb class that injects EntityManager with #PersistenceContext annotation and has save method that calls em.persist(Person) Then I inject this dao in a servlet and pass a person class to it.
This is my Weblogic.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.4/weblogic-web-app.xsd">
<wls:context-root>persistence</wls:context-root>
<wls:container-descriptor>
<wls:prefer-web-inf-classes>true</wls:prefer-web-inf-classes>
</wls:container-descriptor>
</wls:weblogic-web-app>
This is my dao class:
#Stateless
public class PersonEjb {
#PersistenceContext
private EntityManager entityManager;
private static final Logger logger =Logger.getLogger("PersonEjb");
public void save(Person person) {
entityManager.persist(person);
logger.info("persisted");
}
}
and This is servlet:
#WebServlet("/Serv1")
public class Serv1 extends HttpServlet {
private static final long serialVersionUID = 1L;
#EJB
private PersonEjb pe;
public Serv1() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Person p = new Person();
p.setAge(25);
p.setFirstName("hamidreza");
p.setLastName("abroshan");
pe.save(p);
response.getWriter().append("Served at: ").append(request.getContextPath());
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
You can download this project at github.
Thanks allot.
as OpenJpa documentation Section 2, “ Integrating with the Transaction Manager ”
says, I should add <property name="openjpa.TransactionMode" value="managed"/> to persistence.xml.
By this property, OpenJpa understands that should uses container's managed transaction.
In case of weblogic, I do not need to configure "openjpa.ManagedRuntime " property.
and according to Section 2.1, “ Managed and XA DataSources ”.
"When using a managed DataSource, you should also configure a second unmanaged DataSource that OpenJPA can use to perform tasks that are independent of the global transaction. The most common of these tasks is updating the sequence table OpenJPA uses to generate unique primary key values for your datastore identity objects. "
Note: If you do not set AutoStrategy id generation, and you created your database's schema and sequence before, and remove
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
from your persistence.xml, You do not need to second none jta dataSource.
So, this is my persistence.xml:
<?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
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="batch" transaction-type="JTA" >
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl </provider>
<jta-data-source>jdbc/new</jta-data-source>
<class>com.smartsoft.persistence.Person</class>
<validation-mode>NONE</validation-mode>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
<property name="openjpa.Log" value="DefaultLevel=TRACE"/>
<property name="openjpa.TransactionMode" value="managed"/>
<property name="openjpa.ConnectionFactoryMode " value="managed"/>
<property name="openjpa.Connection2UserName" value="app"/>
<property name="openjpa.Connection2Password" value="app"/>
<property name="openjpa.Connection2URL" value="jdbc:derby://localhost:1527/testdb;create=false"/>
<property name="openjpa.Connection2DriverName" value="org.apache.derby.jdbc.ClientDriver"/>
</properties>
</persistence-unit>
</persistence>

Configuration to be able to #Inject EntityManager in Seam 3

In my project I use Seam 3 and I am having issues injecting the EntityManager with the #Inject annotation. I am pretty sure there is some kind of configuration to make sure the EnityManager knows which PersistenceUnit to use. For example with EJB you can type:
#PersistenceContext(unitName="MY_PERSISTENCE_UNIT_NAME")
private EntityManager eManager;
which persistence unit is configured in the persistence.xml file. Here is my pseudo configuration:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
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">
<persistence-unit name="MY_PERSISTENCE_UNIT_NAME" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/TimeReportDS</jta-data-source>
<mapping-file>META-INF/orm.xml</mapping-file>
<class>....</class>
<class>....</class>
<class>....</class>
<properties>
<property name="jboss.entity.manager.factory.jndi.name"
value="java:/modelEntityManagerFactory" />
<!-- PostgreSQL Configuration File -->
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.password" value="password" />
<property name="hibernate.connection.url" value="jdbc:postgresql://192.168.2.125:5432/t_report" />
<property name="hibernate.connection.username" value="username" />
<!-- Specifying DB Driver, providing hibernate cfg lookup
and providing transaction manager configuration -->
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup" />
<property name="hibernate.archive.autodetection" value="class" />
<!-- Useful configuration during development - developer can see structured SQL queries -->
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="false" />
</properties>
</persistence-unit>
</persistence>
I have read some articles about Seam 2 but there the configuration is made in components.xml file by adding the:
<persistence:managed-persistence-context
name="entityManager" auto-create="true" persistence-unit-jndi-name="java:/modelEntityManagerFactory" />
inside the <components> tag. The next step in Seam 2 is to add the:
<property name="jboss.entity.manager.factory.jndi.name"
value="java:/modelEntityManagerFactory" />
in the persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence ...>
<persistence-unit name="MY_PERSISTENCE_UNIT_NAME" ...>
...
<properties>
...
<property name="jboss.entity.manager.factory.jndi.name"
value="java:/modelEntityManagerFactory" />
</properties>
</persistence-unit>
</persistence>
but it seam that in Seam 3 there is no file components.xml. Also there is no attribute unitName in #Inject annotation to specify the persistence unit.
So please help me to configure my project so I can use the #Inject with EntityManager as shown in many examples on the net.
I use Postgres database and JBoss AS 7.
EDIT: Adding an example. I don't use the EntityManager in an Entity class.
#Named("validateReportAction")
#SessionScoped
public class ValidateReportAction extends ReportAction implements Serializable {
private static final long serialVersionUID = -2456544897212149335L;
#Inject
private EntityManager em;
...
}
Here in this #Inject I get warning from Eclipse "No bean is eligible for injection to the injection point [JSR-299 §5.2.1]"
If I use the #Inject on some beans that are marked as Entity the #Inject works fine.
You can use #PersistenceContext on a CDI bean. It doesn't have to be an EJB.
If for some reason you want to use #Inject, you have to do more work. #Inject doesn't know about the EntityManager; it can only inject other managed beans. Happily, there is a simple workaround - use a producer method that acts as a simple trampoline.
#ApplicationScoped
public class EntityManagerProducer {
#PersistenceContext
private EntityManager entityManager;
#Produces
#RequestScoped
public EntityManager getEntityManager {
return entityManager;
}
public void closeEntityManager(#Disposes EntityManager em) {
if (em != null && em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
if (em != null && em.isOpen()) {
em.close();
}
}
}
You can now use #Inject to inject the EntityManager. The injected EntityManager will be RequestScoped, while the EntityManagerProducer is ApplicationScoped. Furthermore, the entityManager must be closed.

#PersistenceUnit annotation not working

I want to use the #PersistenceUnit annotation in my app to create an application managed EntityManager
#PersistenceUnit(unitName="primary")
private static EntityManagerFactory entityManagerFactory;
EntityManager entityManager = entityManagerFactory.createEntityManager();
This doesn't seem to be working. I run my code through a debugger and discover that entityManagerFactory is null. My guess is that the injection of Persistence context with the #PersistenceUnit annotation is not working.
My app is a CDI app. It was not previously a CDI application - I converted it to CDI by creating a beans.xml file in WEB-INF, I needed to in order to do something like this.
Is there anything I need to configure within CDI to get the annotation to work? Thanks.
I have a JPA application running with only Java SE. I don't have a WEB-INF/beans.xml, but I do have a META-INF/persistence.xml configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 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">
<persistence-unit name="JPAPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>jpa.Container</class>
<class>jpa.Item</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:derby:D:\NetBeansProjects\JPA\jpaTestDB;create=true"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
<property name="javax.persistence.jdbc.user" value=""/>
<property name="eclipselink.ddl-generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>
Container and Item are the two persistence classes in my jpa package.
This was generated automatically by Netbeans. There is also some information about using JPA without Java EE in the official (Sun/Oracle) Java EE tutorial in the persistence chapter.

JPA Entity found in unit tests, not in EJB

I have a DAO that uses JPA with a non-JTA data source and RESOURCE_LOCAL transactions. All of my unit tests that exercise the DAO work perfectly (data is inserted and retrieved from the database).
When I deploy my EJB to my Weblogic 10.3.3 server, however, I get the following exception:
Caused by: java.lang.IllegalArgumentException: Unknown entity bean class: class com.foo.bar.CatalogEntity, please verify that this class has been marked with the #Entity annotation.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:576)
My persistence.xml (in WEB-INF/classes/META-INF):
<?xml version="1.0" ?>
<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_1_0.xsd"
version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="cmf-awe-service" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>MyDataSource</non-jta-data-source>
<class>com.foo.bar.CatalogEntity</class>
<properties>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.query-results-cache" value="false"/>
<property name="eclipselink.target-server" value="WebLogic_10" />
<property name="eclipselink.logging.level" value="FINEST" />
</properties>
</persistence-unit>
</persistence>
I have confirmed that the CatalogEntity class is in the WEB-INF/classes directory. Any ideas about why this works in unit tests but not when deployed to the application server?
Brian, I had the same issue here... and I solved by adding a PreDestroy method on my bean that closes EntityManagerFactory:
#PreDestroy
public void close()
{
emf.close();
}
I hope this can help you! Please vote if it works...

EntityManager not injected

I'm getting an NPE for my EntityManager and can't figure out why - can anyone spot my mistake?
UserManagerImpl.java
#Stateless
public class UserManagerImpl implements UserManager {
#PersistenceContext(unitName = "persistenceUnit")
EntityManager em;
public List<User> findUsers() {
return (List<User>) em.createQuery("from User").getResultList();
}
}
META-INF/persistence.xml
<?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 http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="persistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/DefaultDS</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
</persistence-unit>
</persistence>
These are inside my ejb jar project, the UserManagerImpl is invoked from a JSP, not sure that should make a difference though.
Thanks in advance.
When you are using new UserManagerImpl() the container has no way to inject the EntityManager into this class. You need to let the container inject an instance into your object using
#EJB
private UserManager userManager;
This will only work for container managed objects like JSF managed beans, servlets or JSPs. Alternatively you can look up the ejb from jndi using something like
new InitialContext().lookup("UserManagerImpl");
The actual jndi name might be different.

Categories