Qualificadores no CDI
Tags: java, jarkataee, cdi
Published: 2022-08-28 12:12:00

### INTRODUÇÃO

Vamos começar falando um pouco sobre os qualificadores da CDI, como muitos devem saber a CDI a uma especificação JAVA que deu muito poder e extensividade a Linguagem, não vou entrar no mérito de falar sobre a especificação, apenas sobre a funcionalidade de Qualificadores.

### QUALIFICADORES OU QUALIFIER

Imagine que temos uma interface com várias implementações, uma das utilidades dos qualifier é informarmos qual implementação vamos usar, se liga no exemplo.

```java
public interface PaymentMethod {
    public void pay();
}
```

ai temos 2 implementações para a interface PaymentMethod

```java
public class CreditCard implements PaymentMethod {
    @Override
    public void pay() {
        System.out.println("payment by cred card");
    }
}
```

```java
public class Cash implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by CASH");
    }
}
```

Se em nossa classe cliente apenas injetarmos a interface PaymentMethod a CDI lançará uma exceção de ambiguidade, informando que não sabe qual implementação irá injetar, tranquilo até ai ?

```java
public class Checkout {

    @Inject
    private PaymentMethod payment;

    public void checkout() {
        payment.pay();
    }

}
```

Da uma olha no error que vai aparecer no seu console.

```bash
WELD-001475: The following beans match by type, but none have matching qualifiers:
- Managed Bean [class br.com.cassunde.cdi.qualifier.Cash] with qualifiers [@Any @Payment],
- Managed Bean [class br.com.cassunde.cdi.qualifier.CreditCard] with qualifiers [@Any @Payment]
```

Para resolvermos isso teremos que criar um qualifier CDI, a sua criação e bem simples, basta criar uma anotação java padrão com uma pequena diferença, essa nossa anotação terá um @Qualifier, como o próprio nome já diz, será o responsável por indicar que essa nossa anotação e um qualifier. ficara mais ou menos assim.

```java
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
@Qualifier
public @interface PaymentCreditCard {}
```

vamos fazer um exemplo ruim e depois vamos ver uma forma melhor de resolver esse problema usando qualifier, em nosso exemplo a interface PaymentMethod tem 2 implementações a CreditCard e a Cash, em nossa abordagem ruim faremos uma outra anotação para qualificarmos a segunda implementação então vamos lá: Qualifier para Implementação Cash:

```java
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
@Qualifier
public @interface PaymentCash {}
```

para usarmos esses qualifier ficara mais ou menos assim: - Implementação CreditCard

```java
@PaymentCreditCard
public class CreditCard implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by creditcard");
    }
}
```

Classe cliente

```java
public class Checkout {

    @Inject
    @PaymentCreditCard
    private PaymentMethod payment;

    public void checkout() {
        System.out.println("Starting checkout");
        payment.pay();
    }
}
```

Dessa forma não fica muito legal, caso apareça uma nova implementação teremos que criar uma nova anotação e por ai vai... vamos agora melhorar essa abordagem, vamos inserir uma enum em nosso qualifier.

Vou criar essa enum e um terceiro qualifier chamado Payment

```java
public enum PaymentType {
    CREDIT,
    CASH,
    DEBIT
}
```

Nosso terceiro qualifier ficaria assim:

```java
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD, PARAMETER })
@Qualifier
public @interface Payment {
    PaymentType type();
}
```

agora podemos substituir os primeiros qualifier que criamos por esse último, ficando mais ou menos assim:

Implementação CreditCard

```java
@Payment(type=PaymentType.CREDIT)
public class CreditCard implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by cred card");
    }
}
```

Método Cliente


```java
public class Checkout { 

    @Inject
    @Payment(type=PaymentType.CREDIT)
    private PaymentMethod payment; 

    public void checkout() {
        System.out.println("Starting checkout");
        payment.pay();
    }
}
```

Implementação Cash

```java
@Payment(type=PaymentType.CASH)
public class Cash implements PaymentMethod {

    @Override
    public void pay() {
        System.out.println("payment by cred card");
    }
}
```

Método Cliente


```java
public class Checkout { 

    @Inject
    @Payment(type=PaymentType.CASH)
    private PaymentMethod payment; 

    public void checkout() {
        System.out.println("Starting checkout");
        payment.pay();
    }
}
```




Observem que agora estamos usando apenas uma única anotação e estamos "tipando" nosso qualifier, dessa forma temos mais liberdade para evoluir o código.

Por enquanto e só isso.