Motivação

Com o CDI (Contexts and Dependency Injection), e suas anotações, podemos delegar ao container a tarefa de injetar dependências entre as classes da aplicação. O uso inadequado desse recurso, no entanto, pode nos levar a erros como o de “Ambiguous Dependencies”, que ocorre quando o container não sabe qual dependência injetar. Nesse artigo veremos as causas desse erro e comosolucioná-lo.

Origem do erro Ambiguous Dependencies

O CDI é responsável por gerenciar as dependências entre classes da aplicação, desde que elas estejam sinalizadas por meio de anotações. Um bom exemplo de anotação do CDI é a @Named, que informa algo como: “Gerencie essa dependência para mim”.

Quando essa anotação é encontrada sem o parâmetro “value”, o CDI cria em seu repositório de dependências a referência para esse objeto através do nome da classe usando a técnica lowerCamelCase. Assim, se sua classe tem o nome “PrinterService”, como no código abaixo, o CDI irá criar uma referência a ela com o nome “printerService”:


        import javax.inject.Named;
        import java.io.Serializable;
        @Named
        public class PrinterService implements Serializable{}
        

A partir desse trecho de código o CDI já conseguirá gerenciar a criação de objetos “printerService”. Se desejarmos escolher um nome diferente, podemos declarar o atributo “value”. Por exemplo, podemos chamar de “printer” a nossa classe PrinterService, da seguinte forma:


        import javax.inject.Named;
        import java.io.Serializable;
        @Named(value=”printer”)
        public class PrinterService implements Serializable{}
        

Compreendendo o funcionamento dessa anotação, podemos entender o erro “Ambiguous Dependencies”, que ocorre quando duas classes diferentes são registradas com o mesmo nome no repositório de dependências do CDI.

Existem pelo menos duas formas desse erro ocorrer e veremos a seguir como evitá-las.

Classes diferentes com mesmo valor em @Named

O caso mais comum ocorre quando temos classes distintas usando o mesmo valor (value) na anotação @Named, como podemos observar na Listagem 1.

Listagem 1. Classes com mesmo valor na anotação @Named

        @Named(value = "printer")
        public class PrinterService implements Serializable {
        }
        ...
        @Named(value = "printer")
        public class FaxService implements Serializable {
        }
        

Nesse caso, não conseguiremos nem iniciar o servidor de aplicação, e o erro deve ser parecido com o mostrado na Listagem 2.

Listagem 2. Erro causado pela classe PrinterService e FaxService

        Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001414: Bean name is ambiguous. Name printer
        resolves to beans:
        - Managed Bean [class br.com.devmedia.service.PrinterService] with qualifiers [@Default @Named @Any],
        - Managed Bean [class br.com.devmedia.service.FaxService] with qualifiers [@Default @Named @Any]
        

De forma resumida, esse erro quer dizer: “O CDI não sabe qual das classes injetar no seu repositório de dependências, pois ambas têm o mesmo nome para ele”. A solução para esse erro é muito simples: trocar o “value” de uma das classes na anotação @Named. Por exemplo, podemos mudar o valor da classe FaxService para “fax”: @Named (value = "fax").

Classe gerenciável herdando de outra classe gerenciável pelo CDI

Outra situação em que ocorre o erro Ambiguous Dependencies é quando você possui uma classe que já é gerenciável pelo CDI, a faz herdar de outra classe que também é gerenciável e resolve injetar a classe pai (super classe) em algum bean.

Para demonstrar esse caso, vamos utilizar a classe PrinterService, vista anteriormente, e mudar FaxService para herdar da primeira, como mostra a Listagem 3.

Listagem 3. Classe FaxService herdando de PrinterService

        package br.com.devmedia.service;
        import javax.inject.Named;
        @Named(value = "fax")
        public class FaxService extends PrinterService {
        }
        

Feito isso, se injetarmos a super classe PrinterService dentro de uma classe chamada UtilService, por exemplo, como mostra a Listagem 4, ao iniciar o servidor de aplicação, novamente receberemos o erro “Ambiguous Dependencies”, como mostra a Listagem 5.

Listagem 4. Injetando a classe PrinterService

        package br.com.devmedia.service;
        import javax.inject.Inject;
        import javax.inject.Named;
        import java.io.Serializable;
        @Named
        public class UtilService implements Serializable {
        @Inject
        private PrinterService printerService;
        }
        
Listagem 5. Erro Ambiguous Dependencies causado por herança

        Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type
        PrinterService with qualifiers @Default
        at injection point [BackedAnnotatedField] @Inject private br.com.devmedia.service.UtilService.printerService
        at br.com.devmedia.service.UtilService.printerService(UtilService.java:0)
        Possible dependencies:
        - Managed Bean [class br.com.devmedia.service.PrinterService] with qualifiers [@Default @Named @Any],
        - Managed Bean [class br.com.devmedia.service.FaxService] with qualifiers [@Default @Named @Any]
        

Assim como no caso anterior, o CDI não quem injetar (neste caso, se PrinterService ou FaxService). Para resolver isso, na classe UtilService, devemos utilizar a anotação @Named com o atributo value especificando o bean que deve ser injetado, como mostra o trecho abaixo:


        @Inject
        @Named(value = "printer")
        private PrinterService printerService;
        

Com isso, resolvemos as duas causas mais recorrentes que levam ao erro “Ambiguous Dependencies”. Em ambos os casos precisamos especificar qual bean o CDI deve injetar e para isso utilizamos o atributo value da anotação @Named.