@Stereotype // we define a stereotype
@Retention(RUNTIME) // resolvable at runtime
@Target(TYPE) // this annotation is a class level one
@Alternative // it replace @Alternative
public @interface Mock {}
Alternativas e Estereótipos do CDI
Introdução
CDI é uma revolução para o mundo Java EE. Está especificação é a melhor para evitar acoplamento entre classes.
Este exemplo simplesmente pretende substituir ligações em tempo de execução para simplificar o trabalho de mocking.
Aqui usamos dois tipos de mocks:
1) um mock com nenhuma implementação no classloader
2) um mock com uma implementação no classloader
A resposta mock do CDI é chamada de alternative.
Anotando com o @Alternative
uma classe significa que será usado como implementação se não houver outra implementação
ou se for forçado (através do META-INF/beans.xml
).
Explicação do Código
Código Principal
Nós usamos um EJB Journey
para modelar um journey onde o vehicle e society pode mudar. Aqui um EJB é usado
por que isto simplifica o teste. Uma journey envolve a informação de vehicle e society .
Nós definimos duas interfaces para injetar no EJB Journey
:` Vehicle` e Society
.
Finalmente, adicionamos uma implementação para a interface Society
:` LowCostCompanie`.
Se paramos aqui, o objeto Journey
não poderá ser criado porque não há uma implementação Vehicle
acessível.
se tivermos uma implementação de Vehicle , a Society injetada deverá ser LowCostCompanie .
|
Código de Teste
O objetivo aqui é para testar o nosso EJB Journey
. Portanto, temos que fornecer uma implementação de Vehicle
:` SuperCar`.
Queremos forçar a interface Society
a ser a implementação do AirOpenEJB
para o nosso teste.
Uma solução poderia ser simplesmente adicionar a anotação @ Alternative
no` AirOpenEJB` e ativá-la através do
arquivo META-INF / beans.xml
.
Aqui queremos escrever um código mais explícito. Então, queremos substituir a anotação @Alternative
por uma` @Mock
.
Então nós definimos uma anotação @Mock
para classes, resolvíveis em tempo de execução como um estereótipo (` @Stereotype`)
que substitui o @Alternative
.
Aqui a anotação:
você pode adicionar mais anotações CDI após @Alternative e obterá o comportamento esperado (o escopo para a instância).
|
Então agora temos a nossa anotação @ Mock
, que é um estereótipo capaz de substituir a anotação` @ Alternative` quando
adicionado às nossas mocks.
Se você executar isso agora, nós receberemos está exceção:
jakarta.enterprise.inject.UnsatisfiedResolutionException: Api type [org.superbiz.cdi.stereotype.Vehicle] is not found with the qualifiers
Qualifiers: [@jakarta.enterprise.inject.Default()]
for injection into Field Injection Point, field name : vehicle,
Bean Owner : [Journey, Name:null, WebBeans Type:ENTERPRISE, API Types:[java.lang.Object,org.superbiz.cdi.stereotype.Journey],
Qualifiers:[jakarta.enterprise.inject.Any,jakarta.enterprise.inject.Default]]
Isso significa que o estereótipo não está ativado. Para fazer isso basta adicioná-lo ao seu META-INF / beans.xml
:
<alternatives> <stereotype>org.superbiz.cdi.stereotype.Mock</stereotype> </alternatives>
se você não especificar AirOpenEJB como` @ Alternative` (feito através de nossa anotação mock) você receberá está exceção:
|
Caused by: jakarta.enterprise.inject.AmbiguousResolutionException:
There is more than one api type with : org.superbiz.cdi.stereotype.Society with qualifiers :
Qualifiers: [@jakarta.enterprise.inject.Default()] for injection into Field Injection Point, field name : society,
Bean Owner : [Journey, Name:null, WebBeans Type:ENTERPRISE,
API Types:[org.superbiz.cdi.stereotype.Journey,java.lang.Object],
Qualifiers:[jakarta.enterprise.inject.Any,jakarta.enterprise.inject.Default]]
found beans:
AirOpenEJB, Name:null, WebBeans Type:MANAGED,
API Types:[org.superbiz.cdi.stereotype.Society,org.superbiz.cdi.stereotype.AirOpenEJB,java.lang.Object],
Qualifiers:[jakarta.enterprise.inject.Any,jakarta.enterprise.inject.Default]
LowCostCompanie, Name:null, WebBeans Type:MANAGED,
API Types:[org.superbiz.cdi.stereotype.Society,org.superbiz.cdi.stereotype.LowCostCompanie,java.lang.Object],
Qualifiers:[jakarta.enterprise.inject.Any,jakarta.enterprise.inject.Default]
o que significa simplesmente que duas implementações estão disponíveis para o mesmo ponto de injeção (Journey.society
).
Conclusão
Com o CDI é realmente fácil definir anotações com um forte significado. Você pode definir anotações de negócios ou simplesmente anotações técnicas para simplificar seu código (como fizemos com a anotação mock).
se você usou qualificadores para injetar objetos Society você poderia ter colocado todos esses qualificadores em
a classe mock ou definiu uma anotação @SocietyMock para poder injetar a mesma implementação para
todos os qualificadores em seus testes.
|
Saída
Running org.superbiz.cdi.stereotype.StereotypeTest Apache OpenEJB 7.0.0-SNAPSHOT build: 20111030-07:54 http://tomee.apache.org/ INFO - openejb.home = /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes INFO - openejb.base = /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes INFO - Using 'jakarta.ejb.embeddable.EJBContainer=true' INFO - Configuring Service(id=Default Security Service, type=SecurityService, provider-id=Default Security Service) INFO - Configuring Service(id=Default Transaction Manager, type=TransactionManager, provider-id=Default Transaction Manager) INFO - Found EjbModule in classpath: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes/target/test-classes INFO - Found EjbModule in classpath: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes/target/classes INFO - Beginning load: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes/target/test-classes INFO - Beginning load: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes/target/classes INFO - Configuring enterprise application: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes INFO - Configuring Service(id=Default Managed Container, type=Container, provider-id=Default Managed Container) INFO - Auto-creating a container for bean cdi-alternative-and-stereotypes_test.Comp: Container(type=MANAGED, id=Default Managed Container) INFO - Configuring Service(id=Default Singleton Container, type=Container, provider-id=Default Singleton Container) INFO - Auto-creating a container for bean Journey: Container(type=SINGLETON, id=Default Singleton Container) INFO - Enterprise application "/opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes" loaded. INFO - Assembling app: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes INFO - Jndi(name="java:global/cdi-alternative-and-stereotypes/cdi-alternative-and-stereotypes_test.Comp!org.apache.openejb.BeanContext$Comp") INFO - Jndi(name="java:global/cdi-alternative-and-stereotypes/cdi-alternative-and-stereotypes_test.Comp") INFO - Jndi(name="java:global/cdi-alternative-and-stereotypes/cdi-alternative-and-stereotypes.Comp!org.apache.openejb.BeanContext$Comp") INFO - Jndi(name="java:global/cdi-alternative-and-stereotypes/cdi-alternative-and-stereotypes.Comp") INFO - Jndi(name="java:global/cdi-alternative-and-stereotypes/Journey!org.superbiz.cdi.stereotype.Journey") INFO - Jndi(name="java:global/cdi-alternative-and-stereotypes/Journey") INFO - Jndi(name="java:global/EjbModule162291475/org.superbiz.cdi.stereotype.StereotypeTest!org.superbiz.cdi.stereotype.StereotypeTest") INFO - Jndi(name="java:global/EjbModule162291475/org.superbiz.cdi.stereotype.StereotypeTest") INFO - Created Ejb(deployment-id=cdi-alternative-and-stereotypes_test.Comp, ejb-name=cdi-alternative-and-stereotypes_test.Comp, container=Default Managed Container) INFO - Created Ejb(deployment-id=cdi-alternative-and-stereotypes.Comp, ejb-name=cdi-alternative-and-stereotypes.Comp, container=Default Managed Container) INFO - Created Ejb(deployment-id=org.superbiz.cdi.stereotype.StereotypeTest, ejb-name=org.superbiz.cdi.stereotype.StereotypeTest, container=Default Managed Container) INFO - Created Ejb(deployment-id=Journey, ejb-name=Journey, container=Default Singleton Container) INFO - Started Ejb(deployment-id=cdi-alternative-and-stereotypes_test.Comp, ejb-name=cdi-alternative-and-stereotypes_test.Comp, container=Default Managed Container) INFO - Started Ejb(deployment-id=cdi-alternative-and-stereotypes.Comp, ejb-name=cdi-alternative-and-stereotypes.Comp, container=Default Managed Container) INFO - Started Ejb(deployment-id=org.superbiz.cdi.stereotype.StereotypeTest, ejb-name=org.superbiz.cdi.stereotype.StereotypeTest, container=Default Managed Container) INFO - Started Ejb(deployment-id=Journey, ejb-name=Journey, container=Default Singleton Container) INFO - Deployed Application(path=/opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes) INFO - Undeploying app: /opt/dev/openejb/openejb-trunk/examples/cdi-alternative-and-stereotypes