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.
Saiba mais sobre: CDI
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.
@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.
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.
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.
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;
}
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.