Status: New
Owner: ----
New issue 753 by [email protected]: JpaLocalTxnInterceptor is
inconsistent. It uses both UnitOfWork and JpaPersistService
http://code.google.com/p/google-guice/issues/detail?id=753
Description of the issue:
JpaLocalTxnInterceptor is inconsistent as it uses the "JpaPersistService
emProvider" field to begin a transaction but uses the "UnitOfWork
unitOfWork" to finish it. When the "UnifOfWork" binding of the
JpaPersistModule is overriden, this causes incoherent states and eventually
crashes.
Here is a class (I used nested class to keep a single java file) that
reproduce the issue:
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Persistence;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.persist.PersistService;
import com.google.inject.persist.Transactional;
import com.google.inject.persist.UnitOfWork;
import com.google.inject.persist.jpa.JpaPersistModule;
import com.google.inject.util.Modules;
public class TestGuiceUnitOfWork {
@Entity
public static class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "name")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Singleton
public static class EntityManagerFactoryProvider implements
Provider<EntityManagerFactory>, PersistService {
private EntityManagerFactory emFactory;
@Override
public EntityManagerFactory get() {
return emFactory;
}
@Override
public void start() {
this.emFactory =
Persistence.createEntityManagerFactory("my-pu");
}
@Override
public void stop() {
emFactory.close();
emFactory = null;
}
}
@Singleton
public static class EntityManagerProvider implements
Provider<EntityManager>, UnitOfWork {
private final ThreadLocal<EntityManager> entityManager = new
ThreadLocal<EntityManager>();
@Inject
private Provider<EntityManagerFactory> emf;
@Override
public EntityManager get() {
return entityManager.get();
}
@Override
public void begin() {
System.err.println("Begin");
entityManager.set(emf.get().createEntityManager());
}
@Override
public void end() {
entityManager.remove();
System.err.println("End");
}
}
public static class MyGuicePersistModule extends AbstractModule {
@Override
protected void configure() {
bind(EntityManagerFactory.class).toProvider(EntityManagerFactoryProvider.class);
bind(PersistService.class).to(EntityManagerFactoryProvider.class);
bind(EntityManager.class).toProvider(EntityManagerProvider.class);
bind(UnitOfWork.class).to(EntityManagerProvider.class);
bind(InjectedClass.class);
}
}
public static class InjectedClass {
@Transactional
public void doAction() {
}
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(Modules.override(new
JpaPersistModule("a")).with(new MyGuicePersistModule()));
InjectedClass instance =
injector.getInstance(InjectedClass.class);
injector.getInstance(PersistService.class).start();
try {
instance.doAction();
} finally {
injector.getInstance(PersistService.class).stop();
}
}
}
an example of the persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<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="my-pu">
<class>TestGuiceUnitOfWork$MyEntity</class>
<properties>
<property name="hibernate.connection.pool_size" value="16"/>
<property name="javax.persistence.jdbc.driver"
value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
And one set of Maven dependencies:
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-persist</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.1.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.2.1.Final</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.172</version>
</dependency>
This leads to the following stacktrace:
Exception in thread "main" java.lang.NullPointerException
at
com.google.inject.persist.jpa.JpaPersistService.begin(JpaPersistService.java:70)
at
com.google.inject.persist.jpa.JpaLocalTxnInterceptor.invoke(JpaLocalTxnInterceptor.java:49)
at TestGuiceUnitOfWork.main(TestGuiceUnitOfWork.java:121)
Expected behaviour:
JpaLocalTxnInterceptor.invoke should not call "emProvider.begin();"
but "unitOfWork.begin()". This would also require an extra-method
on "UnifOfWork": "isWorking()".
--
You received this message because this project is configured to send all
issue notifications to this address.
You may adjust your notification preferences at:
https://code.google.com/hosting/settings
--
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice-dev?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.