Desenvolvendo uma aplicação Desktop com Weld – Final
Depois da parte 1 e parte 2, chegamos à parte final do nosso exemplo. Disponibilizei o código e vou mostrar mais algumas coisas.
Só uma observação sobre o código: é o mesmo utilizado na apresentação de 14 de Novembro de 2009, quando ainda não tínhamos as mesmas versões de hoje. Mas o exemplo é totalmente funcional. Acabei deixando fixa a versão no pom.xml, então para testar a última versão você vai ter que alterá-lo.
Agora voltando ao post…
Alternatives
Alternatives são a forma de trocarmos um objeto por outro. É parecido com um decorator, mas em vez de incrementar funcionalidades, um alternative serve para substituir um bean.
No nosso exemplo, temos o seguinte objeto como alternativa ao nosso CaixaEletronico:
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Alternative public class CaixaEletronicoSubstituto extends CaixaEletronico{ public void depositar(float valor) { System.out.println("@@@@@@ CaixaEletronicoMock.depositar():" + valor); } public void sacar(float valor) { System.out.println("@@@@@@ CaixaEletronicoMock.sacar():" + valor); } } |
E para habilitar temos que mudar novamente nosso META-INF/beans.xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <interceptors> <class>br.com.jugms.weldse.intercept.ContaInterceptor</class> </interceptors> <decorators> <class>br.com.jugms.weldse.intercept.CaixaDecorator</class> </decorators> <alternatives> <class>br.com.jugms.weldse.model.CaixaEletronicoSubstituto</class> </alternatives> </beans> |
Agora se executarmos nosso código a saída sera:
hello CaixaDecorator.sacar() @@@@@@ CaixaEletronicoMock.sacar():200.0 ContaInterceptor.protege(antes) >> getSaldo ContaInterceptor.protege(depois) >> getSaldo 2000.0 CaixaDecorator.depositar() @@@@@@ CaixaEletronicoMock.depositar():300.0 ContaInterceptor.protege(antes) >> getSaldo ContaInterceptor.protege(depois) >> getSaldo 2000.0
Como podemos ver, nosso decorator decora o alternative e o interceptor continua funcionando normalmente.
Podemos também declarar uma anotação própria e anotá-la como alternative. Mas em vez de tentar explicar, vou mostrar um outro exemplo que servirá como base para este.
Estereótipos próprios
Podemos criar nossos próprios estereótipos, e dessa forma não só reduzir a quantidade de anotações em cima dos nossos beans, mas também deixar a leitura das anotações mais condizentes com nosso linguajar do dia a dia.
Vamos pegar como exemplo o nosso objeto ContaBancaria:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package br.com.jugms.weldse.model; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.inject.Named; import br.com.jugms.weldse.intercept.Seguro; @ApplicationScoped @Seguro public class ContaBancaria { //o código já foi visto antes } |
Já vimos este código e o corpo da classe não tem relação com o que vamos ver agora. Agora o mais importante é observarmos as anotações. Temos duas, mas poderíamos ter mais. Para deixar isso mais limpo e com mais significado no meu negócio, poderia criar um estereótipo próprio como o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package br.com.jugms.weldse.model; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Stereotype; import br.com.jugms.weldse.intercept.Seguro; @ApplicationScoped @Seguro @Stereotype @Target(TYPE) @Retention(RUNTIME) public @interface JavaneirosBean { } |
E depois mudar nosso ContaBancaria deixando ele assim:
1 2 3 4 5 6 7 8 9 10 | package br.com.jugms.weldse.model; import javax.enterprise.event.Observes; import javax.inject.Inject; import javax.inject.Named; @JavaneirosBean public class ContaBancaria { //o código já foi visto antes } |
Com isso o resultado será o mesmo de antes. Nosso objeto ContaBancaria é @Seguro e @ApplicationScoped. Além disso se depois quisermos dizer que nosso @JavaneirosBean é também um @Alternative ou qualquer outro estereótipo pré-existente ou mesmo um outro estereótipo customizado, basta anotar nossa anotação @JavaneirosBean com a anotação desejada.
Pode parecer estranho usarmos anotações de anotações, mas para exemplificar, se a JPA suportasse isso eu poderia ter uma anotação @Entidade que seria uma @Entity (JPA) e ao mesmo tempo @Named (CDI) e assim poder utilizá-la diretamente nas minhas view JSF com uma única anotação.
Conceitos gerais
Eu disse que ao final do exemplo iria entrar mais na parte teórica de como a CDI trata mais extamente a injeção de dependência, seleção de candidatos etc. Porém por questão de organização, vou deixar isso em um post separado.
Boa Tarde Giliard!
Parabéns novamente pelo Blog!
Eu estava tentando criar um Estereótipos próprios, usando o exemplo do @JavaneirosBean, mas diferente, eu uso como @SessionScoped.
Voce sabe como eu posso fazer isso?
Não criou na session, será um bug?
@Léo
Obrigado. Sobre o problema, apesar de parecer bug fui ver na spec se havia alguma restrição e não encontrei nenhuma. Assim que eu conseguir um tempinho pra testar isso eu posto o resultado aqui.