quarkus: @Inject Injection into EntityListener not working

Describe the bug I do have JPA entities annotated with @EntityListeners. I @Inject some CDI bean (@RequestScoped in my case but happens for other scopes, too) into the EntityListener. The bean never gets injected, the reference is allways null.

Things I tried:

  • placing some CDI scope annotation onto the entity listener.
  • Tried different CDI scopes on the injected bean
  • Tried all variants of injection: constructor-, setter- and attribute-injection on the listener

Expected behavior Instance of the CDI bean should get injected

Actual behavior The CDI bean reference is allways null resulting in a NPE when accessing some attribute of the bean.

To Reproduce See attached test case

Configuration

quarkus.datasource.url=jdbc:h2:tcp://localhost/mem:test
quarkus.datasource.driver=org.h2.Driver
quarkus.hibernate-orm.database.generation=drop-and-create

(Also happens with postgresql, drop-and-create is just for testing)

Environment (please complete the following information):

  • Output of java -version: from 8 to 11
  • Quarkus version or git rev: 1.2.0

Additional context Interestingly, when the CDI bean I want injected into the EntityListener ist injected somewhere else (e.g. some @ApplicationScoped bean), injection works. Possible causse: looks like Quarkus bean discovery does not regard EntityListeners as trigger for registering some bean during compile-time-initialization.

Example code:

src/main/java/…

package org.acme;

import java.util.UUID;

import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.Id;
import javax.persistence.Version;

@Entity
@EntityListeners(FooListener.class)
public class FooEntity {

	@Id
	private String id = UUID.randomUUID().toString();
	@Version
	private long version;
	private String data;

	// getters/setters omitted for brevity
}
package org.acme;

import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.persistence.PrePersist;

// also happens with @Dependent
public class FooListener {

	@Inject
	private FooBean fooBean;

	@PrePersist
	public void prePersist(FooEntity entity) {
		entity.setData(fooBean.pleaseDoNotCrash());
	}
}
package org.acme;

import javax.enterprise.context.RequestScoped;

@RequestScoped
public class FooBean {

	public String pleaseDoNotCrash() {
		return "Yeah!";
	}
}

src/test/java/…

package org.acme;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;

import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

@QuarkusTest
public class EntityListenerInjectionTest {

	@Inject
	private EntityManager em;

	@Test
	@Transactional
	public void shouldNotCrash() {
		FooEntity o = new FooEntity();
		em.persist(o);
	}

	@Test
	@Transactional
	public void shouldInvokeEntityListener() {
		FooEntity o = new FooEntity();
		em.persist(o);
		assertEquals("Yeah!", o.getData());
	}
}
package org.acme;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.h2.H2DatabaseTestResource;

@QuarkusTestResource(H2DatabaseTestResource.class)
public class TestResources {
}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 9
  • Comments: 34 (21 by maintainers)

Commits related to this issue

Most upvoted comments

For all those arriving here via google:

A workaround is to create some other bean and @Inject your bean there… just so Quarkus knows it needs to register your bean for CDI injection.

@ApplicationScoped
public class JPAEntityListenerInjectionWorkaround {
  @Inject FooBean fooBean;
}

Then retrieve your bean instance in the EntityListener like this: FooBean fooBean = CDI.current().select(FooBean.class).get();

+1

@eliaharm I think you still need to @Inject JsonWebToken somewhere (it doesn’t really matter where or if it is used there, as long as the bean injecting it is used, or marked as @io.quarkus.arc.Unremovable).

I think Quarkus is like “you don’t use the bean? I’ll not pack it then” on buildtime, and CDI.current() lookup alone do not classify as “use”.

Fixed by #20708

@TheParad0X CDI.current().select(FooBean.class).get(); still works fine for me in Quarkus 2.1. Just make sure the bean is injected somewhere else, or that it carries @io.quarkus.arc.Unremovable.

OMG, sorry for missing this 😦

may I re-classify this report as a feature request?

sure!