javajpajersey-2.0guice-persist

JPA EntityManager returns old state after update


Introduction

I'm currently working on migrating GWT-RPC application to use RESTful services. For that, I repalced all RPC calls with domino-rest and additionally updated jersey1 to jersey2. Yes, jersey1 was already there for some external communication. Now, I have migrated all RPC calls to REST and at first I thought everything works great.

For dependcy injection I use Guice 6 and after migration to Jersey2 the HK2-Guice-bridge. For persistence of my multiple DBs I use JPA/Hibernate. Just for completeness: before starting the migration to Jersey2 and domino-rest everything was working.

Problem

Whenever I update a domain object to the database, that works perfect. But, when I request it again by a GET request I sometimes (!) receive an old version (from before the update) and sometimes the correct updated one. I checked the entire call stack and figured out, that it's no GET caching problem. The problem comes from my repository, more precise the EntityManager, sometimes returns the old version. The jersey2 log showed me, that different threads are used, so as the EntityManager is not thread-safe I was thinking whether that's the problem. I'm not sure or is there anything else. If it's the thread-safe issue, it would be nice if you can help me what's wrong.

Sources

Generic-Repository

public class Repository<T> {

    @Inject
    private Provider<EntityManager> emProvider;

    private final Class<T> entityType;

    @Inject
    public Repository(final Class<T> entityType) {
        this.entityType = entityType;
    }

    public EntityManager getEntityManager() {
        return emProvider.get();
    }

    public T get(long id) {
        return getEntityManager().find(entityType, id);
    }

    public T update(T o) {
        EntityManager em = getEntityManager();
        em.merge(o);
        em.flush();
        return o;
    }

    //other code omitted
}

Persistence Module (one of more)

public class PersistenceModule extends PrivateModule {

    private final String unitName;

    public PersistenceModule(String unitName) {
        this.unitName = unitName;
    }

    @Override
    protected void configure() {
        // I know setAutoBeginWorkOnEntityManagerCreation is not recommended, but for the time being.
        install(new JpaPersistModule(unitName, JpaPersistOptions.builder().setAutoBeginWorkOnEntityManagerCreation(true).build()));
        bind(PersistenceManager.class).asEagerSingleton();
        expose(PersistenceManager.class);

        // User
        TypeLiteral<Repository<User>> userRepoType = new TypeLiteral<>() {
        };
        bind(userRepoType).toInstance(new Repository<>(User.class));
        expose(userRepoType);
    }
}

Persistence Manager (one of more)

@Singleton
public class PersistenceManager {

    private final PersistService service;

    @Inject
    public PersistenceManager(PersistService service) {
        this.service = service;
        service.start();
    }

    public void stop() {
        service.stop();
    }
}

Final words

My entry point for the web application is the ApplicationConfig extending ResourceConfig, where Guice.createInjector with the above mentioned PersistenceModule is called. The injector is then passed to the HK2-Guice Bridge. I hope you have a clue. Is there anything more required? Thank you!


Solution

  • Often it's a minor thing and in that case I missed to add filter("/*").through(PersistFilter.class); to my Module extending ServletModule. I use guice-persist that's why PersistService and PersistFilter is in use and PersistFilter starting the UnitOfWork. Thank you both for your valuable input.