Setup
I'm Using JPA 1.0, Spring 3.0.6 and hibernate 3.2.1 on JBoss 4.3.2. There are some EJBs which at some point call a DAO which tries to persist two entities.
Problem
The result is quite unexpected: The entities are not managed after calling .persist(entity).
The Funny thing is: A quite similar test app, which uses the same jars containing DAOs, Beans persistence.xml as the server application, persists everything just fine. The beans are managed after calling .persist().
The entities
I have a class Subscriber that has a SubscriberState.
#Entity
#Table(name = "subscriber")
public class Subscriber implements java.io.Serializable {
// all the other stuff
#ManyToOne
#JoinColumn(name = "status")
private SubscriberState state;
}
For legacy reasons the SubscriberState has a relation Subscriber.
#Entity
#Table(name = "subscriber_state")
public class SubscriberState implements java.io.Serializable {
// ...blah
#ManyToOne
#JoinColumn(name = "subscriber", nullable = false)
private Subscriber subscriber;
}
what i do to persist
Now i try to persist a subscriber, it will be unmanaged afer persist():
final Subscriber subscriber = new Subscriber();
// set up...
entityManager.persist(subscriber);
entityManager.contaons(subscriber); //will yield FALSE
Adding a SubscriberState will work. But only one side of the relation will be stored to DB:
SubscriberState subscriberState = new SubscriberState();
subscriberState.setSubscriber(subscriber);
entityManager.persist(subscriberState);
entityManager.merge(subscriber);
where SubscriberState.setSubscriber looks like this:
public void setSubscriber(final Subscriber subscriber) {
this.subscriber = subscriber;
subscriber.setState(this);
}
A look at the database shows me, that the SubscriberState knows it's Subscriber, but the Subscriber does not know it's State.
the config
Here's the (now modified and stripped down) persistence.xml:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
org.hibernate.ejb.HibernatePersistence
java:jdbc/SODS
<properties>
<property name="hibernate.dialect" value="${db.hibernate.dialect}" />
<property name="hibernate.validator.apply_to_ddl" value="false" />
<property name="hibernate.validator.autoregister_listeners" value="false" />
<property name="hibernate.cache.provider_class" value="org.jboss.ejb3.entity.TreeCacheProviderHook" />
<property name="hibernate.treecache.mbean.object_name" value="jboss.cache:service=EJB3EntityTreeCache" />
<property name="jboss.entity.manager.jndi.name" value="java:/SOEntityManager-${app.version}" />
<property name="jboss.entity.manager.factory.jndi.name" value="java:/SOEntityManagerFactory-${app.version}" />
<property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" />
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" />
</properties>
<class>com.stackoverflow.some.classes.i.cant.show.Here</class>
and here are the relevant parts of my spring context:
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
<jee:jndi-lookup id="entityManagerFactory" jndi-name="java:/SOEntityManagerFactory-${app.version}" />
<jee:jndi-lookup id="entityManager" jndi-name="java:/SOEntityManager-${app.version}" />
<jee:jndi-lookup id="soDataSource" jndi-name="java:jdbc/SODS" />
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg ref="soDataSource" />
</bean>
<context:component-scan base-package="blah - secret" />
<import resource="daoContext.xml" />
</beans>
Any ideas, why this config won't work?
I don't see use of #Transaction in your DAO or service layer
Adding a SubscriberState will work. But only one side of the relation will be stored to DB
You should use cascade option in
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "subscriber", nullable = false)
private Subscriber subscriber;
This will save both side of the relationship in persist operation
Also what I see is two unidirectional relationship, not one bidireccional, try to use mappedBy
#ManyToOne
#JoinColumn(name = "status")
private SubscriberState state;
Unless that is not what you want, but you should reconsider your design to made one side OneToMany and the other side ManyToOne, use mappedBy to define the source (owner) of the relationship
This happened to my application, JPA with MySQL. Load the appropriate database driver class in the property file.
Related
I'm facing a problem and have no idea what's going wrong. The cenary:
Hibernate 5
Apache Tomcat 9
JSF 2
No Spring. It's important to say because I saw this problem happening realted with Spring use, but this is not my case.
The datasource was correctly configured on Tomcat, and the Hibernate also creates the tables and update schemma correctly for each new Entity.
The problem is when I try to persist a new Entity, nothing happens. Then I tried to include "flush()" call... but then I've got an error saying I have no transaction active:
javax.persistence.TransactionRequiredException: no transaction is in progress
It seems to be a problem related with a transaction requirement, but I have also tried:
include "#Transactional" annotation on method;
include "#Transactional" annotation on class;
Force begin transaction with "beginTransaction()" call but then I've got a NullPointer;
So... I don't know what do to.
Follow you'll see my relevant code. Can you help me to solve this problem?
persistence.xml file:
<persistence-unit name="hospitalPU" transaction-type="RESOURCE_LOCAL">
<description>
Persistence unit for Hibernate
</description>
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>java:comp/env/jdbc/hospitalDatasource</non-jta-data-source>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.default_catalog" value="hospital" />
<property name="hibernate.connection.datasource" value="java:comp/env/jdbc/hospitalDatasource"/>
<property name="hibernate.id.new_generator_mappings" value="false" />
</properties>
</persistence-unit>
My Entity:
#Entity(name="Dominio")
#Table(name="Dominio")
public class Dominio implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Integer id;
here goes another fileds and getters/setters...
On my managed bean, I have:
#PersistenceUnit
private EntityManagerFactory emf;
And:
protected synchronized EntityManager getEntityManager() {
if (emf == null) {
emf = Persistence.createEntityManagerFactory("hospitalPU");
}
return emf.createEntityManager();
}
It seems to work fine, but the problem happens here:
With this, nothing happen and no Exception occours. Just NOTHING happens:
getEntityManager().persist(getDominio());
With this, I have "javax.persistence.TransactionRequiredException: no transaction is in progress":
getEntityManager().persist(getDominio());
getEntityManager().flush(); //exception occours here!
What am I doing wrong? Thanks in advance for you all!
you need to more configure the persistence.xml or hibernate.cfg.xml. you can refer bellow link to configure these xml files.
https://gist.github.com/imanoleizaguirre/3819393
http://www.journaldev.com/7122/jsf-spring-hibernate-integration-example-tutorial
http://www.javaknowledge.info/simple-crud-using-jsf2hibernate-integration-and-mysql/
This one here clearly explains what is the problem:
"javax.persistence.TransactionRequiredException: no transaction is in progress"
First, you have clearly mentioned that you are using a Non-JTA datasource. meaning that the container will no longer manage for you transaction boundaries. You must begin and commit/rollback transactions on your own. You therefore need to follow the following:
EntityManager em = ....
EntityTransaction et = em.getTransaction();
try {
et.begin();
em.persist(entity);
et.commit();
} catch (Exception ex) {
et.rollback();
throw new RuntimeException(ex);
}
I try to test the persistence of some entities with an in-memory H2 DB but I recognized that #SequenceGenerator will never be invoked as it should be, neither when running by build platform, nor when running it with RunAs->JUnit test in Eclipse.
What I can say for sure is that the sequences are generated inside the H2 DB. I can even select them when I connect to this generated H2. So it's definitely not a problem inside H2 but with Hibernate.
(Usually Hibernate automatically assigns an ID when persisting an Entity which needs one).
The entity
#Entity
#Table(name = "HOUSE_USERDATA")
public class UserData {
#Id
#Column(name = "HU_ID")
#GeneratedValue(generator = "SEQ_HOUSE_USERDATA", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(sequenceName = "SEQ_HOUSE_USERDATA", name = "SEQ_HOUSE_USERDATA", allocationSize = 2)
private Long huId;
#Column(name = "HU_DATA")
#Size(max = 1000)
private String m_data;
#ManyToOne
#JoinColumn(name = "HR_ID")
private Registry m_registry;
//more code [...]
}
The reference in the referencing Entity...
#OneToMany(mappedBy = "registry")
private List<UserData> userDataList;
The persistence unit...
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.foo.bar.all.entity</class>
<!-- all entity references -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
<property name="hibernate.connection.url"
value="jdbc:h2:inmemory;INIT=runscript from 'classpath:testscripts/drop_h2.sql'\;runscript from 'classpath:testscripts/create.sql'"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.use_sql_comments" value="true" />
</properties>
</persistence-unit>
The invocation in JUnit test...
Registry registry = new Registry();
registry.setClientId("clientId");
List<UserData> userDataList = new ArrayList<>();
UserData userData1 = new UserData();
userData1.setData("User defined data 1.");
userData1.setRegistry(registry);
UserData userData2 = new UserData();
userData2.setData("User defined data 2.");
userData2.setRegistry(registry);
userDataList.add(userData1);
userDataList.add(userData2);
registry.setUserDataList(userDataList);
entityManager.persist(registry);
Registry result = entityManager.find(Registry.class, "clientId");
//MUST NOT BE NULL, BUT IS NULL
assertThat(result.getUserDataList().get(0).getId(), is(not(nullValue())))
Other values are persisted properly. Only the IDs were not generated. (I wonder why this test works at all for all the other values since the ID is defined as NOT NULL in the generated DB, so there should be a persistence exception or something else).
Any ides why the sequence generator does not generate anything (I tried GenerationType.AUTO as well, but no difference)?
When you are doing entityManager.persist(registry) that is what it is going to do, store the Registry and check all the mappings for that class. It will encounter the collection of UserData objects, but because there is no cascade property matching the PERSIST it will not store the UserData objects.
It will only store the top level Registry object. If you want to change this add cascade={CascadeType.ALL} or at least cascade={CascadeType.PERSIST} to the #OneToMany annotation, to tell Hibernate it also needs to check the collection for new elements and persist those.
Or first store the UserData elements, before storing the Registry.
I have the below mentioned Entity classes, when I execute my application I am getting the following exception. Some of the other similar questions didn't solve the problem.
WARNING: StandardWrapperValve[jersey-serlvet]: PWC1406: Servlet.service()
for servlet jersey-serlvet threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize
a collection of role: test.entity.Dept.empDeptno, no session
or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationException(AbstractPersistentCollection.java:393)
at org.hibernate.collection.internal.AbstractPersistentCollection.
throwLazyInitializationExceptionIfNotConnected
(AbstractPersistentCollection.java:385)
at org.hibernate.collection.internal.AbstractPersistentCollection.
initialize(AbstractPersistentCollection.java:378)
How can I solve this issue?
Emp Entity
#Entity
#Table(name = "EMP", schema = "SCOTT"
)
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Emp.findAllEmployees", query = "select e from Emp e left
join fetch e.deptNo order by e.empno desc")
})
public class Emp implements java.io.Serializable {
#Id
#Column(name = "EMPNO", unique = true, nullable = false, precision = 4,
scale = 0)
private short empno;
#ManyToOne
#JoinColumn(name = "DEPTNO", referencedColumnName = "DEPTNO")
private Dept deptNo;
Dept Entity
#Entity
#Table(name = "DEPT", schema = "SCOTT"
)
#XmlRootElement
public class Dept implements java.io.Serializable {
#Id
#Column(name = "DEPTNO", unique = true, nullable = false, precision = 2,
scale = 0)
private short deptno;
#OneToMany(fetch=FetchType.LAZY,mappedBy = "deptNo")
private Set<Emp> empDeptno;
DAOImpl
#Override
public List<Emp> findAllEmployees() {
return getEntityManager().createNamedQuery("Emp.findAllEmployees",
Emp.class).getResultList();
}
Jersey RESTful service
#Component
#Path("/employee")
public class EmployeeRestService {
#Autowired
EmployeeService employeeService;
#GET
#Produces({MediaType.APPLICATION_JSON})
public List<Emp> getEmployees() {
List<Emp> emp = new ArrayList<Emp>();
emp.addAll(getEmployeeService().findAllEmployees());
return emp;
}
Spring applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"
>
<!-- Data Source Declaration -->
<bean id="DataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/scottDS"/>
</bean>
<context:component-scan base-package="net.test" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="DataSource" />
<property name="packagesToScan" value="net.test" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="${jdbc.dialectClass}" />
</bean>
</property>
</bean>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />
<!-- Transaction Config -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:annotation-config/>
<bean id="hibernateStatisticsMBean" class="org.hibernate.jmx.StatisticsService">
<property name="statisticsEnabled" value="true" />
<property name="sessionFactory" value="#{entityManagerFactory.sessionFactory}" />
</bean>
</beans>
I have resolved the issue by adding the following in web.xml
<filter>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
courtesy here and here
Thanks
The problem is that the scope of your database/JPA transaction only contains the service (which I assume is a stateless session bean) and does NOT contain the REST resource bean.
Web server dispatches request to JAX-RS service
JAX-RS service calls EJB Stateless Session Bean
Transaction starts
EJB Stateless Session Bean loads data from database (other beans might be involved)
EJB Stateless Session Bean returns result
Transaction ends
JAX-RS service returns result
JAX-RS Producer creates XML out of List<Emp> and accesses field empDeptno.
So when Jersey gets the list of Emp to produce XML out of it, the transaction has already been closed. When now the field empDeptNo is navigated, JPA tries to lazily load it, which fails as we're already outside a valid transaction/session.
You might try to extend the transaction scope to also contain your Jersey REST resource bean by making a stateless session bean out of it. Then it might be as follows:
Web server dispatches request to JAX-RS service
Transaction starts
JAX-RS service calls EJB Stateless Session Bean
EJB Stateless Session Bean loads data from database (other beans might be involved)
EJB Stateless Session Bean returns result
JAX-RS service returns result
JAX-RS Producer creates XML out of List<Emp> and accesses field empDeptno.
Transaction ends
I'm not 100% sure, it might also be that step 8 comes BEFORE step 7, so the transaction might be closed before the producer does its job. If that's the case, this solution is simply wrong...
But I think you should simply try it...
If you would like to continue using FetchType.LAZY but need access to the lazily loaded attributes for some queries, a portable solution would be to access the field and perform an operation on it while still within a transaction/session. I mention portability because AFAIK Hibernate offers at least one different approach to explicitly trigger loading that is not part of the JPA spec.
Adapting your code, this could look like this:
public List<Emp> findAllEmployees() {
List<Emp> employees = getEntityManager().createNamedQuery("Emp.findAllEmployees",
Emp.class).getResultList();
//trigger loading of attributes
for(Emp emp: employees){
emp.getDeptNo().getEmpDetNo().size();
}
return employees;
}
EDIT: Another portable alternative would be to use fetch joins in the query. Your Emp.findAllEmployees query could look like this:
SELECT e FROM Emp e JOIN FETCH e.dept.empDetno
Make it a left join if you have Emps without departments and departments without empDetNo
I created the small JPA project to persist a Student record. I use Oracle database. I use the OpenJPA as the JPa provider.
I have created the Table student and relevant sequences correctly.
Student Entity class
#Entity
#Table(name = "Student")
public class Student implements Serializable {
private int id;
private String name;
private static final long serialVersionUID = 1L;
public Student() {
super();
}
#Id
#Column(name = "ID")
#SequenceGenerator(name = "TRAIN_SEQ", sequenceName = "STUDENT_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TRAIN_SEQ")
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "NAME")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
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="JPAOracleDemo">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>com.jpa.demo.model.Student</class>
<properties>
<property name="openjpa.ConnectionURL" value="jdbc:oracle:thin:#TEST:50111:TESTPEGAD1" />
<property name="openjpa.ConnectionDriverName" value="oracle.jdbc.driver.OracleDriver" />
<property name="openjpa.ConnectionUserName" value="admin" />
<property name="openjpa.ConnectionPassword" value="admin" />
<property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
<property name="openjpa.jdbc.Schema" value="MYSCHEMA" />
</properties>
</persistence-unit>
</persistence>
Client Class
OpenJPAEntityManager em = JPAUtil.getEntityManager();
OpenJPAEntityTransaction tx = em.getTransaction();
tx.begin();
// Create the instance of Employee Entity class
Student student = new Student();
student.setName("A.Ramesh");
// JPA API to store the Student instance on the database.
em.persist(student);
tx.commit();
em.close();
System.out.println("Done...");
Util class
private static OpenJPAEntityManagerFactory emf = OpenJPAPersistence
.createEntityManagerFactory("JPAOracleDemo", "META-INF/persistence.xml");
private static OpenJPAEntityManager entManager;
/**
* No need to create any instance for this Util.
*/
private JPAUtil() {
}
/**
* Get {#link EntityManager}.
*
* #return the {#link EntityManager}
*/
public static OpenJPAEntityManager getEntityManager() {
if (entManager == null || !entManager.isOpen()) {
entManager = emf.createEntityManager();
}
return entManager;
}
The data persist in the student table successfully, but I have the bellow error
Exception in thread "Attachment 60230" java.lang.UnsupportedOperationException: cannot get the capability, performing dispose of the retransforming environment
at com.ibm.tools.attach.javaSE.Attachment.loadAgentLibraryImpl(Native Method)
at com.ibm.tools.attach.javaSE.Attachment.loadAgentLibrary(Attachment.java:253)
at com.ibm.tools.attach.javaSE.Attachment.parseLoadAgent(Attachment.java:235)
at com.ibm.tools.attach.javaSE.Attachment.doCommand(Attachment.java:154)
at com.ibm.tools.attach.javaSE.Attachment.run(Attachment.java:116)
Exception in thread "main" java.lang.UnsupportedOperationException: cannot get the capability, performing dispose of the retransforming environment
at sun.instrument.InstrumentationImpl.isRetransformClassesSupported0(Native Method)
at sun.instrument.InstrumentationImpl.isRetransformClassesSupported(InstrumentationImpl.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:48)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:600)
at org.apache.openjpa.enhance.ClassRedefiner.canRedefineClasses(ClassRedefiner.java:123)
at org.apache.openjpa.enhance.ManagedClassSubclasser.prepareUnenhancedClasses(ManagedClassSubclasser.java:122)
at org.apache.openjpa.kernel.AbstractBrokerFactory.loadPersistentTypes(AbstractBrokerFactory.java:304)
at org.apache.openjpa.kernel.AbstractBrokerFactory.initializeBroker(AbstractBrokerFactory.java:228)
at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:202)
at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:156)
at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:213)
at com.ibm.ws.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:45)
at com.ibm.ws.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:30)
at com.jpa.demo.util.JPAUtil.getEntityManager(JPAUtil.java:32)
at com.jpa.demo.client.JPAClient.main(JPAClient.java:13)
1045 JPAOracleDemo INFO [main] openjpa.Enhance - Creating subclass for "[class com.jpa.demo.model.Student]". This means that your application will be less efficient and will consume more memory than it would if you ran the OpenJPA enhancer. Additionally, lazy loading will not be available for one-to-one and many-to-one persistent attributes in types using field access; they will be loaded eagerly instead.
Done...
Java version
JDK 1.6
Anybody please let me know what is the issue here?
Updated:
I used the IBM Rational Software Architect for Websphere Software for this development. this problem is with this IDE. When I create the JPA project by default it adds the IBM jre. I just removed the IBM jre and tried with the SUN jre then it was success. Please let me know why this function does not support with IBM jre?
<property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
For starters, get rid of that property.
This is my enhancer template, this works properly for OPENJPA:
`
<path id="enhance.cp">
<pathelement location="${basedir}${file.separator}${build.dir}" />
<fileset dir="${basedir}${file.separator}ext_libs/">
<include name="**/*.jar" />
</fileset>
</path>
<property name="cp" refid="enhance.cp" />
<target name="openjpa.libs.check" unless="openjpa.libs">
<fail message="Please set -Dopenjpa.libs in your builder configuration!" />
</target>
<target name="build.dir.check" unless="build.dir">
<fail message="Please set -Dbuild.dir in your builder configuration!" />
</target>
<target name="enhance" depends="openjpa.libs.check, build.dir.check">
<echo message="${cp}" />
<taskdef name="openjpac" classname="org.apache.openjpa.ant.PCEnhancerTask">
<classpath refid="enhance.cp" />
</taskdef>
<openjpac>
<classpath refid="enhance.cp" />
<configpropertiesFile="${basedir}${file.separator}src${file.separator}main${file.separator} resources${file.separator}META-INF${file.separator}persistence.xml" />
</openjpac>
</target>
`
The JPA spec requires some type of monitoring of Entity objects, but the spec does not define how to implement this monitoring. Some JPA providers auto-generate new subclasses or proxy objects that front the user's Entity objects at runtime, while others use byte-code weaving technologies to enhance the actual Entity class objects. OpenJPA supports both mechanisms, but strongly suggests only using the byte-code weaving enhancement. The subclassing support (as provided by OpenJPA) is not recommended (and is disabled by default in OpenJPA 2.0 and beyond).(Source: http://openjpa.apache.org/entity-enhancement.html)
The cause of this issue is I used the subclassing support for the entity enhancement but that is disabled by default in OpenJPA2.0 and beyond.
I found the solution for this issue. We have to enhance the entity class at run time by providing a javaagent when launching the JVM that OpenJPA is going run in.
I put something like the following as a JVM argument
-javaagent:C:/OpenJPA/apache-openjpa-2.0.0/openjpa-2.0.0.jar
And I removed the bellow line from persistence.xml
<property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
Working persistence.xml
<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="DataSourceDemo">
<jta-data-source>oracleDS</jta-data-source>
<class>com.auditlog.model.BatchPrint</class>
<properties>
<property name="openjpa.ConnectionUserName" value="admin" />
<property name="openjpa.ConnectionPassword" value="test" />
<property name="openjpa.jdbc.Schema" value="defaultScheme" />
</properties>
</persistence-unit>
</persistence>
I am quite a newbie to Spring JPA in cooperation with ObjectDB database, but I have encountered a problem that I cannot work out.
I have an application written with the mentioned technologies and it works OK, it persists new entities etc. (thus I think there is no problem with the configuration beans), except for updating even the simplest OneToMany/ManyToOne relations. Those updates are not persisted to the database and I cannot figure out why. Here's the snippet of my code:
Entity Team (1:N):
#Entity
public class Team implements Serializable {
...
List<Player> squad;
...
#OneToMany(mappedBy="team", cascade=CascadeType.PERSIST)
public List<Player> getSquad() {
return squad;
}
...
}
Entity Player (N:1)
#Entity
public class Player implements Serializable {
...
private Team team;
...
#ManyToOne
public Team getTeam() {
return team;
}
...
}
Here is a snippet from controller using both DAO objects and the problem:
public ModelAndView addPlayer(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
Team t = teamDao.getTeamById(1); // retrieves an object with ID=1
Player p = playerDao.getPlayerById(1); // retrieves a player with ID=1
t.getSquad().add(p); // adds a player to the squad -> working fine but does not persist
System.out.println("Size of squad: " + t.getSquad().size()); // the player is there
...
return new ModelAndView("index.jsp", "team", t);
}
When I try to list all players in the team inside the index.jsp page or try to add another player the same way, the squad is always empty - nothing persisted to the database. Neither the team object, nor the player object. What do I do wrong?
Any help would be appreciated. Thanks.
EDIT: here is 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="NewPU" transaction-type="RESOURCE_LOCAL">
<provider>com.objectdb.jpa.Provider</provider>
<properties>
<property name="javax.persistence.jdbc.url" value="C:/file.odb" />
<property name="javax.persistence.jdbc.user" value="admin"/>
<property name="javax.persistence.jdbc.password" value="admin"/>
</properties>
</persistence-unit>
P.S. The absolute path "C:/file.odb" is only for demonstration purposes.
and here is Spring configuration:
<mvc:annotation-driven />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="NewPU" />
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
CascadeType.PERSIST cascades the persistens of a new object but you load a player from the database and attach the player to your team. If you want to cascade that you have to add the CascadeType.MERGE
cascade = {CascadeType.PERSIST, CascadeType.MERGE}
You may have a look at CascadeType.ALL.