JPA2 in SAP NetWeaver AS Java
This article is the first in a series of three tutorials that cover the following topics:
- JPA2 in SAP NetWeaver
- Building server-side database-backed OData services in SAP NetWeaver with JPA2
- Building server-side database-backed OData services in SAP NetWeaver with JPA1
Introduction
The SAP NetWeaver AS Java provides a JPA2-compliant container from version 7.5 SP03 onwards according to the SAP NetWeaver 7.5 SP03 release notes. A rough outline for the necessary steps to make use of this new feature is given in the SAP help.
The bad news about the new feature is that NetWeaver only provides the container while the SAP JPA provider is not capable of JPA2. Therefore, we need to supply NetWeaver and our JEE applications with our own provider. We decided to use Hibernate ORM for this purpose, as it is the most widely used OR mapper in the JEE world.
In this tutorial, we will demonstrate how to develop JEE applications for SAP NetWeaver that use JPA2 with Hibernate as the provider implementation. Generally, it should be possible to use other providers such as, for example EclipseLink, however we did not test this and therefore cannot guarantee that other providers will work.
Prerequisites
We strongly advise using the latest version of SAP NetWeaver AS Java, which is 7.5 SP06 at the time of writing this article, for reasons that we will discuss in the following pitfalls.
The latest stable Hibernate version that supports JPA 2.0 is Hibernate 4.2.21.Final. Download the hibernate-core artifact and all dependencies for this version, including the sources for Hibernate 4.2.21, as we will need these later. The following artifacts are required:
- antlr-2.7.7.jar
- dom4j-1.6.1.jar
- hibernate-commons-annotations-4.0.2.Final.jar
- hibernate-core-4.2.21.Final.jar
- hibernate-entitymanager-4.2.21.Final.jar
- javassist-3.18.1-GA.jar
- jboss-logging-3.1.0.GA.jar
- jboss-transaction-api_1.1_spec-1.0.1.Final.jar
Pitfall:
Ensure that you use Javassist version 3.18.1-GA or higher. This is necessary to provide compatibility for Java SE 8 (which SAP NetWeaver 7.5 supports) in your application. Otherwise, Hibernate will not work with Java 8 applications!
Pitfall:
Do not include the JPA-API artifact (“hibernate-jpa-2.0-api-1.0.1.Final.jar”)! Initially we tested JPA2 in SAP NetWeaver 7.5 SP03 and included the JPA-API-JAR as NetWeaver did not provide its own artifact for the API. However, somewhere between SP03 and SP06, SAP decided to include its own artifact of the JPA API with their application server as one would expect. If you include your own JPA-API-JAR with the later versions of NetWeaver 7.5, a deploy-time exception will be raised stating that an API mismatch was detected, even if you deploy the very same JAR that NetWeaver ships! This means that if you include your own API-JAR with NW 7.5 SP03 (where it is required) and you decide to migrate to later service packs, your application deployment will break!
Hibernate and NetWeaver Transactions
Hibernate provides support for a large number of JEE application servers regarding the Java Transaction API (JTA), in the sense that it includes components that provide container-specific JNDI-lookups of the TransactionManager and UserTransaction, which are essential for JPA2. Unfortunately SAP NetWeaver is not among those application servers supported by Hibernate. Furthermore, it is not possible to ship a suitable component for SAP NetWeaver with your application as the Hibernate JPA provider will be at the top end of the classloader chain, which means that it cannot search for classes „lower“ in the classloading chain. Hence, the only way of making Hibernate compatible with SAP NetWeaver is compiling your own version of the hibernate-core artifact with said class. We have submitted this change to Hibernate so that users of future versions will be able to make use of this out-of-the-box. If you get in touch with us, we will provide you with our own version of this artifact. We will still outline the necessary steps to generate your own artifact. Note that as of Hibernate 4, the TransactionManagerLookup-mechanism was replaced by JTA platform constructs.
In the sources for hibernate-core, navigate to the following package: org.hibernate.engine.transaction.jta.platform.internal
Create a new class SAPNetWeaverJtaPlatform:
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.engine.transaction.jta.platform.internal;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
/**
* {@link org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform} implementation for SAP NetWeaver
*
* @author Lukas Pradel
*/
public class SapNetWeaverJtaPlatform extends AbstractJtaPlatform {
public static final String TM_NAME = "TransactionManager";
public static final String UT_NAME = "UserTransaction";
@Override
protected TransactionManager locateTransactionManager() {
return (TransactionManager) jndiService().locate(TM_NAME);
}
@Override
protected UserTransaction locateUserTransaction() {
return (UserTransaction) jndiService().locate(UT_NAME);
}
}
Modify the class StrategySelectorBuilder at line 318 to include the following:
addJtaPlatforms(
strategySelector,
SapNetWeaverJtaPlatform.class,
"SapNetWeaver",
"org.hibernate.service.jta.platform.internal.SapNetWeaverJtaPlatform"
);
Finally, replace the original hibernate-core-4.2.21.Final.jar with your freshly compiled one.
Pitfall:
You must compile Hibernate 4.2.21 with JDK 6 as the remaining artifacts in Hibernate 4.2.21 were compiled using Java 6 as well.
Installing Hibernate as JPA provider
Follow the steps listed in SAP help:
- Put all hibernate artifacts (excluding the JPA-API-JAR) into a directory <hibernate-dir>
- Connect to NetWeaver using telnet <netweaver-host> 50008
- add orpersistence
- deploy_provider <hibernate-dir> -vendor org.hibernate -name hibernate4221
Configuring your application
Open the file application-j2ee-engine.xml in the META-INF directory of your EAR DC and add the following reference:
<reference reference-type="hard">
<reference-target provider-name="org.hibernate" target-type="library">hibernate4221</reference-target>
</reference>
Note that the provider-name is the same as the vendor specified in the previous section and the value of the reference-target property is the name specified in the previous section.
Next, edit the persistence.xml file of your EJB DC and make it a JPA2 persistence-file:
<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="pu-name">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>YOUR_DATA_SOURCE</jta-data-source>
<properties>
<property name="com.sap.jpa.container.packaging.pu.root.strategy.jpa10" value="true"/>
<property name="com.sap.jpa.container.packaging.referenced.jars.strategy.jpa10" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.SapNetWeaverJtaPlatform" />
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.connection.autocommit" value="false" />
<property name="hibernate.validator.autoregister_listeners"
value="false" />
<property name="hibernate.validator.apply_to_ddl" value="false" />
<property name="hibernate.default_schema" value="DEFAULT_SCHEMA"/>
</properties>
</persistence-unit>
</persistence>
Note the important parts:
- The provider attribute which sets the Hibernate provider
- The SAP-specific properties that ensure JPA2-compatibility and
- The transaction.jta.platform property which references the class we added to Hibernate.
In this example we used an Oracle DB. You will have to modify the related properties for your specific project setting.
Congratulations, you are now ready to deploy your first JPA2 application to SAP NetWeaver!
Compiling JPA2 applications in NWDS
By default, JEE DCs in NWDS depend on engine.jee5.facade. Naturally, this includes the JPA 1 API which makes it impossible to compile an application that uses JPA2-specific annotations such as for example the orphanRemoval attribute in OneToMany annotations.
We solved this issue by removing the engine.jee5.facade dependency and adding a dependency to an external library DC that includes only the JEE6 API (javaee-api-6.0.jar). Obviously, you can only use JPA2 related classes and annotations and not for example EJB 3.1 annotations such as @Singleton or you will experience exceptions at deploytime.
Conclusion
We successfully deployed and tested JPA2 applications with this setup in SAP NetWeaver 7.5 SP06 and hope that this tutorial enables you to develop JPA2 applications for SAP NetWeaver.
If you are experiencing problems, need assistance, or would like to see a minimal sample project, do not hesitate to contact us via SAP Community or by commenting on this article.
In the next article of this series, we will demonstrate how to use JPA2 to develop OData services with Apache Olingo with minimal boilerplate code.
Great blog Lukas.
I am trying to replicate your steps with Eclipse link. However when I run my web Module to get the metadata I get an error :
Will it be possible for you to guide.? Also Will it be possible for you to share a minimal sample implementation for hibernate.
Thanks and Regards
Prashant
Hi Prashant,
For Eclipselink On SAP Netweaver 75 SP4 Patch0 (SERVERCORE) it was needed to add a heavy classloader for persistence-api2.0 libs, otherwise he picks up the jpa 1.0 libs.
In your application-j2ee-engine-xml place:
For 75 SP4 Patch4 (SERVERCORE) it wasnt needed for me anymore.
Ciao
Lars
Prashant told me via email that he was able to solve his problem and that it was classloading-related. I will ping him again so he will hopefully provide his solution here for others to see.
Thanks @lars.laegner.ext.rohde-schwarz.co and @lpradel.
Apologies for being late in updating the thread.
My problem was resolved by following SAP Note 2260207.
When I was using a JPA Project in 7.5 Sp-6 It was expecting a Heavy Class loader configuration but when I switched to DC it was no longer needed.
The SAP Note alongwith Lukas's blog helped me to configure JPA and Olingo using Eclipse Link.
I am in the middle of the project hope all goes well :-). I will share my learning once the project is over.
Thanks
Prashant
Thank you for taking the time to update and good luck with your project! I am looking forward to your blog detailling your experiences 🙂
Best regards
Lukas
Hi Lukas,
All works well if I use a RESOURCE_LOCAL in Persistence.xml. However when I use a Data source, I am getting the below error.
Exception [EclipseLink-7060] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ValidationException Exception Description: Cannot acquire data source [JPA_P74]. Internal Exception: com.sap.engine.services.jndi.persistent.exceptions720.NameNotFoundException: Object not found in lookup of JPA_P74.
Any pointers on what's going wrong..?
Thanks
Prashant
This is very cool and simple tutorial, thank you! I am pretty sure this will be helpful for every Java coder. The most important thing for web developers to be always updated and learn lots of new things in the IT sphere. You are a programmer when you keep learning. Besides, using SAP NetWeaver AS Java might be very convenient.
Hi Lukas
The below packages doesn't even exist in 4.2.21 version of Hibernate Core. Would you be able to provide the SAP version of Hibernate-core jar file that works with JPA2.0?
Thanks
Sasi
From what I've gleaned from the Hibernate Github repository, these packages were not created until the 4.3 hibernate core tags.
4.3 also appears to use 2.1 JPA, which as of this writing is incompatible with Netweaver AS Java. Not sure how the author got it to work.