Injecting an entitymanager in @ApplicationScoped bean

Viewed 697

I am porting an existing JBOSS JEE application to Quarkus. I am using a number of HV custom validators that require injection.

For that purpose I've defined all custom validators that require injection as bean in my libraries like this:

@ApplicationScoped
public class SomeValidator implements ConstraintValidator<SomeValidation, AnObject> {

    @Inject
    public BeanUsingEntityManager bean;

Note: It is common code, so it should remain working on JBOSS as well

Next I defined a REST service. The REST service makes use of an application scoped bean like this.



@ApplicationScoped
public class ApplicationContext {

    @PersistenceContext( unitName = "A" )
    EntityManager em;

    @Produces
    @EnityManagerA // required qualifier to make datasource unique in JEE context (there are more)
    public EntityManager produce() {
        return em;
    }
    // NOTE: quarkus does not allow the @Produces on a field, which is allowed in JBOSS hence the method

    @Produces
    public BeanUsingEntityManager createBeanUsingEntityManager () {
        // some logic that requires the entity manager.
    }
}

Now the problem is simplified, but I keep on running into an error message.

Caused by: javax.enterprise.inject.CreationException: Synthetic bean instance for javax.persistence.EntityManager not initialized yet: javax_persistence_EntityManager_b60c51739990fc921960fc78caeb075a811a91a6
    - a synthetic bean initialized during RUNTIME_INIT must not be accessed during STATIC_INIT
    - RUNTIME_INIT build steps that require access to synthetic beans initialized during RUNTIME_INIT should consume the SyntheticBeansRuntimeInitBuildItem
    at javax.persistence.EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.create(EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.zig:167)
    at javax.persistence.EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.create(EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.zig:190)
    at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:96)
    at io.quarkus.arc.impl.AbstractSharedContext.access$000(AbstractSharedContext.java:14)
    at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
    at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
    at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
    at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
    at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
    at javax.persistence.EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.get(EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.zig:222)
    at javax.persistence.EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.get(EntityManager_e1903961aa3b05f292293ca76e991dd812f3e90e_Synthetic_Bean.zig:238)
    at nl.bro.gm.gmw.dispatch.resources.ApplicationContext_Bean.create(ApplicationContext_Bean.zig:131)
    ... 59 more

I'm new to Quarkus. So, not sure to how to handle this issue or even if I make the correct assumptions. I can imagine that Quarkus wants to give me a fresh entitymanager each request (which I understand), but that poses a problem for my application scoped beans.

What am I doing wrong here?

1 Answers

So, the full answer is that the EntityManager is created at the runtime init phase whereas the ValidatorFactory (and the ConstraintValidators) are created at static init time.

The Quarkus bootstrap goes static init -> runtime init.

So in your case, you can't access a @Singleton bean which uses the EntityManager during static init as it's not yet available.

Making your bean @ApplicationScoped will create a proxy and avoid this chicken and egg problem.

You will have only one BeanUsingEntityManager for your whole application.

The EntityManager is a bit different because we wrap it and you will get one new EntityManager/Session per transaction, which is what is expected as EntityManagers/Sessions are not thread safe.

Related