Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting generic Beans with CDI/Weld

I just come from my tiny nice JavaSE/Guice world and am currently discovering the path of "carried by the container"-EE6. After having some trouble with Glassfish3.1, I just switched to JBoss and am now facing a problem that shouldnt be one.

As infrastructural assisting class, im trying to create a generic repository/DAO for any kind of entity. In a very simple manner, this might look like this one.

public class Repository<E, K extends Serializable & Comparable<K>> {

    private final Instance<EntityManager> entityManagerInstance;

    protected final Class<E> getDomainObjectClass() {
        return domainObjectClass;
    }

    private final Class<E> domainObjectClass;

    protected final EntityManager getEntityManager() {
            return entityManagerInstance.get();
    }

    @Inject
    public Repository(Instance<EntityManager> entityManageryProvider, Provider<E> domainObjectProvider) {
            //This is a dirty hack, sadly :(
            domainObjectClass = (Class<E>)domainObjectProvider.get().getClass();
            this.entityManagerInstance = entityManageryProvider;
    }

    public final void persist(E domainObject) {
        final EntityManager em = getEntityManager();
        em.persist(domainObject);
    }

    public final Collection<E> getAllEntities() {
            final EntityManager em = getEntityManager();
            final CriteriaBuilder cb = em.getCriteriaBuilder();
            final CriteriaQuery<E> query = cb.createQuery(getDomainObjectClass());

            final List<E> result = em.createQuery(query).getResultList();
            return Collections.unmodifiableList(result);
    }

    public final E find(K id) {
            Preconditions.checkNotNull(id);
            final EntityManager em = getEntityManager();
            return em.find(getDomainObjectClass(), id);
    }

    // [...]
}

Now there may be a bean that does not require entity-dependent query capabilities but just a repository of a certain entity type, like (might be a test case):

public class DomainObjectARepositoryTest{

    @Inject
    Repository<DomainObjectA, PersistableUUID> domainObjectARepository;


    @Test
    public void testMitarbeitererstellung() {
        for (DomainObjectA a : domainObjectARepository.getAllEntities()) {
            // do cool stuff
        }       
    }
}

Unfortunatly Weld does not seem to like this kind of generic injection. At deployment time, I get the following error:

state=Create: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Repository<DomainObjectA , PersistableUUID>] with qualifiers [@Default] at injection point [[field] @Inject sompackage.DomainObjectARepositoryTest.domainObjectARepository]

Am I missing something or did they just forgot to implement generic injects? As far as I understand the generic stuff, it is erasured after compiletime anyway - even this worked so fine in guice3 so far.

Kind regards,

avi

edit: found a comment by garvin king that this behavior is in the spec, but not implemented in weld, (staement was in june 2009)

like image 238
dwegener Avatar asked Jun 21 '11 22:06

dwegener


People also ask

What is CDI bean?

A CDI bean is a POJO, plain old java object, that has been automatically instantiated by the CDI container, and is injected into all, and any qualifying injection points in the application. The CDI container initiates the bean discovery process during deployment.

What does the@ inject annotation do?

The annotation @Inject allows Dagger to call the constructor of the injected class to create an instance of a class, twitterApi . However, there are some cases that we may not call a constructor directly. For example: Interfaces.

What is weld CDI?

Weld is the reference implementation of CDI: Contexts and Dependency Injection for the Java EE Platform - a JCP standard for dependency injection and contextual lifecycle management and one of the most important and popular parts of the Java EE.

What is CDI implementation?

Overview. CDI (Contexts and Dependency Injection) is a standard dependency injection framework included in Java EE 6 and higher. It allows us to manage the lifecycle of stateful components via domain-specific lifecycle contexts and inject components (services) into client objects in a type-safe way.


1 Answers

That's rather a long comment than a complete answer to your question, but might point you in the right direction:

I'm following the discussions in seam-dev & weld-dev since quite some time, and do not remember that anything like this ever popped up. So my guess would be that it hasn't been on the agenda ever since Gavin commented about it.

What you can do relatively easy to verify this assumption:

(a) Obtain a reference to the BeanManager and query it for the relevant bean type (or just for Object to be on the save side), of course you will have to remove @Inject in DomainObjectARepositoryTest in order to get the application started.

(b) Register an extension and listen to ProcessBean to what comes up during the deployment. That would be my suggested way to go, you'll find more information here.

With that outcome you should definitely be able to tell if there are any bean types Repository<E, K extends Serializable & Comparable<K>> hanging around :-)

Would be cool if you'd report back here with the results and also considered filing a Jira issue in the negative case.

like image 169
Jan Groth Avatar answered Sep 27 '22 20:09

Jan Groth