Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

JPA EntityManager not working when using Guice's PrivateModule

283 views
Skip to first unread message

Óscar Andrés López

unread,
Mar 17, 2021, 6:20:05 AM3/17/21
to google-guice
Hi, this is a crosspost from a question originally asked on Stack Overflow, I thought I might get better results here. Copying verbatim:

I have a service with a persistence setup using JPA, Hibernate and Guice (if it's useful, I'm not using Spring). This is the first, working version of my code:

    public class BookDao {
    
        @Inject
        protected Provider<EntityManager> entityManagerProvider;
    
        protected EntityManager getEntityManager() {
            return entityManagerProvider.get();
        }
    
        @Transactional
        public void persist(Book book) {
            getEntityManager().persist(book);
        }
    
    }
    
    public class MyAppModule extends AbstractModule {
    
        @Override
        protected void configure() {
            initializePersistence();
        }
    
        private void initializePersistence() {
            final JpaPersistModule jpaPersistModule = new JpaPersistModule("prod");
            jpaPersistModule.properties(new Properties());
            jpaPersistModule.configure(binder());
            install(jpaPersistModule);
        }
    
    }

But now I need to configure multiple persistence units. I'm following the advice in this mailing list, and according to them, I should move my module logic to a private module. I did as suggested and created a second version of the same code, the changes are commented below:

     @BindingAnnotation
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ FIELD, PARAMETER, METHOD })
    public @interface ProductionDataSource {} // defined this new annotation
    
    public class BookDao {
    
        @Inject
        @ProductionDataSource // added the annotation here
        protected Provider<EntityManager> entityManagerProvider;
    
        protected EntityManager getEntityManager() {
            return entityManagerProvider.get();
        }
    
        @Transactional
        public void persist(Book book) throws Exception {
            getEntityManager().persist(book);
        }
    
    }
    
    public class MyAppModule extends PrivateModule { // module is now private
    
        @Override
        protected void configure() {
            initializePersistence();
            // expose the annotated entity manager
            Provider<EntityManager> entityManagerProvider = binder().getProvider(EntityManager.class);
            bind(EntityManager.class).annotatedWith(ProductionDataSource.class).toProvider(entityManagerProvider);
            expose(EntityManager.class).annotatedWith(ProductionDataSource.class);
    
        }
    
        private void initializePersistence() {
            JpaPersistModule jpaPersistModule = new JpaPersistModule("prod");
            jpaPersistModule.properties(new Properties());
            install(jpaPersistModule);
        }
    
    }

The newly annotated EntityManager is being correctly injected by Guice and is non-null, but here's the fun part: some of my unit tests started failing, for example:

    class BookDaoTest {
    
        private Injector injector;
        private BookDao testee;
    
        @BeforeEach
        public void setup() {
            injector = Guice.createInjector(new MyAppModule());
            injector.injectMembers(this);
            testee = injector.getInstance(BookDao.class);
        }
    
        @Test
        public void testPersistBook() throws Exception {
            // given
            Book newBook = new Book();
            assertNull(newBook.getId());
            // when
            newBook = testee.persist(newBook);
            // then
            assertNotNull(newBook.getId()); // works in the first version, fails in the second
        }
    
    }

In the first version of my code the last line above just works: the entity is persisted and has a new id. However, in the second version of my code (using a PrivateModule and exposing an annotated EntityManager from it) the persist() operation doesn't work anymore, the entity is without an id. What could be the problem? I didn't do any other configuration changes in my environment, and I don't see error messages in the logs. Let me know if you need more details.

Óscar Andrés López

unread,
Mar 27, 2021, 4:53:31 PM3/27/21
to google-guice
I found the solution, it's detailed here. TL;DR: the @Transactional annotation was not being executed in the second version of my code, as a workaround I had to implement transaction management by hand. It seems that I stumbled into a Guice bug?
Reply all
Reply to author
Forward
0 new messages