CDI Dependency Injection on explicitly added classes fails

2.4k views Asked by At

Soo i thought it would be simple, but then:

I have some small test. It tests a CDI Dependency injection:

//Imports
@RunWith(Arquillian.class)
public class EditCustomerTest
{
     @Deployment
     public WebArchive createTestArchive()
     {
        return ShrinkWrap
           .create(WebArchive.class, "testcrm.war")
           .addClass(CustomerListProducer.class)
           .addPackage("company.product.controller")
           .addPackage("company.product.model")
           .addPackage("company.product.util")
           .addPackage("company.product.services")
           .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
           .addAsResource("test-ds.xml", "ds.xml")
           .addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml");
      }

      @Inject 
      CustomerEditController customerEditController;

      @Inject
      List<Customer> customers;

      @Test
      public void testInjectionResolution(){
           Assert.assertNotNull(customerEditController);
           //do some stuff, where actually nothing happens
      }
 }

The CustomerEditController injects a private CustomerListController, who itself injects a private CustomerDetailsController.
All the controllers are SessionScoped (I know I shouldn't, but it is a prototype project either way, also i wasn't able to get events running yet.)
Resources is a custom class to provide Logger, EntityManager for Persistence and FacesContext for error messages. All Controllers are in the Package "company.product.controller"

When I now run this test as a Standard JUnit test (Alt+ Shift + X, T) i get the Error message:

org.jboss.arquillian.container.spi.client.container.DeploymentException: Could not deploy to container: {"JBAS014671: Failed services" => {"jboss.deployment.unit.\"testCDI.war\".WeldService" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"testCDI.war\".WeldService: org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [CustomerDetailsController] with qualifiers [@Default] at injection point [[field] @Inject company.product.controller.CustomerListController.customerDetailsController]"}}

I tried to add all the Controllers explicitly in the addClasses call, but unfortunately there were no changes in the result.

EDIT:

here is a skeletalized CustomerListProducer:

@ApplicationScoped
public class CustomerListProducer implements Serializable{

     @Inject
     CustomerService customerServiceBean;

     private static final long serialVersionUID = 1L;
     private List<Customer> customers = new ArrayList<Customer>();
     private Random rnd;
     //some private static final String[] to create DummyData from

     @PostConstruct
     public void init(){
         //check if database is empty, and if then generate DummyData and persist them
     }

     //these call the ServiceBeans implementation to persist the changes
     //the qualifiers are declared in class Events in the package company.product.util
     public void onCustomerAdded(@Observes @Added Customer customer);
     public void onCustomerDeleted(@Observes @Deleted Customer customer);
     public void onCustomerUpdated(@Observes @Updated Customer customer);

     @Named
     @Produces
     public List<Customer> getCustomers();
}

The controllers all work almost the same, the annotations are the same, so i'll just post one of 'em here:

@Named
@SessionScoped
public class  CustomerDetailsController implements Serializable {
     private static final long serialVersionUID = 1L;

     private Customer customer = new Customer();

     // Inject dependent Controllers. there are no events to pass data between views yet
     @Inject
     ContractEditController contractEditController;
     @Inject
     AddContactPersonController addContactPersonController;

     @Inject
     Resources res;

     @Named
     @Produces
     public Customer getCustomer();

     //CRUD-Events for the Customer that are fired, to persist modifications
}

And here are the Services:

@Named
@ApplicationScoped
public interface CustomerService{
    public List<Customer> getAllCustomers();
    public void addCustomer(Customer c);
    public void deleteCustomer(Customer c);
    public void updateCustomer(Customer c);
}

And this is the corresponding implementation:

@Stateless
public class CustomerServiceBean implements CustomerService{
    @Inject
    EntityManager entityManager;

    //implementations for the CustomerService Methods, using the Entity Manager
}

EDIT 2:
After commenting the problematic injected CustomerDetailsController (even though i really need it), I got a new Error message: Could not inject CDI Bean
After moving through the StackTrace a bit, i found that the persistence is not included, so I adjusted the @Deployment Method. unfortunately now i get the error, that my persistenceunit cannot find the datasource.

I double checked the names, and i am positive they are the same.

2

There are 2 answers

0
Vogel612 On BEST ANSWER

After hours of searching i found out, that (as mentioned in the question) the hibernate Datasource used in the CustomerListProducer and the Services Package was configured incorrectly.

Thanks to @rubenlop88 I was able to add the datasource in the correct manner. this resolved the underlying conflict. I still got a load of errors from the missing services Package.

To make creating new Tests easier and to centralize the testarchive-creation I introduced a new abstract class, that does this for all Tests:

@RunWith(Arquillian.class)
public abstract class TestBundle{
     @Deployment
     public static WebArchive createTestArchive() {
         return ShrinkWrap
            .create(WebArchive.class, "testArchive.war")
            .addClass(CustomerListProducer.class)
            .addPackage("company.product.controller")
            .addPackage("company.product.model")
            .addPackage("company.product.util")
            .addPackage("company.product.services")
            .addPackage("company.product.test")
            .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml")
            .addAsWebInfResource("test-ds.xml", "product-ds.xml")
            .addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml");
     }
}

this class gets extended by all tests, so any changes necessary to the package-generation can be made centralized

2
jvalli On

To point out the obvious, CustomerDetailsController has a qualifier annotation on it (@Named), which prevents it from being picked up by a default inject. That's what the Weld warning is about. You'll need to either remove the qualifier from the bean or add it to your injection point.