3

I'm developing a portlet which runs in WebSphere Application Server ( - I accept the same problem to appear if it was a servlet instead of a portlet). At the moment it depends on Hibernate. As WAS provides a JPA implementation itself, which is a modified version of OpenJPA 2.0, I want to get rid of Hibernate.

This is my setup. 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" version="2.0"
               xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
  >
      <persistence-unit name="default" transaction-type="JTA">
          <provider>org.hibernate.ejb.HibernatePersistence</provider>

          <jta-data-source>jdbc/myDb</jta-data-source>
          <properties>
              <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform" />
              <property name="hibernate.dialect" value="org.hibernate.dialect.DB2Dialect" />
          </properties>
      </persistence-unit>
  </persistence>

myPortlet-portlet.xml

  <!-- ... -->

  <tx:jta-transaction-manager />
  <jee:jndi-lookup jndi-name="jdbc/myDb" cache="true" id="dataSource" expected-type="javax.sql.DataSource" />

  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="persistenceUnitName" value="default" />
  </bean>

In my DAO-classes I access the entityManager by using annotations:

  @PersistenceContext(unitName = "default")
  private EntityManager entityManager;

Everything works fine using Hibernate.

According to WebSphere Application Server docs, the default persistence provider is used if you don't specify it by using the <provider/>-tag in persistence.xml. But after commenting out the provider specification, Spring throws an exception due not being able to find the provider-class:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in PortletContext resource [/WEB-INF/myPortlet-portlet.xml]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: No PersistenceProvider specified in EntityManagerFactory configuration, and chosen PersistenceUnitInfo does not specify a provider class name either

How can I use the provided JPA implementation together with Spring (Portlet) MVC?

fishbone
  • 3,140
  • 2
  • 37
  • 50
  • What is WAS version? (Just in case, you may need a feature pack for version 7, for example). And we actually use org.apache.openjpa.persistence.PersistenceProviderImpl in our persistence.xml anyway. – skegg99 May 19 '14 at 11:30
  • Version 8.0. If I use org.apache.openjpa.persistence.PersistenceProviderImpl, I actually use OpenJPA (which is also provided by WAS). But I want to use their modified version of OpenJPA – fishbone May 19 '14 at 11:32
  • I guess you are right. But omitting provider may be only ok for EJB configuration. Probably spring doesn't handle it correctly. – skegg99 May 19 '14 at 11:50

2 Answers2

2

Short answer

You cannot use WebSphere's default provider by omitting the provider, if you want to use LocalContainerEntityManagerFactoryBean.

Long answer

Normally an entity manager is created by an entity manager factory provided by the container. You retrieve it by doing a context loopkup (EntityManager em = (EntityManager) ctx.lookup(...)) manually or use Springs jndi-lookup capability:

<beans>
    <jee:jndi-lookup id="myEmf" jndi-name="persistence/myPersistenceUnit"/>
</beans>

In the question, a different approach is used, a LocalContainerEntityManagerFactoryBean, which creates an entity manager factory itself. This entity manager factory is a proxy that implements all the interfaces of the native entity manager factory. For creating such a proxy, Spring must know the class of the native entity manager factory. Spring uses three different ways to determine the class:

  1. Detect it by the <provider/>-entry in persistence.xml
  2. Asking a jpaVendorAdapter (specified in the equally named property of the factory bean)
  3. Using the entityManagerFactoryInterface-property of the factory bean

And that's why you cannot completely omit the specification of your provider.

fishbone
  • 3,140
  • 2
  • 37
  • 50
0

This is most likely happening because the Spring JAR(s) that you include with your application contains a different implementation of the Persistence class, or other JPA classes, used to "bootstrap" JPA.

If you'd like to use WebSphere's default provider (or, more precisely, to use whichever JPA provide configured through WebSphere's administration screens), then you must ensure that the JPA "bootstrapping" code being called during runtime is WebSphere's, not yours.

You should look for a Spring distribution JAR that doesn't mess with JPA.

Isaac
  • 16,458
  • 5
  • 57
  • 81