My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
JPA  
Using JPA with Guice Persist.
Updated Oct 16, 2011 by sberlin

Java Persistence API (JPA)

JPA is a standard released as part of JSR-220 (or EJB3). It is roughly an analog to Hibernate or Oracle TopLink; and they are also the two most prominent vendors of JPA. Guice Persist supports JPA in a vendor-agnostic fashion, so it should be easy to swap between implementations (such as Appengine's datastore) should you need to.

Enabling Persistence Support

To enable persistence support, simply install the JPA module:

Injector injector = Guice.createInjector(..., new JpaPersistModule("myFirstJpaUnit"));

In JPA, you specify your configuration in a persistence.xml file in the META-INF folder of that is available on the classpath (if inside a jar, then at the root for example). In this file you declare several Persistence Units that are roughly different profiles (for example, backed by different databases). Here is an example of a simple JPA configuration:

<?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"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
	http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

	<!-- A JPA Persistence Unit -->
	<persistence-unit name="myFirstJpaUnit" transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
 
		<!-- JPA entities must be registered here -->
		<class>com.wideplay.warp.jpa.JpaTestEntity</class>

		<properties>
			<!-- vendor-specific properties go here -->
		</properties>
	</persistence-unit>

</persistence>

To tell Guice Persist which persistence unit you wish you use, you specify its name when creating your module:

Injector injector = Guice.createInjector(..., new JpaPersistModule("myFirstJpaUnit"));

Finally, you must decide when the persistence service is to be started by invoking start() on PersistService. I typically use a simple initializer class that I can trigger at a time of my choosing:

public class MyInitializer { 
	@Inject MyInitializer(PersistService service) {
		service.start(); 
 
 		// At this point JPA is started and ready.
	} 
}

It makes good sense to use Guice's API to start all services in your application at once. I recommend you think about how it fits into your particular deployment environment when doing so.

However, in the case of web applications, you do not need to do anything if you simply install the PersistFilter (see below).

Session-per-transaction strategy

This is a popular strategy, where a JPA EntityManager is created and destroyed around each database transaction. Set the transaction-type attribute on your persistence unit's configuration:

 <persistence-unit name="myFirstJpaUnit" transaction-type="RESOURCE_LOCAL">

Using the EntityManager inside transactions

Once you have the injector created, you can freely inject and use an EntityManager in your transactional services:

import com.google.inject.persist.Transactional;
import javax.persistence.EntityManager; 
 
public class MyService {
	@Inject EntityManager em; 
 
	@Transactional 
	public void createNewPerson() {
		em.persist(new Person(...)); 
	} 
}

This is known as the session-per-transaction strategy. For more information on transactions and units of work (sessions), see this page.

Note that if you make MyService a @Singleton, then you should inject Provider<EntityManager> instead.

Web Environments (session-per-http-request)

So far, we've seen the session-per-transaction strategy. In web environments this is atypical, and generally a session-per-http-request is preferred (sometimes also called open-session-in-view). To enable this strategy, you first need to add a filter to your ServletModule:

public class MyModule extends ServletModule {
  protected void configureServlets() {
    install(new JpaPersistModule("myJpaUnit"));  // like we saw earlier.

    filter("/*").through(PersistFilter.class);
  }
}

You should typically install this filter before any others that require the EntityManager to do their work. Note that with this configuration you can run multiple transactions within the same EntityManager (i.e. the same HTTP request).

Comment by mendapar...@gmail.com, Apr 3, 2011

I have a different persistence.xml in src/test/resources/META-INF in my maven project for unit tests but it seems that the persistence.xml in src/main/resources/META-INF gets precedence.

Is it possible to specify different persistence.xml for tests?

Comment by brian.bl...@gmail.com, Jul 8, 2011

Is there a way to load the properties for a persistence unit from a properties file? I can do this with standard JPA, but I don't see a way to inject custom properties into the JpaPersistService? where it creates the EntityManagerFactory?.

Comment by brian.bl...@gmail.com, Jul 11, 2011

I found it. You can pass properties to the JpaPersistModule?. For example, when creating JpaPeristModule?, you can invoke:

new JpaPersistModule?("myapp-db").properties(hibernateJpaProperties)

Comment by zyskow...@gmail.com, Jul 26, 2011

It looks that injecting EntityManager? this way:

@Inject EntityManager? em;

breaks persist() and merge() functionality. I tested it on Jboss 5/Hibernate. Everyting else works, but objects just won't be saved. We had to change it to:

@Inject Provider<EntityManager> em;

There are great warp-persist examples here: http://code.google.com/p/warp-persist-sample/. With minor modifications it will work with guice-persist engine.

Comment by ungar...@gmail.com, Aug 25, 2011

I quote zyskow, the EntityManager? injection does not work also on Tomcat7.0.19/Hibernate3.6.7.

Comment by moha...@gmail.com, Nov 16, 2011

Hello,

I'd like to ask you if it's possible to make the PersistFilter? class not final.

Cause I need to start the PersistService? when the servlet context is initialized. But when the filter starts it throws an error.

If it wasn't final or if it could check if the PersistService? is already initialized would solve my problem.

Comment by anu...@gmail.com, Dec 11, 2011

There is the hint "Note that if you make MyService? a @Singleton, then you should inject Provider<EntityManager> instead." IMHO this not only is true if MyService? is a @Singleton but also if MyOtherService? is a @Singleton and is using MyService? which itself is NOT @Singleton.

Comment by pmmi...@gmail.com, Dec 16, 2011

Would look to add something for newcomers like me. Don't know how obvious or not this is (it wasn't for me), but if you instantiate MyService? MANUALLY your EntityManager? will be null and calls will throw NullPointerException?. Since we are using Guice already, just create a new module which you can add after MyModule? when you call createInjector

public class ServiceModule? extends AbstractModule? {

@Override protected void configure() {
bind(Service.class).to(MyService?.class);
}
}

Comment by alexande...@gmail.com, Dec 23, 2011

http://google-guice.googlecode.com/git/javadoc/com/google/inject/persist/PersistFilter.html

For multiple providers, you should register this filter once per provider, inside a private module for each persist module installed (this must be the same private module where the specific persist module is itself installed).

Is there an example somewhere? I tried several things but was not able to use multiple persistence units with the PersistFilter?.

https://groups.google.com/forum/#!topic/google-guice/2VK-bdsnjZc/discussion

Comment by sekaran....@gmail.com, Jan 13, 2012

The module file for this sample may also be kindly furnished for the benefit of users new to Guice but have used Jpa earlier.

Comment by alex.che...@gmail.com, Feb 4, 2012

I'm using an environment with guice-servlet running on a tomcat and hibernate under guice-persist. The problem I've encountered is that when I use em.getReference() in one request the loaded proxy object stays in the entitymanager cache and may appear in another request where I expect to have an object completely loaded from the DB.

I'm used to using hibernate in EJB3 environment where it is a default behavior. The entity manager cache is clear for each new request. Isn't it a more safe behavior for guice-persist to clear the session for each request? Or at least to give it as a setting for JpaPersistModule??

There is a special flag in hibernate SessionImpl? "autoClear" which is responsible for EJB3-behavior. Is there any way I could enable the flag when the new entity manager is being created by JpaPersistModule??

Comment by owen.k.b...@gmail.com, Mar 2, 2012

"Note that if you make MyService? a @Singleton, then you should inject Provider<EntityManager> instead."

When should MyService? be a singleton? If I am using the DAO without state, i.e. injecting it into my Servlets for processing through a Provider, should it be a one and done created object? I am creating a new one each time, but have noticed that on message boards people say to make the DAO Services singletons, is that right?


Sign in to add a comment
Powered by Google Project Hosting