Search code examples
javajakarta-eejava-ee-7jboss-arquillianweld

Alternative CDI implementation - WELD-001408: Unsatisfied dependencies for type Repository with qualifiers @Default


I have an interface Repository with two implementations, DBRepository and UTRepository. UTRepository is annotated with @Alternative and I'm trying to use it in a JUnit test.

The test class:

@RunWith(Arquillian.class)
public class UserServiceTest {
    @Inject
    private UserService service;

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class)
            .addClasses(Repository.class, UserService.class, UTRepository.class)
            .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Test
    public void addCharacterTest() {
        service.addCharacter(1L, Mockito.mock(GameCharacter.class));
    }
}

The class under test:

public class UserService {
    @Inject
    Repository repository;

    @Transactional
    public void addCharacter(Long userId, GameCharacter character) {
        User user = repository.readById(userId, User.class);
        user.addCharacter(character);
        repository.update(user);
    }
}

My beans.xml file (placed in src/test/webapp/WEB-INF/beans.xml):

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/beans_1_2.xsd"
    bean-discovery-mode="all">
    <alternatives>
        <class>org.package.name.UTRepository</class>
    </alternatives>
</beans>

When I try to run the test, I get the exception:

org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type Repository with qualifiers @Default
    at injection point [BackedAnnotatedField] @Inject org.package.name.services.UserService.repository
    at org.package.name.services.UserService.repository(UserService.java:0)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:359)
    at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:281)
    at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
    at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:155)
    at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:518)
    at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
    at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66)
    at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:63)
    at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:56)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

What is the problem?


Solution

  • The solution you found works well, so just for completness.

    Basically you need to add beans.xml which will enable your alternative. EmptyAsset.INSTANCE will result in empty beans.xml which won't cut it in this case.

    However, in your solution, the beans.xml you placed under src/test/webapp/WEB-INF/beans.xml does nothing. If you want to leverage an existing beans.xml file, you can use:

    • addAsManifestResource(File resource, String target) which adds given File as with name of target
    • addAsManifestResource(Package resourcePackage, String resourceName, String target) which allows you to specify just the package where the file is, then its name and file the name under which you want it in your deployment