CDI Ambiguous Dependencies: Aprenda o que é e como resolver

Veja neste artigo qual a origem do erro “Ambiguous Dependencies” do CDI no Java e como resolvê-lo.

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.

Artigos relacionados