CDI - JSF + Primefaces + GlassFish

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 !