Estou estudando sobre CDI
e desenvolvendo um mini aplicação para tal propósito e utilizando:
- GlassFish 4.1.1
- Netbeans 8.1
- JSF 2.2
- Primefaces 5.0
Eu basicamente travei na minha primeira tentativa de usar CDI e não consigo solucionar o seguinte erro:
Grave: Exception while loading the app : CDI deployment failure:WELD-001408: Unsatisfied dependencies for type EntityManager with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private br.com.ddavel.progro.dao.UsuarioDAO.em
at br.com.ddavel.progro.dao.UsuarioDAO.em(UsuarioDAO.java:0)
Minhas classe que tem anotações do CDI
são:
package br.com.ddavel.progro.dao;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Disposes;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public class FabricaDeConexoes{
private static EntityManagerFactory emf;
@Produces
@RequestScoped
public EntityManager criaEntityManager(){
if (emf == null){
emf = Persistence.createEntityManagerFactory("ProgroPU");
}
return emf.createEntityManager();
}
public void finaliza(@Disposes EntityManager em) {
em.close();
}
}
e essa
package br.com.ddavel.progro.dao;
import br.com.ddavel.progro.entidades.Usuario;
import java.io.Serializable;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
public class UsuarioDAO implements Serializable{
@Inject
private EntityManager em;
public List<Usuario> getLista(){
TypedQuery<Usuario> query = em.createNamedQuery("Usuario.findAll",
Usuario.class);
return query.getResultList();
}
public Usuario merge(Usuario usuario){
em.getTransaction().begin();
Usuario novo = em.merge(usuario);
em.getTransaction().commit();
return novo;
}
public void delete(Usuario usuario){
em.getTransaction().begin();
em.remove(em.merge(usuario));
em.getTransaction().commit();
}
}
Como resolver esse problema?
Voce está em um servidor de aplicação ?
No título do tópico está escrito que ele usa CDI com JSF, Primefaces e roda no Glassfish, que é um application server…
Eu não gosto mesmo desta abordagem.
É muito mais simples criar assim (desde que você possua o persistence.xml corretamente configurado no projeto):
@PersistenceContext
private EntityManager em;
Mas, se você está seguindo um tutorial/livro/apostila/vídeo aula, deve tentar rever os passos e identificar onde errou.
O erro Unsatisfied dependencies for type EntityManager with qualifiers @Default
indica que não foi encontrado nenhuma classe que corresponda ao que o mapeamento exige, logo, o CDI não sabe o que fazer com esse objeto.
Coloque a anotação @ApplicationScoped no seu producer, afinal queremos um produtor por aplicação certo ? Em seguida para voce precisa de alguem para gerenciar suas transações no dao, coloque uma anotação @Stateless que automaticamente o container irá gerenciar para você, e esse DAO não terá estado, assim será feito um pool de objetos nele, sendo que o size é definido no xml do servidor.
Em objetos que não são @Stateless e voce precise fazer um injeção de dependencia, voce deve anotala com @Named além de implementar o Serializable
Vou lhe mandar meu Producer de entity manager da minha aplicação, para voce ter como base.
@ApplicationScoped
public class EntityManagerProducer {
@PersistenceUnit(unitName ="UNITNAME")
private EntityManagerFactory managerFactory;
@Produces
@RequestScoped
public EntityManager createEntityManager() {
return managerFactory.createEntityManager();
}
public void closeEntityManager(@Disposes EntityManager entityManager) {
entityManager.close();
}
}
No caso voce está utilizando JTA ?
Se voce não quer um producer voce pode fazer exatamente oque o Luis sugeriu.
@matrella2
@Luis_Augusto_Santos
Ambos os exemplos deram certo aqui, e isso me causou na verdade mais dúvidas…
Até agora estou limitado ao conceito de que a anotação @inject substitui um “new Objeto();”, e de que a anotação @Produces sinaliza o método que “força” a produção do objeto com a anotação @Inject; e que a grande vantagem disso é controlar o ciclo de vida dos objetos na memória do servidor;
1 - A anotação @PersistenceContext tem o mesmo efeito que?:
@Inject
private EntityManager em;
@Produces
public EntityManager getEntityManager(){
return meuEntityManagerFactory.createEntityManager();
}
2 - Anotar a classe que produz o EntityManagerFactory com @ApplicationScoped, não causa o mesmo efeito (em termos de ciclo de vida) que (declarar variavel estatica, que teoricamente dura o tempo da aplicação)?:
private static EntityManagerFactory emf;
Entao @Satangozo , quando se usa o servidor de aplicações, tais como Glassfish, wildfly, jetty. Eles controlam suas transações do banco de dados. O que torna desnecessario e até não recomendado voce fazer isso quando usa algum deles.
Quando a anotação @Produces ela quer dizer ao cdi conheça aquele objeto.
O @PersistContext avisa ao servidor que aquele objeto é o que você vai usar para persistir seus dados.
O EntityManagerFactory nada mais é que uma fabrica de EntityManagers, que de fato seu servidor tbm vai cuidar disso.
Recomendo que use o @Inject, injetando em seus DAOs o EntityManager, dessa maneira você tirar muito proveito do poderoso CDI.
Abraços !