cdi do básico ao avançado
Post on 11-May-2015
1.982 Views
Preview:
TRANSCRIPT
CDI, do básico ao avançado
Thursday, September 5, 13
Alberto Souza
• @alberto_souza
• github.com/asouza
Thursday, September 5, 13
Usar ou criar?
@ManagedBeanpublic class ProdutosBean {
@PostConstruct public void carregaProdutos(){ ProdutoDAO produtos = new ProdutoDAO(); produtos.setConnection(ConnectionFactory.createConnection()); this.lista = dao.lista(); }}
Thursday, September 5, 13
Usar!
@ManagedBeanpublic class ProdutosBean { private ProdutoDAO produtos; private ProdutosBean(ProdutoDAO produtos){ this.produtos = produtos; }
@PostConstruct public void carregaProdutos(){ this.lista = dao.lista(); }}
Thursday, September 5, 13
Injeção de Dependências
• JAVAEE 6/7
• CDI 1.0/1.1
• WELD 2
Thursday, September 5, 13
Uso fácil
@ManagedBeanpublic class ProdutosBean { @Inject private ProdutoDAO produtos; @PostConstruct public void carregaProdutos(){ return dao.lista(); }}
Thursday, September 5, 13
Injeção de Dependências
• E como configura?
Thursday, September 5, 13
Injeção de Dependências
• Não precisa mais
Thursday, September 5, 13
Outro exemplo
class ProdutoDAO{ @Inject private EntityManager em; public List<Produto> lista(){ return em.createQuery("select p from Produto p"); }}
Thursday, September 5, 13
Criação de EntityManager
EntityManagerFactory emf = Persistence. createEntityManagerFactory("loja"); EntityManager em = emf.createEntityManager();
Thursday, September 5, 13
Tem que ensinar
class EntityManagerProducer{private EntityManagerFactory emf = Persistence.createEntityManagerFactory("loja"); @Produces public EntityManager create(){ return factory.createEntityManager(); }}
Thursday, September 5, 13
Escopo?
class EntityManagerProducer{private EntityManagerFactory emf = Persistence.createEntityManagerFactory("loja"); @Produces @RequestScoped public EntityManager create(){ return factory.createEntityManager(); }}
Thursday, September 5, 13
Escopo?
class EntityManagerProducer{private EntityManagerFactory emf = Persistence.createEntityManagerFactory("loja"); //outro método aqui... public void close(@Disposes EntityManager entityManager){ entityManager.close(); }}
Thursday, September 5, 13
Qual é o remetente?
public class FinalizadorDeCompra{ private String remetente; public void envia(){ mailer.send(remente,...); }}
Thursday, September 5, 13
Trocar a injeção de String?
public class FinalizadorDeCompra{ @Inject private String remetente; public void envia(){ mailer.send(remente,...); }}
Thursday, September 5, 13
Só quero para determinada String
public class FinalizadorDeCompra{ @Inject @RemetenteCompra private String remetente; public void envia(){ mailer.send(remente,...); }}
Thursday, September 5, 13
Qualifier
//outras annotations chatas@Qualifier@interface RemetenteCompra{}
Thursday, September 5, 13
Qualifier@ApplicationScoped
class RemetentesProducer { @Produces @RemetenteCompra public String remetenteCompra(){ return properties.getProperty("remetente.compra"); } @Produces @RemetenteNewsletter public String remetenteNewsletter(){ return properties.getProperty("remetente.newsletter"); }}
Thursday, September 5, 13
Indo além
• VRaptor CDI e integração com o Container
Thursday, September 5, 13
Injeção de coisas do container
• Quero usar um EJB, EntityManager...
Thursday, September 5, 13
Injeção de coisas do container
@Componentpublic class ProdutoDAO { @Inject private final EntityManager entityManager;
public void salva(Produto produto) { entityManager.persist(produto); }
Thursday, September 5, 13
Injeção de coisas do container
@Stateless @Componentpublic class ProdutoDAO { @Inject private final EntityManager entityManager;
public void salva(Produto produto) { entityManager.persist(produto); }
Thursday, September 5, 13
Injeção de coisas do container
@Resourcepublic class ProdutosController {
//@EJB @Inject private ProdutoDAO produtoDAO; ...}
Thursday, September 5, 13
EJB?
• Por sinal o DAO é um EJB porque?
Thursday, September 5, 13
EJB?
@Componentpublic class ProdutoDAO { @Inject private final EntityManager entityManager;
@Transactional public void salva(Produto produto) { entityManager.persist(produto); }
Thursday, September 5, 13
Exemplo de uso
• Coloco no interceptor e tá tudo certo!
Thursday, September 5, 13
Componente padrão
@RequestScopedpublic class DefaultPathResolver implements PathResolver { public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat();
String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/jsp/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return getPrefix() + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); }
Thursday, September 5, 13
Componente customizado
class CustomPathResolver implements PathResolver{ public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat();
String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/resources/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return "WEB-INF/resources" + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); }}
Thursday, September 5, 13
Alternative
@Alternativeclass CustomPathResolver implements PathResolver{ public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat();
String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/jsp/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return "WEB-INF/resources" + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); }}
Thursday, September 5, 13
Registra no beans.xml
<?xml version="1.0" encoding="UTF-8"?><beans> <alternatives> <class>br.com.caelum.vraptor.view.CustomPathResolver</class> </alternatives>
</beans>
Thursday, September 5, 13
ilhazinha
• Alternative habilitado só no bean archive
Thursday, September 5, 13
ilhazinha
• VRaptor não enxergava
Thursday, September 5, 13
Prioridade
@Alternative@Priority(Interceptor.Priority.APPLICATION)
class CustomPathResolver implements PathResolver{ public String pathFor(ResourceMethod method) { String format = resolver.getAcceptFormat();
String suffix = ""; if (format != null && !format.equals("html")) { suffix = "." + format; } //WEB-INF/jsp/controller/metodo.jsp String name = method.getResource().getType().getSimpleName(); String folderName = extractControllerFromName(name); return "WEB-INF/resources" + folderName + "/" + method.getMethod().getName() + suffix + "."+getExtension(); }}
Thursday, September 5, 13
Prioridade
• Podemos sempre sobreescrever!
Thursday, September 5, 13
Servidor já injeta Request
• Request do VRaptor é modificado
Thursday, September 5, 13
Aproveita o que já existe
public class VRaptorRequest implements MutableRequest,HttpServletRequest {
private final Hashtable<String, String[]> extraParameters = new Hashtable<String, String[]>();
//qual que ele vai injetar? @Inject private HttpServletRequest request;}
Thursday, September 5, 13
Aproveitamos o existente
@Decoratorpublic class VRaptorRequest implements MutableRequest,HttpServletRequest { @Delegate private HttpServletRequest delegate;
@Override public String getParameter(String name) { if (extraParameters.containsKey(name)) { String[] values = extraParameters.get(name); if (values.length == 1) { return values[0]; } else { return Arrays.toString(values); } } return delegate.getParameter(name); }
Thursday, September 5, 13
Configuramos
<decorators> <class>br.com.caelum.vraptor.http.VRaptorRequest</class> </decorators>
Thursday, September 5, 13
Priority
• Pode usar Priority também!
Thursday, September 5, 13
Injetar Requestspublic class DefaultFormatResolver implements FormatResolver {
private final HttpServletRequest request; private final AcceptHeaderToFormat acceptHeaderToFormat;
@Inject public DefaultFormatResolver(HttpServletRequest request, AcceptHeaderToFormat acceptHeaderToFormat) { this.request = request; this.acceptHeaderToFormat = acceptHeaderToFormat; } public String getAcceptFormat() { String format = request.getParameter("_format"); if (format != null) { return format; }
format = request.getHeader("Accept");
Thursday, September 5, 13
Trocar o request o tempo todo
@Inject private CDIHttpServletRequestFactory requestFactory; @Inject private CDIHttpSessionFactory sessionFactory; public <T> T provideForRequest(RequestInfo request) { //configurando produtores requestFactory.setRequest(request); sessionFactory.setSession(request); return execution.insideRequest(container); }
Thursday, September 5, 13
Notifica o povo
@Inject private Event<HttpServletRequest> eventosDeRequest; public <T> T provideForRequest(RequestInfo requestInfo, Execution<T> execution) { //configurando produtores eventosDeRequest.fire(requestInfo.getRequest()); return execution.insideRequest(container); }
Thursday, September 5, 13
Quero ser notificado
public class CDIHttpServletRequestFactory implements ComponentFactory<HttpServletRequest>{
private HttpServletRequest request;
public void handle(@Observes HttpServletRequest request){ this.request = request; } public HttpServletRequest getInstance(){ return request; }
}
Thursday, September 5, 13
VRaptor já tem @RequestScoped
public @interface RequestScoped {}
Thursday, September 5, 13
Eu sou você!
@Stereotype@javax.enterprise.context.RequestScoped@Namedpublic @interface RequestScoped {}
Thursday, September 5, 13
VRaptor não usa @Inject
@Resourcepublic class ProdutoDAO {
private final EntityManager entityManager;
public CDIResourceComponent(EntityManager entityManager) { this.entityManager = entityManager; }
}
Thursday, September 5, 13
Oxi, sem @Inject?
• Cadê o @Inject?
Thursday, September 5, 13
Pedimos a ele para colocar
public class AddInjectToConstructorExtension implements Extension{
public void processAnnotatedType(@Observes final ProcessAnnotatedType pat) { AnnotatedTypeBuilder builder = new AnnotatedTypeBuilder(); builder.readFromType(pat.getAnnotatedType()); if (hasArgsConstructorAndNoInjection) { Constructor constructor = constructors.get(0); //pulo do gato builder.addToConstructor(constructor,new AnnotationLiteral<Inject>() {}); //trocando a configuração original pat.setAnnotatedType(builder.create()); } }
Thursday, September 5, 13
VRaptor já tem Factories
@Componentpublic class CDIComponent implements ComponentFactory {
private final MyRequestComponent component; public CDIComponent(MyRequestComponent component) { this.component = component; }
public ComponentToBeProduced getInstance() { return new ComponentToBeProduced(); }}
Thursday, September 5, 13
Oxi, e o @Produces?
• E o @Produces?
Thursday, September 5, 13
@Produces em cima do método
public class ComponentFactoryExtension implements Extension{
public void addProduces(@Observes ProcessAnnotatedType pat) { builder.readFromType(pat.getAnnotatedType()); if (ComponentFactory.class.isAssignableFrom(javaClass)) { builder.addToMethod(getInstance,new ProducesAnnotion()); } }}
class ProducesAnnotion extends AnnotationLiteral<Produces>{}
Thursday, September 5, 13
Configura extensão
• META-INF/services/javax.enterprise.inject.spi.Extension
Thursday, September 5, 13
Configura extensão
br.com.caelum.vraptor.ioc.cdi.extensions.AddInjectToConstructorExtension
br.com.caelum.vraptor.ioc.cdi.extensions.ComponentFactoryExtension
Thursday, September 5, 13
E para testar?
• E para testar?
Thursday, September 5, 13
Arquillian
@RunWith(Arquillian.class)public class CDIProviderRegisteringComponentsTest { @Deployment public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addClass(DefaultPathResolver.class) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml"); }
Thursday, September 5, 13
Arquillian
public static JavaArchive createDeployment() { return ShrinkWrap.create(JavaArchive.class) .addPackage("com.thoughtworks.xstream") }
Thursday, September 5, 13
Problemas
• Falta de controle sobre o container
Thursday, September 5, 13
DeltaSpike
cdiContainer = CdiContainerLoader.getCdiContainer(); cdiContainer.boot();
Thursday, September 5, 13
Controle do escopo
public void start(Class<? extends Annotation> scope) { cdiContainer.getContextControl().startContext(scope); }
Thursday, September 5, 13
Controle do escopo
start(RequestScoped.class); start(SessionScoped.class); //logica stop(SessionScoped.class); stop(RequestScoped.class);
Thursday, September 5, 13
Últimos detalhes
• Funcionalidade com muitos passos
Thursday, September 5, 13
Funcionalidade com vários passos
@Controllerpublic class PagamentoController implements Serializable{
private InformacoesDoComprador info = new InformacoesDoComprador(); @Inject public PagamentoController(Result result) { super(); this.result = result; }
@Post("compra/endereco") public void associaEndereco(String endereco){ info.setEnderecoDeEntrega(endereco); }
Thursday, September 5, 13
Funcionalidade com vários passos
@Controllerpublic class PagamentoController implements Serializable{
//resto que não coube e eu não soube ajeitar. @Post("compra/endereco") public void associaEndereco(String endereco){ info.setEnderecoDeEntrega(endereco); }
@Post("compra/cartao") public void associaCartao(String numero){ //como mantém as informações do comprador? info.setNumeroDoCartao(numero); result.include("dadosComprador",info); }}
Thursday, September 5, 13
Como implementar?
• 2 Maneiras?
Thursday, September 5, 13
Exemplo de implementação
• Stateless?
Thursday, September 5, 13
Outro exemplo
• Stateful?
Thursday, September 5, 13
Meio termo
• Mangue moderado!
Thursday, September 5, 13
Conversation
@Controller @ConversationScopedpublic class PagamentoController implements Serializable{ @Inject private Conversation conversation; @Post("compra/endereco") public void associaEndereco(String endereco){ conversation.begin(); info.setEnderecoDeEntrega(endereco); result.redirectTo("/compra/cartao?cid="+conversation.getId()); }
Thursday, September 5, 13
Conversation
@Controller @ConversationScopedpublic class PagamentoController implements Serializable{ @Inject private Conversation conversation; @Post("compra/cartao") public void associaCartao(String numero){ info.setNumeroDoCartao(numero); //grava e vamo aí.. conversation.end(); result.include("dadosComprador",info); }
Thursday, September 5, 13
Conversation
@Controller @ConversationScopedpublic class PagamentoController implements Serializable{ @Inject public PagamentoController(Result result) { super(); this.result = result; }
Thursday, September 5, 13
E esse result?
• O Result tem que ser passivavel :(
Thursday, September 5, 13
Não mais :)
@Controller @ConversationScopedpublic class PagamentoController implements Serializable{ @Inject public PagamentoController(@TransientReference Result result) { super(); this.result = result; }
Thursday, September 5, 13
Valeu! @alberto_souza
github.com/asouza
Thursday, September 5, 13
top related