We are in migration process to migrate some application to WAS liberty profile, the application was using open jpa version 1 and java 6 and the code was working just fine , we decided to migrate to JPA 2.0 , and java version 8 because it is implemented in apache open jpa in order to avoid migration issues, now the application is not able to persist a picture in oracle DB , it is stored as a blob datatype filed in a table, we are able to retrieve the image from database correctly but not able to store any in the database due to the below error while commit the storing image query. I have noticed that it failed to get a place holder for the blob data type field.
Field declaration :
@Lob
@Column(name="FORM" ,columnDefinition="BLOB" , nullable=true )
private byte[] form;
storing Transaction
@Action(Action.ACTION_TYPE.CREATE)
public void createTransaction(final Transaction transaction) throws Exception {
EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
em.persist(transaction);
em.getTransaction().commit();
} catch (Exception ex) {
try {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
} catch (Exception e) {
ex.printStackTrace();
throw e;
}
throw ex;
} finally {
em.close();
this.emf.close();
this.emf = null;
}
}
JPA project setting: Platform : Generic 2.0 , JPA Implementation : Library provided by target Runtime.
Exception Stack trace :
[err] <openjpa-2.2.3-SNAPSHOT-r422266:1802153 fatal store error> org.apache.openjpa.persistence.RollbackException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[err] at org.apache.openjpa.persistence.EntityManagerImpl.commit(EntityManagerImpl.java:594)
[err] at com.test.hace.sfp.dao.entities.controller.TransactionManager.createTransaction(TransactionManager.java:92)
[err] at com.test.hace.sfp.services.process.impl.TransactionServiceImpl.submitNewTransactionToApproval(TransactionServiceImpl.java:115)
[err] at pagecode.pages.branch.initiator.NewTransactionStep2.doSubmitAction(NewTransactionStep2.java:229)
[err] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[err] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
[err] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[err] at java.lang.reflect.Method.invoke(Method.java:497)
[err] at org.apache.el.parser.AstValue.invoke(AstValue.java:245)
[err] at [internal classes]
[err] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[err] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[err] at java.lang.Thread.run(Thread.java:745)
[err] Caused by: <openjpa-2.2.3-SNAPSHOT-r422266:1802153 fatal general error> org.apache.openjpa.persistence.PersistenceException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
[err] at org.apache.openjpa.kernel.BrokerImpl.newFlushException(BrokerImpl.java:2352)
[err] at [internal classes]
[err] ... 45 more
[err] Caused by: <openjpa-2.2.3-SNAPSHOT-r422266:1802153 fatal general error> org.apache.openjpa.persistence.PersistenceException: oracle.sql.BLOB
[err] at org.apache.openjpa.jdbc.sql.DBDictionary.narrow(DBDictionary.java:4998)
[err] at [internal classes]
[err] ... 52 more
[err] Caused by: java.sql.SQLException: oracle.sql.BLOB
[err] at org.apache.openjpa.jdbc.sql.OracleDictionary.getEmptyBlob(OracleDictionary.java:1249)
[err] at [internal classes]
[err] ... 59 more
For some operations (particularly involving LOBs), JPA Providers (OpenJPA, Eclipselink) will require the JDBC classes to be resolvable by the application's classloader (more specifically, the thread context classloader, which is the app classloader).
The problem is that the javax.sql.DataSource resolved by the JNDI lookup doesn't automatically add those JDBC classes to the application classloader (you really don't want to pollute an applications' ClassLoader with unnecessary libraries, after all.)
However, if you add to your application's definition the JDBC libraries as a shared library as a definition with your app's entry in server.xml, then it will work.
For example:
<jdbcDriver id="Derby" libraryRef="JDBCLib"/>
<library filesetRef="DerbyFileset" id="JDBCLib"/>
<fileset dir="/derby/lib" id="DerbyFileset"/>
<dataSource id="jdbc/JPA_DS"
jndiName="jdbc/JPA_DS"
jdbcDriverRef="Derby"
isolationLevel="TRANSACTION_READ_COMMITTED">
<properties.derby.client
databaseName="TestDB"
serverName="localhost"
portNumber="1527"/>
</dataSource>
<application type="ear" id="entity10" name="Entity10"
location="${fvt.home}/testbuckets/jpaspec-1.0/Entity/Entity10.ear">
<classloader commonLibraryRef="JDBCLib" />
</application>