Blogs

SpringSource Blog

Using JPA in Spring without referencing Spring

Ben Hale

Spring 2.0 has added support for the JPA data access standard with all of the standard Spring support classes one would expect. Mark Fisher has a great post on how to use this new support. However one of the questions that we keep getting is why one would want to use a Spring class (JpaTemplate) to access an EntityManager. The best answer for this question lies in the value add that JpaTemplate provides. In addition to providing the one-liner convenience methods that are a hallmark of Spring data access, it also provides automatic participation in transactions and translation from PersistenceException to the Spring DataAccessException hierarchy.

But I still don't want to use JpaTemplate

That's fine because you don't have to sacrifice the power of Spring. Specifically the two biggest advantages (transaction participation and exception translation) are available without coding against Spring classes. In fact Spring actually has extensive support for plain API DAOs.

Transaction Participation

One of the benefits of Spring's declarative transaction management is that you never have to reference transaction structures in your code. So if you want automatic transaction participation all you need are a couple of bean definitions.

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" />

<bean class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<tx:annotation-driven />

The JpaTransactionManager is responsible for creating EntityManagers opening transactions and binding them to the current thread context. The <tx:annotation-driven /> simply tells Spring to put transactional advice on any class or method that has an @Transactional annotation on it. You can now just write your main-line DAO logic without having to worry about transactional semantics.

public Collection loadProductsByCategory(String category) {
    return entityManager.createQuery("from Product p where p.category = :category")
        .setParameter("category", category).getResultList();
}

Exception Translation

If you want Spring's exception translation you can get that as well. All that needs to happen is the introduction of the @Repository annotation on your class. This (really minor) Spring annotation simply tells the Spring container that this class is a persistence repository and needs to have exception translation performed on it. To get the exception translation a simple bean definition is required.

<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

That's fine, but how do I get an EnityManager?

This might actually be the coolest part. Basically you'd just define a DAO exactly the way you would if you weren't using Spring by adding the @PersistenceContext JPA annotation.

public class ProductDaoImpl implements ProductDao {

    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this. entityManager = entityManager;
    }

    public Collection loadProductsByCategory(String category) {
        return entityManager.createQuery("from Product p where p.category = :category")
            .setParameter("category", category).getResultList();
    }
}

By adding a single bean definition the Spring container will act as a JPA container and inject an EnitityManager from your EntityManagerFactory.

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

A post this long must mean a lot of code and configuration

But it doesn't! Now that we've show all the pieces and parts let's take a look at the complete system.

Code

  • @Repository for exception translation
  • @PersistenceContext for EntityManager injection
  • Plain JPA API code!
@Repository
public class ProductDaoImpl implements ProductDao {

    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this. entityManager = entityManager;
    }

    public Collection loadProductsByCategory(String category) {
        return entityManager.createQuery("from Product p where p.category = :category")
            .setParameter("category", category).getResultList();
    }
}

Configuration

  • LocalEnityManagerFactoryBean to create the EntityManagerFactory
  • JpaTransactionManager to manager JPA transactions
  • <tx:annotation-driven /> to tell Spring to look for @Transactional
  • Your bean definition!
<?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:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" />

    <bean id="productDaoImpl" class="product.ProductDaoImpl"/>

    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    <bean class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory"
            ref="entityManagerFactory" />
    </bean>

    <tx:annotation-driven />

</beans>

That's it. Two annotations and four bean definitions.

Additional Resources




Updated to remove ellipses from bean definitions. See comments for background.

Similar Posts

Share this Post
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google Bookmarks
  • DZone
  • LinkedIn
  • Slashdot
  • Technorati
  • Twitter
 

44 responses


  1. Couple of issues:

    1) JpaTemplate, for inexplicable reasons, slows down my app startup by an order of magnitude. So that's another reason to avoid it.

    2) Spring's JPA support is pretty bad at handling multiple persistence units (multiple persistence.xml files). The implementations will always scan everything and pick the right one.

    I'm sure both of the two issues above will be addressed in time, but it's something to be wary of.

    Also instead of using the Spring specific tx:annotation-driven, pitchfork will allow you to use spec compliant @TransactionAttribute annotations instead.

    Finally (and this has always caused me so much heartache) why does EVERY Spring xml example contain the ubiquitous '…' section (in the entity manager bean declaration)? It's often that bit that causes the most heartache!


  2. You're absolutely right on the use of ellipses in bean definition files. Here I am trying to prove that it doesn't take much configuration and I skipped the largest part. In my defense I skipped it because the configuration was so implementation dependent, not because of it's size. I've updated the post to remove the ellipses and highlight one of the niceties of Spring's LocalEntityManagerFactoryBean. By default it will use the Persistence class to find the JPA implementation and use the default EntityManager configuration so in the trivial case no configuration is actually required.


  3. After a bit of poking around I can now follow up on some of your concerns. A quick look at JpaTemplate implies that it\'s a pretty simple bean that doesn\'t have any complex startup routines. It\'s possible however that the slowdown is tied to your second point. It turns out that the behavior to search the entire classpath is only the default behavior in the LocalContainerEntiyManagerFactoryBean. And you can simply override that search by putting in a value for persistenceXmlLocaion. This behavior is actually the spec\'d behavior for all JPA providers. At any rate, you may simply be experiencing the same kind of slowdowns that people perceive when the use Hibernate; a slowdown from the technology, not the framework. If you have some profiling data or an example that I could run a profiler on, I\'d be happy to see what\'s up for you.

    As to the use of @TransactionAttribute, that\'s a more difficult call. There is much to be said for using the standard JEE annotations, but there are some downsides. The first is that @TransactionAttribute only allows you to specify propagation rules currently. There is no way to specify rollback or isolation rules. There is an @TransactionException annotation that can help with rollback behaviors but there are some serious problems with it. The issues are a little more involved than a comment should be, so I\'m trying to convince Juergen to write a blog entry on it.

    Needless to say, Spring will continue to support JPA transaction annotations as part of Pitchfork and may at some point honor them in the base transaction support. But for the foreseeable future we still feel that @Transactional provides value-add beyond JPA.


  4. Hi Ben,

    Regarding the classpath scanning, the issue isn't with the spec, it's with Spring's implementation (at least partially). it's sort of a design issue. Instead of having to specify an EMF Bean for every persistence unit, a saner approach would have been to define a bean that houses all the EMF's in the classpath. So in that case, it'd suck in all the persistence.xml, and LocalEMFBean for each one of the found resources. I agree that I'd still be paying the hibernate cost, but at least Spring wouldn't be doing its bit to increase the cost even more.

    Regarding transactions, I never claimed that @TransactionAttibute is better than @Transactional, I'm quite aware that Spring's transaction handling is more powerful. The point is that @Transactional IS referencing Spring, and using a spring specific feature. I'm sure we're all familiar with vendor documentatin for specs always suggesting that the user use a vendor specific feature, and I'm just pointing out that that's exactly what you're doing here, in an article that has a title implying the opposite!


  5. Nice short post for a taste of how to use JPA in Spring. I would recommend the LocalContainerEntityManagerFactoryBean, though, as opposed to the vanilla Local variety. The Local one is not really acting like a JPA Container like the LocalContainer one does.

    Also, isn't the default persistence provider the TopLink Essentials RI?


  6. For anything beyond the simplest case, LocalContainerEntityManagerFactoryBean is definitely the preferred class.


  7. Has somebody succeeded to run this example of Spring 2.0 JPA?
    Seems that PersistenceAnnotationBeanPostProcessor is not called, so the EntityManager dependency is not injected and I get NullPointer exception…

    Can somebody upload a complete (and working!) ZIP archive with Java and XML files for this sample? Maybe I'm doing wrong something.

    Thanks


  8. I have resolved the problem – thanks to gschmutz
    http://forum.springframework.org/showthread.php?p=75109


  9. [quote comment="42"]Hi Ben,

    Regarding the classpath scanning, the issue isn't with the spec, it's with Spring's implementation (at least partially). it's sort of a design issue. Instead of having to specify an EMF Bean for every persistence unit, a saner approach would have been to define a bean that houses all the EMF's in the classpath. So in that case, it'd suck in all the persistence.xml, and LocalEMFBean for each one of …[/quote]
    JIRA issue here (http://opensource.atlassian.com/projects/spring/browse/SPR-2531) – likely to be addressed in the upcoming 2.0-RC4.


  10. I am not sure if I am missing something here. I keep getting the following exception:

    org.springframework.dao.InvalidDataAccessApiUsageException: Unknown entity bean class: class com.volvo.ewarranty.domain.ModelFamily, please verify that this class has been marked with the @Entity annotation.

    persistence.xml contains the classes. The class has been annotated. My applicationContext is setup as Ben described here in this post.

    I am attempting to connect to a Derby db.

    Any thoughts.


  11. Attn: Dan Frey

    I've been experiencing the exact same problem, and I'm pretty sure I've followed the Spring JPA tutorial to a tee. Have you had any luck fixing your problem?


  12. Attn: Yogindra

    I believe it had something to do with Derby. I installed Oracle 10g XE and modified my connection settings and the problem disappeared. I haven't had the time to go back and further research why Derby was failing. Also, I made sure that I was explicitly defining the items in the persistence.xml. For example, the classes.

    Sorry I couldn't be of more help.

    Dan


  13. I had to give the bean a name "transactionManager" to get this to work. Here is my working configuration.


  14. It trimmed my xml config from my post. Here is an html encoded xml.

    <?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:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" />

    <bean id="productDaoImpl" class="product.ProductDaoImpl"/>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

    <bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <tx:annotation-driven />
    </beans>


  15. A comment and a question:

    First, thank you for this post. Nice to see all of this put together with the examples.

    My comment: I struggled with the same issue that vatel did regarding beanFactory v.s. ApplicationContext. I think it is worth noting in your presentation that post processors like the PersistenceAnnotationBeanPostProcessor only get called if beans are loaded using the ApplicationContext. I'm fairly new to spring, so maybe this is commonly understood, and I missed it.

    My Question: I am implementing a generic DAO implementation in which all of my DAO's inherit from a common base class (GenericDAO). I would like to keep the EntityManager in the base class to be used by all subclasses. I have tried implementing this with the @PersistenContext annotation in the base class, however, PersistenceAnnotationBeanPostProcessor does not seem to inject the entity manager to the base class. If I create a subclass attribute/function and annotate this, then the injection works fine. Do I have a configuration issue, or is this a limitation in spring?

    Any input would be greatly appreciated.


  16. Disregard last question: found visibility on base class function was not set correctly. All is working well.

    Thank you


  17. I have implemented this in a project but am running into a strange issue. Everything works great until I try and delete. When I try that I get the following exception:

    java.lang.IllegalArgumentException: Removing a detached instance com.jc.dao.entity.Story#1
    at org.hibernate.ejb.event.EJB3DeleteEventListener.performDetachedEntityDeletionCheck(EJB3DeleteEventListener.java:47)
    at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:75)
    at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:49)
    at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:766)
    at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:744)
    at org.hibernate.ejb.AbstractEntityManagerImpl.remove(AbstractEntityManagerImpl.java:245)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:585)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:176)
    at $Proxy15.remove(Unknown Source)

    For frame of reference I'm using a generic DAO similar to an early poster. This generic DAO has all the basic CRUD operations. Add, Update and Retrieve all work just fine, it's simply the delete that fails.

    I've searched and it seem that this has something to do w/ my transactions though I can't (though experimentation) track it down. I was wondering if anyone else has see this behavior and found a resolution.

    Thanks in advance for any help.


  18. I think you should provide a downloadable working examaples in your articles. The theory is ok but when we try what you suggest IT DOES NOT WORK because there is alway some piece missing or incomplete!


  19. Have you tried this with Glassfish V2? I get the following error:
    javax.el.ELException: org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: Exception Description: Cannot use an EntityTransaction while using JTA.
    I think the problem is that the JpaTransactionManager does not use JTA ?


  20. I wish I could delete my previous comment.
    My code is working fine now based on what explained in this article. I had to struggle with the configuration a little but I have gained better understanding of the Spring framework. Thank you


  21. The problems with loading multiple persistence units are addressed in Spring 2.5 by the PersistenceUnitManager check out the documentation on this, for the full story. http://static.springframework.org/spring/docs/2.5.x/reference/orm.html#orm-jpa.


  22. Hi,

    is the solution with @PersistenceContext demonstrated above thread-safe? As far as I know in Spring a bean is a singleton per default. What happens if two or more threads call methods of the injected entityManager in parallel?

    Thanks.
    Martin


  23. Yes, this is thread-safe, since the injected EntityManager is actually a shared EntityManager proxy that will transparently delegate to the actual thread-bound EntityManager resource in the background.

    In other words, any "xxx" call on that EntityManager proxy actually translates to a sort of "entityManagerFactory.getCurrentEntityManager().xxx" call at runtime.

    This style is actually defined by the JPA specification; we just adapted it into the Spring environment.

    Juergen


  24. With this example I'm interesting to know how you could manage some error, like some duplicate entry that you would try to make a retry on the entity but with an other generated value for the unique property… I tryed some aop interception or to catch some errors on my side but this get me some problems and put transactions errors…

    Do you have any idea on how to manage such errors ?

    Thanks

    Julien


  25. I'm not able to get the EntityManager.it gives me null.


  26. Because of the lack of multiple persistence units handling in spring, I'm using a EntityManagerFactory instance in my DAOs and getting the EntityManager's instance with entityManagerFactory.createEntityManager().
    For some reason, transactions never commit.
    Here is the chain: some client calls some service method. The service method is annotated with @Transactional. The service method calls one or more DAO methods performing CRUD.
    When returning from the service method, nothing is commited into the database.

    When using JpaDaoSupport (which I don't want) with the same spring configuration, everything works fine.

    Why?


  27. Thanks Ben for this nice blog… I have a question for you…

    Are JPA Annotations required to utilize the entityManager injection?

    Background:
    My ORM mappings are defined using hibernate hbm xml files and this is perfectly fine when running JPA on JBoss with the hibernate implementation. However, when I try an inject the entityManager in my DAO pojo, as described above, I get a " is not mapped" error at runtime for any db access. The only difference in the code that works and does not work is where the entityManager is introduced.

    If I use JPA annotations in the entity classes instead of the XML mappings… Then it does not matter where the entityManager is injected.

    Any ideas?


  28. Hi all, I am currently using Spring JPA to inject my Entity Manager for merging purposes. I have follow the same concept which mention from this blog however I received null pointer exception of my entity manager. I guess something missing which doens't mention from the step above.

    Below is my partially code and implementation:

    HibernateSessionMergeConverter:

    @Repository
    public class HibernateSessionMergeConverter implements TypeConverter {

    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
    this. entityManager = entityManager;
    }

    public Object coerceToUi(Object val, Component comp) {

    if(val instanceof GenericBean){
    entityManager.merge(val);
    }
    return val;
    }

    JPA Context XML:

    Your help and consideration is highly appreciated. Thanks in advance.


  29. Hi,

    Thanks for your post. It was of great help for setting up the project with eclipselink.
    Our project worked all fine in non-dm environment.

    However currently we have a requirement to port our project to OSGI. As a first step I am trying to use Spring-DM for making the service layer work. I faced many other problems I posted at http://forum.springsource.org/showthread.php?t=71414. I am using the loadtimeweaver provided by Martin in his blog http://martinlippert.blogspot.com/2009/04/load-time-weaving-for-spring-dm.html.

    Now when I run the project in OSGI environment I see that entitymanager is not getting injected in the service. Hence I get NPE.
    Does anybody have any inputs?

    Thanks in advance,
    Shashi


  30. Hi,

    Finally I could solve all the issues. The issue about the null entitymanager was resolved when I replaced

    with

    Regards,
    Shashi


  31. Hi,

    Finally I could solve all the issues. The issue about the null entitymanager was resolved when I replaced

    HTML Code:

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

    with

    <context:annotation-config/>

    Regards,
    Shashi


  32. Thank you for the example, but I have a small question. If we wanted to have an entity manager of 'extended' context, how do we go about it given the example? My issue is that I need to implements a 'long conversation' (I could not solve this in spring alone) – as EJB supports it with a session bean, as long as the entity manager survives over many thread calls. In that case, is this example still 'conversation' safe, if you know what I mean?

    Will


  33. If you're getting null pointer exceptions and your setEntityManager() method isn't being called by Spring (causing your entity manager to not be injected), consider putting the @PersistenceContext annotation on the field instead of the setter.


  34. Hi Erik,

    Even after keeping the annotation at the Field level , i am getting the same error " Entity manger is null " below is my configuration

    Please read http://www.springframework.org/docs/reference/transaction.html

    please let me know if any thing is wrong in my config, appricate your help


  35. Oh, nice tutorial thank you


  36. I tried to recreate an application like this, but I had a lot of problems.
    See my post on http://forum.springsource.org/showthread.php?t=88989
    If someone knows why I had all the problems, and why the example on this blog works fine, I would be very interested to know it?!
    Thanks you


  37. Nice post! Straight to the point.

    Following your example, I just can't seem to get the EntityManager injected. The EntityManagerFactory has been instantiated, but no EntityManager was created or injected (based on debug logs from org.springsource). What would keep this from happening?


  38. Thanks for the nice article. Any idea how @Resource annotation is used?


  39. cool! i also wanna share this very spoon fed version of Spring Hibernate JPA combo

    http://www.adobocode.com/spring/spring-with-hibernate-annotations

    tnx


  40. Hi Team ,

    I got exception this when i'm saving data through Entity Manager

    org.springframework.dao.InvalidDataAccessApiUsageException: Transaction not active; nested exception is ang.IllegalStateException: Transaction not active


  41. Hi,

    just FYI for people trying this. Nothing ever got committed until I included aspectj-1.6.11.jar in my classpath.

    Cheers,
    David


  42. Nothing gets commited!!
    Added aspectjs library.. and still nothing commits..

    Ben.. anybody?


  43. Thank you so much for posting this. You're the first person in about 5 million google searches that made sense on how to use JPA in a Spring project without referencing Spring. I was bashing my head against transaction limitations and enforcement until I took a step back and read this blog. Thanks again.


  44. I’m impressed, I must say. Really hardly ever do I encounter a weblog that’s each educative and entertaining, and let me inform you, you've got hit the nail on the head. Your concept is excellent; the difficulty is one thing that not sufficient people are speaking intelligently about. I am very joyful that I stumbled throughout this in my search for something relating to this.

5 trackbacks

Leave a Reply