Announcement Announcement Module
Collapse
No announcement yet.
Toplink ignores JPA annotations / porting Petclinic Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Toplink ignores JPA annotations / porting Petclinic

    As the Petclinic example (JPA version) uses xml-based mapping files (orm.xml), I tried to create a Petclinic version that uses JPA annotations.

    I succeeded with Hibernate as JPA persistence provider, my petclinic version with JPA annotations runs fine.

    But when using Toplink as JPA provider, I managed to run the Petclinic only successfully when I continue to use the xml-based mapping (orm.xml).

    It appears that Toplink completely ignores the JPA annotations , so when I eliminate orm.xml, no mappings are defined. Consequently, when running the Petclinic and trying to display all veterinarians, Toplink throws the following exception, which isn't surprising: oracle.toplink.essentials.exceptions.EJBQLExceptio n Exception Description: Unknown abstract schema type [Vet]

    When NOT eliminating orm.xml, however, my Petclinic JPA version runs fine with Toplink.

    There are some pitfalls I am aware of:

    First of all, my persistence.xml file to define the persistence unit has the <exclude-unlisted-classes> element either uncommented or set to "false", so scanning of unlisted-classes should actually not be prevented. Also, there is no <xml-mapping-metadata-complete/> element in my persistence.xml.

    Secondly, when persistence.xml is placed in WEB-INF/classes/META-INF of my Petclinic WAR-file, my compiled Java classes are in WEB-INF/classes (and not in a separate JAR file placed in WEB-INF/lib).

    My questions:

    How can I configure Toplink Essentials (using Tomcat 6.0.2) and Spring 2.0 so that it doesn't ignore the JPA annotations placed on Entity classes?

    Does anyone perhaps have a small example to demonstrate that Toplink, set up by Spring, can read JPA annotations (rather than just xml-based mapping files)?


    Any hints would be highly appreciated.



    applicationContext-jpa.xml (placed in WEB-INF):
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	     xmlns:aop="http://www.springframework.org/schema/aop"
    	     xmlns:tx="http://www.springframework.org/schema/tx"
    	     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
               http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
               http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
    
    	<!-- Configurer that replaces ${...} placeholders with values from a properties file -->
    	<!-- (in this case, JDBC-related settings for the dataSource definition below) -->
    	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    		<property name="location" value="/WEB-INF/jdbc.properties"/>
    	</bean>
    
    
    	<!-- Local DataSource that works in any environment -->
    	<!-- Note that DriverManagerDataSource does not pool; it is not intended for production -->
    	<!-- See JPetStore for an example of using Commons DBCP BasicDataSource as alternative -->
    	<!-- See Image Database for an example of using C3P0 ComboPooledDataSource as alternative -->
    	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName" value="${jdbc.driverClassName}"/>
    		<property name="url" value="${jdbc.url}"/>
    		<property name="username" value="${jdbc.username}"/>
    		<property name="password" value="${jdbc.password}"/>
    	</bean>
    
    	<!-- JPA EntityManagerFactory -->
    	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    		<property name="dataSource" ref="dataSource"/>
    		<!-- loadTimeWeaver not needed for Hibernate --> 
    		<property name="loadTimeWeaver">
    			<bean class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"/>
    		</property> 
    		
    		<property name="jpaVendorAdapter">
    			<bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
    				<!-- <property name="databasePlatform"
    						value="org.springframework.samples.petclinic.toplink.EssentialsHSQLPlatformWithNativeSequence"/> -->
    			        <property name="databasePlatform" value="oracle.toplink.essentials.platform.database.MySQL4Platform"/>
    		        	<property name="generateDdl" value="false"/> 
    				<property name="showSql" value="true" />
    			</bean>
    		</property> 
    	</bean>
    
    	<!-- Transaction manager for a single JPA EntityManagerFactory (alternative to JTA) -->
    	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    		<property name="entityManagerFactory" ref="entityManagerFactory"/>
    	</bean>
    
    
    	<!--
    		Instruct Spring to retrieve and apply @AspectJ aspects which are defined
    		as beans in this context (such as the UsageLogAspect below).
    	-->
    	<aop:aspectj-autoproxy/>
    
    	<!--
    		Simply defining this bean will cause requests to owner names to be saved.
    		Spring automatically deploys the @Aspect when AspectJ autoproxying is enabled.
    		Note that we can dependency inject this bean like any other bean.
    	-->
    	<bean class="org.springframework.samples.petclinic.aspects.UsageLogAspect">
    		<property name="historySize" value="300"/>
    	</bean>
    
    
    	<!--
    		Instruct Spring to perform declarative transaction management automatically
    		on annotated classes.
    	-->
    	<tx:annotation-driven/>
    
    	<!--
    		PostProcessors to perform resource injection according to the JPA specification
    	  (@PersistenceContext, @PersistenceUnit).
    	-->
    	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
    
    	<!--
    		PostProcessors to perform exception translation on @Repository classes (from native
    		exceptions such as JPA PersistenceExceptions to Spring's DataAccessException hierarchy).
    	-->
    	<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    
    
    	<!--
    		Will automatically be transactional due to @Transactional.
    		EntityManager will be auto-injected due to @PersistenceContext.
    		PersistenceExceptions will be auto-translated due to @Repository.
    	-->
    	<bean id="clinic" class="org.springframework.samples.petclinic.jpa.EntityManagerClinic"/>
    
    
    </beans>
    persistence.xml (placed in WEB-INF/classes/META-INF):
    Code:
    <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="PetClinic" transaction-type="RESOURCE_LOCAL">
    
    
    		<!--
    			Prevent annotation scanning. In this app we are purely driven by orm.xml.
    		-->
    		 <exclude-unlisted-classes>false</exclude-unlisted-classes> 
    
    		<!--
    			Using Spring we don't need the basic required vendor-specific properties like 
    			the following, which in this sample app are all conveyed in Spring configuration...
    		-->
    		<properties>
                   </properties>
    	</persistence-unit>
    
    </persistence>

    Spring version used: 2.0

    Toplink essentials version:
    taken from Spring 2.0 distribution, but version from glassfish-persistence-installer-v2-b25.jar doesn't work either.

    spring-tomcat-weaver.jar placed in ${TOMCAT_HOME}/lib

    Tomcat version used: 6.0.2

  • #2
    Have you tried listing your entities in the persistence.xml file using the <class> node?

    Comment


    • #3
      Originally posted by cwash5 View Post
      Have you tried listing your entities in the persistence.xml file using the <class> node?
      Yes, I already tried that before posting here.

      An hour ago I tried the following:

      I deployed a Petclinic version with JPA-Annotations and Hibernate as persistence provider. Via context.xml put in /META-INF of the WAR-File, I also activated the org.springframework.instrument.classloading.tomcat .TomcatInstrumentableClassLoader,
      even though this classloader is NOT needed by Hibernate, but only by Toplink.

      My intention was to first deploy a Hibernate-JPA-Annotations-based Petclinic and afterwards, when it runs without problems, simply choose Toplink as persistence provider by stopping Tomcat, changing the persistence provider defined via the Spring application context (and not via persistence.xml) and then restarting Tomcat.

      But it does not have any effect on Toplink, as far as processing of the Annotations is concerned.

      Of course, if I add orm.xml, the deployed Petclinic also works with Toplink as persistence provider.


      My context.xml is as follows: (placed in /META-INF of the WAR file)
      Code:
      <?xml version="1.0" encoding="UTF-8" ?>
      
      <Context path="/petclinicJPA_Annotations" 
                     docBase="petclinicJPA_Annotations"
              debug="5" reloadable="true" crossContext="true">
          <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
      </Context>
      persistence.xml (with explicitly listed classes):
      Code:
      <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="PetClinic" transaction-type="RESOURCE_LOCAL">
                    <class>org.springframework.samples.petclinic.Person</class>
                    <class>org.springframework.samples.petclinic.BaseEntity</class>
                    <class>org.springframework.samples.petclinic.Owner</class>
                    <class>org.springframework.samples.petclinic.Visit</class>
                    <class>org.springframework.samples.petclinic.Vet</class>
                    <class>org.springframework.samples.petclinic.Pet</class>
                    <class>org.springframework.samples.petclinic.PetType</class>
                    <class>org.springframework.samples.petclinic.Specialty</class>
                    <class>org.springframework.samples.petclinic.NamedEntity</class>
      	</persistence-unit>
      
      </persistence>


      Has anyone ever got Toplink with JPA annotations (not just XML mapping files) to work under Spring + Tomcat 6?
      Last edited by IngoM; Dec 17th, 2006, 01:55 PM.

      Comment


      • #4
        I've got JPA Toplink working well. But to wrok, I had to use the JpaDaoSupport.getJpaTemplate().

        I'm a beginner, so take the following code has a working example, not a good example ;-)

        Here are my files (sorry but XML file attachment is not allowed).

        persistence.xml:
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <persistence version="1.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_1_0.xsd">
          <persistence-unit name="Tap03PU" transaction-type="RESOURCE_LOCAL">
        <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
            <class>tap03.domain.model.Document</class>
            <class>tap03.domain.model.Configuration</class>
            <properties>
              <property name="toplink.jdbc.url" value="jdbc:mysql://localhost:3306/tap03"/>
              <property name="toplink.jdbc.driver" value="com.mysql.jdbc.Driver"/>
              <property name="toplink.jdbc.user" value="root"/>
              <property name="toplink.jdbc.password" value=""/>
              
              <property name="toplink.cache.type.default" value="NONE" />
              <property name="toplink.logging.level" value="FINEST" />
              <property name="toplink.logging.thread" value="true" />
              <property name="toplink.logging.session" value="true" />
              <property name="toplink.logging.exceptions" value="true" />
              
            </properties>
          </persistence-unit>
        </persistence>
        applicationContext.xml:
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" 
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
        <beans>
            <bean id="documentsManager" class="tap03.service.impl.DocumentsManagerImpl">
                <property name="documentDao">
                    <ref bean="documentDAO" />
                </property>
                <property name="configurationManager">
                    <ref bean="configurationManager" />
                </property>
            </bean>
            <bean id="configurationManager" class="tap03.service.impl.ConfigurationManagerImpl">
                <property name="configurationDao">
                    <ref bean="configurationDAO" />
                </property>
            </bean>
        </beans>
        applicationContewxt-JPA.xml:
        Code:
        <?xml version="1.0" encoding="UTF-8"?>
        <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" 
        "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
        <beans>
            <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
                <property name="persistenceUnitName" value="Tap03PU" />
                <property name="jpaVendorAdapter">
                    <bean class="org.springframework.orm.jpa.vendor.TopLinkJpaVendorAdapter">
                        <property name="showSql" value="true" />
                        <property name="generateDdl" value="true" />
                        <property name="databasePlatform" value="oracle.toplink.essentials.platform.database.MySQL4Platform" />
                    </bean>
                </property>
            </bean>
            
            <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                <property name="entityManagerFactory" ref="entityManagerFactory" />
                <property name="dataSource" ref="dataSource" />
            </bean>
            <bean id="documentDAOTarget" class="tap03.domain.dao.jpa.GenericDaoJpa" >
                <constructor-arg>
                    <value>tap03.domain.model.Document</value>
                </constructor-arg>
                <property name="entityManagerFactory" ref="entityManagerFactory" />
            </bean>
            <bean id="documentDAO" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" >
                <property name="transactionManager" ref="transactionManager" />
                <property name="target" ref="documentDAOTarget" />
                <property name="transactionAttributes">
                    <props>
                        <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                        <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
                        <prop key="save*">PROPAGATION_REQUIRED</prop>
                        <prop key="delete*">PROPAGATION_REQUIRED</prop>
                    </props>
                </property>
            </bean>
            <bean id="configurationDAO" class="tap03.domain.dao.jpa.GenericDaoJpa" >
                <constructor-arg>
                    <value>tap03.domain.model.Configuration</value>
                </constructor-arg>
                <property name="entityManagerFactory" ref="entityManagerFactory" />
            </bean>
        
        </beans>
        and finally the GenericDaoJpa.java:
        Code:
        package tap03.domain.dao.jpa;
        import java.io.Serializable;
        import java.util.Collection;
        import java.util.Map;
        import org.springframework.dao.DataAccessException;
        import org.springframework.orm.ObjectRetrievalFailureException;
        import org.springframework.orm.jpa.support.JpaDaoSupport;
        import tap03.domain.dao.GenericDao;
        public class GenericDaoJpa<T, ID extends Serializable>
            extends JpaDaoSupport
            implements GenericDao<T, ID>
        {
            private Class<T> entityClass;
            public GenericDaoJpa()
            {
            }
            public GenericDaoJpa(Class<T> type)
            {
                this.entityClass = type;
            }
            public Class<T> getPersistentClass()
            {
                return entityClass;
            }
            public T findById(ID id) throws ObjectRetrievalFailureException
            {
                return (T) getJpaTemplate().find(getPersistentClass(), id);
            }
            @SuppressWarnings("unchecked")
            public Collection<T> findAll()
            {
                String q = "SELECT z FROM "+ this.entityClass.getSimpleName() +" z" ;
                System.out.println( "GenericDaoJpa.findAll() q=\""+q+"\"" );
                return (Collection<T>) this.getJpaTemplate().find(q);
            }
            @SuppressWarnings("unchecked")
            public Collection<T> findByNamedQueryAndNamedParam(Class<T> entityClass,
                String queryName, Map<String,Object> params ) throws DataAccessException
            {
                return (Collection<T>) this.getJpaTemplate().findByNamedQueryAndNamedParams( queryName, params);
            }
            public T saveOrUpdate(T entity)
            {
                return getJpaTemplate().merge(entity);
            }
            public void delete(ID id)
            {
                /*
                 * Entity must be managed to call remove: tap03.domain.model.Document[docId=11],
                 * try merging the detached and try the remove again.
                 */
                this.delete( this.findById(id) );
            }
            public void delete(T entity)
            {
                getJpaTemplate().remove(entity);
            }  
        }

        Comment


        • #5
          Originally posted by cyrille37 View Post
          I've got JPA Toplink working well. But to wrok, I had to use the JpaDaoSupport.getJpaTemplate().
          Hello,

          thanks for posting. In what environment do you use Spring with Toplink? Standalone, or have you deployed your application to Tomcat?


          The Petclinic example also contains a JpaTemplateClinic as alternative to EntityManagerClinic. But unfortunately, it does not solve my problem.

          In my case it appears that Toplink simply doesn't get initialized correctly to process the JPA annotations on Entity classes.

          I'm a beginner too who wants to evaluate to what extent Spring could be an alternative to EJB 3.0.

          As mentioned, my Hibernate configuration works fine with JPA annotations. As far as Toplink is concerned, I was just curious to know whether I could easily use Toplink as alternative JPA provider...


          But I will give up on this issue (Toplink) now... I do not have the knowledge of the Spring internals yet to find out why Toplink doesn't get intialized correctly, and I do not have a working example for comparison:

          Spring+ Toplink-JPA (with JPA annotations, not xml-mapping), deployable to Tomcat 6
          Last edited by IngoM; Dec 18th, 2006, 08:15 AM.

          Comment


          • #6
            Ingo, can you please raise an issue on JIRA and assign it to me. It's probably a good idea to add an annotation-petclinic example to prevent users from having problems as you did.
            I haven't tried Tomcat 6.x which is still in beta and I would advice you to try the latest stable release which is 5.2-something.
            Thanks.

            Comment


            • #7
              Btw, can you give OpenJPA a try also? It would be helpful to pin point the problem - is it your configuration or something specific to oracle and tomcat?

              Comment


              • #8
                Originally posted by Costin Leau View Post
                Ingo, can you please raise an issue on JIRA and assign it to me. It's probably a good idea to add an annotation-petclinic example to prevent users from having problems as you did.
                I haven't tried Tomcat 6.x which is still in beta and I would advice you to try the latest stable release which is 5.2-something.
                Thanks.
                I'll make a deployment test to Tomcat 5.5 later today.

                As for the Petclinic example, if there is interest, I could send you my Hibernate JPA-annotations based version.

                Comment


                • #9
                  When creating the JIRA issue, please add the classes as an attachment.
                  The only thing I am worried about is packing all this samples - one reason why annotations where not provided was to be able to reuse the current example for non-java5 users.
                  I'll see what can be done. Thanks for the feedback!

                  Comment


                  • #10
                    Originally posted by IngoM View Post
                    Hello,
                    thanks for posting. In what environment do you use Spring with Toplink? Standalone, or have you deployed your application to Tomcat?
                    JDK 1.5, Tomcat 5.5.17, Spring 2, Toplink 9.1 build: b28

                    Comment


                    • #11
                      Originally posted by IngoM View Post
                      I'll make a deployment test to Tomcat 5.5 later today.
                      It might be worth a try to try a standalone deployment first, to see whether the problem is in the JPA configuration, or specifically in Tomcat deployment. Most likely it's Tomcat, as I was able to succesfully run a Spring-JPA-Toplink test app in standalone mode

                      Comment


                      • #12
                        I am having the same problem. What is the status of this issue now?

                        Comment


                        • #13
                          Sorry for the late reply. Try placing toplink and the jpa annotations inside shared/lib *or* common/lib folder- outside your web application. Let me know if that solves your problem.

                          Comment


                          • #14
                            Originally posted by Costin Leau View Post
                            Sorry for the late reply. Try placing toplink and the jpa annotations inside shared/lib *or* common/lib folder- outside your web application. Let me know if that solves your problem.
                            I have put my entity classes with JPA annotations in one jar and put it into one of these folders at a time and tried to deploy the rest of my web application on this Tomcat but deployment failed..

                            I got around this issue by switching to Hibernate for a moment but I would like to help resolving it.

                            What should I try now?

                            Comment


                            • #15
                              You shouldn't couple the JPA annotations along with your classes.
                              What I was suggesting was to remove the toplink jar from your war and place it under [TOMCAT]/shared/lib or [TOMCAT]/common/lib.

                              Comment

                              Working...
                              X