Search code examples
genericsjakarta-eecdi

How are subtypes and generics resolved in CDI/Weld?


I work in Wildfly 8.2.1 Final which runs Weld 2.2.6 Final.

Given

@Entity
public class Fruit{ ... }

@Entity
public class Apple extends Fruit{ ... }


public interface Repository<T extends Identifiable> { ... }


public interface Identifiable { String getId(); }

and

@ApplicationScoped
public class FruitCDIDelegateRepository implements Repository<Fruit>, SearchableRepository<Fruit> { @EJB private FruitRepository repo; }

@Stateless
@LocalBean
@Typed(FruitRepository.class)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class FruitRepository extends PersistenceRepository<Fruit> implements SearchableRepository<Fruit, FruitCriteria> {

The last two Repositories are a construct straight out of the book Continous Enterprise Development in Java by Andrew Lee Rubinger and Aslak Knidsen. It is a workaround to help EJB and CDI work together. In the book they write

This EJB is @Typed to a specific type to avoid being picked up by CDI under Repository due to limitations/error in the CDI EJB interactions. A EJB Beans is always resolved as Repository, which means two EJBs that implements the Repository interface both respond to the InjectionPoint @Inject Repository and making the InjectionPoint ambiguous.

As a WorkAround we wrap the EJB that has Transactional properties in CDI bean that can be used by the Type system. The EJB is to be considered a internal implementation detail. The CDI Type provided by the ConferenceCDIDelegateRepository is the real Repository api.

Other classes should be negligible in this context.

Should I not be able to declare

@Inject
Repository<Apple> repository;

in a class and obtain a FruitRepository (CDIDelegate kind)? A similar case

@Inject
Repository<Fruit> repository;

In the same environment yields the expected object.


Solution

  • You can inject the @Statless Repository without wrapper.

    @RequestScoped
    public class Service {
    
        @Inject
        FruitRepository fruitRepository;
    
        public void saveFruit(Fruit fruit){
            fruitRepository.save(fuit);
        }
    
    }