Archive

Archive for 01/04/2017

Injeção de Dependência no Java EE

O CDI (Contexts and Dependency Injection) é um recurso muito útil do Java EE embora a idéia seja bem mais antiga que o framework. Nesse artigo, trataremos do uso da anotação @Inject para permitir que possamos escolher qual das instâncias da interface PessoaService será injetada em um managed bean.

public interface PessoaService {}

Para esse exemplo, a interface PessoaService terá apenas duas implementações:

public class PessoaFisicaService implements PessoaService {}

public class PessoaJuridicaService implements PessoaService {}

Em princípio, vamos deixar o próprio container, que no caso é o JBoss, escolher a implementação que será injetada tomando por base a interface do atributo pessoaService no managed bean abaixo:

@ViewScoped
public class ManagedBean {
   @Inject
   private PessoaService pessoaService;
}

O código acima vai lançar uma exceção, pois ao delegarmos para o container a escolha de uma implementação que atenda à interface, ele não terá como decidir entre as duas implementações disponíveis. Você poderia injetar diretamente a implementação que você necessita, mas uma boa prática de design orientado à objetos e que considero importante quando se trabalha com linguagens fortemente tipadas como o Java é desenvolver “contra” a interface para que seja estabelecido um contrato que várias implementações terão que atender, o que permite que troquemos a implementação utilizada uma vez que a composição foi desacoplada – a classe onde a instância é injetada depende da interface (contrato) e não de uma implementação. Sendo assim, em princípio, vamos apenas qualificar nossas implementações com @Named:

@Named("PessoaFisica")
public class PessoaFisicaService implements PessoaService {}

@Named("PessoaJuridica")
public class PessoaJuridicaService implements PessoaService {}

Em seguida, basta informar o nome ou qualificação da implementação que queremos que o container injete. No caso, garantimos que a implementação injetada é PessoaFisicaService, que é qualificada ou nomeada como PessoaFisica:

@ViewScoped
public class ManagedBean {
   @Inject
   @Named("PessoaFisica")
   private PessoaService pessoaService;
}

O problema dessa estratégia é que ela não é “refactor friendly“, pois se você renomear uma implementação, terá que adequar esse nome em todos os lugares em que ela é utilizada. Não podemos depender de nossa memória, que em geral é bem estragada nos desenvolvedores de software. Também temos que pensar nos pobres coitados que darão manutenção naquele código no futuro. Uma forma elegante de resolver esse problema é criar uma anotação específica para cada implementação e anotá-las com @Qualifier. O @Qualifier indica ao container que ele deverá procurar uma implementação anotada com a anotação definida:

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface PessoaFisica{}

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface PessoaJuridica{}

Vamos aplicar essas anotações em nossas implememntações:

@PessoaFisica
public class PessoaFisicaService implements PessoaService {}

@PessoaJuridica
public class PessoaJuridicaService implements PessoaService {}

Em seguida, vamos indicar que a implementação do contrato que deve ser utilizada é @PessoaFisica:

@ViewScoped
public class ManagedBean {
   @Inject
   @PessoaFisica
   private PessoaService pessoaService;
}

O código parece bem limpo e você pode refatorá-lo pela sua IDE favorita sem que precise lembrar de alterar os lugares em que as implementações são utilizadas. Não é necessário incluir muitos comentários para que um desenvolvedor entenda a intenção de quem codificou e o que está acontecendo ali. O único problema é que para cada implementação você deve criar uma anotação, mas essa é uma decisão de projeto que você terá que tomar. Sempre converse com seus colegas antes de tomar esse tipo de decisão. Às vezes eles podem ter uma ideia melhor que a sua.

Referências

1. [http://sysout.be/2011/06/16/java-ee6-cdi-named-components-and-qualifiers/]

Categorias:Programação