Status: New
Owner: ----

New issue 753 by guillaum...@gmail.com: 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 google-guice-dev+unsubscr...@googlegroups.com.
To post to this group, send email to google-guice-dev@googlegroups.com.
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.


Reply via email to