Problemas com JSF, Weld CDI e TomCat [RESOLVIDO]

Bom dia, galera.

Estou fazendo um estudo com JSF 2.2, TomCat 7 e Weld 2.0

Na parte do weld, já foi criado o arquivo beans.xml e alterado o web.xml;

Da a seguinte exceção:

WARNING: #{cidadeBean.grava}: java.lang.NullPointerException
javax.faces.FacesException: #{cidadeBean.grava}: java.lang.NullPointerException
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:117)
	at javax.faces.component.UICommand.broadcast(UICommand.java:315)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:786)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1251)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:947)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	at java.lang.Thread.run(Thread.java:722)
Caused by: javax.faces.el.EvaluationException: java.lang.NullPointerException
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:101)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:101)
	... 23 more
Caused by: java.lang.NullPointerException
	at br.com.protech.officeManager.dao.DAO.adiciona(DAO.java:37)
	at br.com.protech.officeManager.mb.CidadeBean.grava(CidadeBean.java:28)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:601)
	at org.apache.el.parser.AstValue.invoke(AstValue.java:278)
	at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:274)
	at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:40)
	at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
	... 24 more

Abaixo estão os Arquivos

public class JPAUtil {

	private static EntityManagerFactory emf = Persistence
			.createEntityManagerFactory("tributoProduto");

	@Produces
	@RequestScoped
	public EntityManager getEntityManager() {
		return emf.createEntityManager();
	}

	public void close(@Disposes EntityManager em) {
		em.close();
	}

}
public class DAO<T> implements Serializable {

	private static final long serialVersionUID = 1L;

	private final Class<T> classe;

	public DAO(Class<T> classe) {
		this.classe = classe;
	}

	@Inject
	private EntityManager em;

	public void adiciona(T t) {
		em.getTransaction().begin();
		em.persist(t);
		em.getTransaction().commit();
	}

//restante do codigo
}
@Named
@ViewScoped
public class CidadeBean implements Serializable {

	private Cidade cidade = new Cidade();

	private LazyDataModel<Cidade> lista;

	public void grava() {
		DAO<Cidade> dao = new DAO<Cidade>(Cidade.class);
		if (this.cidade.getId() != null)
			dao.atualiza(this.cidade);
		else
			dao.adiciona(this.cidade);
		this.cidade = new Cidade();
	}
   //Restante de codigo
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui">
<ui:composition template="/_template.xhtml">
	<ui:define name="corpo">
		<h:form id="cadastro">
			<p:panel header="Cadastro">
				<h:messages styleClass="erros" />
				<h2>
					<h:outputText value="Editando ICMS"
						rendered="#{not empty cidadeBean.cidade.id}" />
					<h:outputText vralue="Cadastrando ICMS"
						rendered="#{empty cidadeBean.cidade.id}" />
				</h2>
				<h:outputLabel value="Cidade:" for="cidade" />
				<h:inputText id="cidade" value="#{cidadeBean.cidade.cidade}"
					required="true" />
				<h:outputLabel value="Estado:" for="uf" />
				<h:inputText id="uf" value="#{cidadeBean.cidade.uf}" required="true"
					size="100" />

				<p:commandButton value="Gravar" action="#{cidadeBean.grava}"
					update=":cadastro " />
				<p:commandButton value="Cancelar"
					action="#{cidadeBean.limpaFormulario}" immediate="true"
					update=":cadastro " />
			</p:panel>
		</h:form>
	</ui:define>
</ui:composition>
</html>

Obrigado pela ajuda…

Não sei direito, mas Tomcat 7 não suporta a especificação CDI, suporta?
Lendo sobre, cheguei aqui, onde há uma resposta mais adequada para o que você está tentando fazer. O sujeito cita o Apache TomEE (pronuncie Tommy).
Talvez te ajude.

Posta o seu web.xml para ver se as configurações JNDI estão OK e dá uma olhada em como o Sergio Lopes exemplificou o ciclo de vida do CDI com JPA, ficou muito bom,
link http://blog.caelum.com.br/use-cdi-no-seu-proximo-projeto-java/ .

Pq você não injeta Cidade também ?

Suporta sim, mas é necessário fazer uma configuração em um arquivo context.xml, porque tanto o Tomcat quanto o Jetty trabalham de forma READ-ONLY com JNDI.

Muito Obrigado pelas respostas.

segue meu web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>OfficeManager</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/faces/*</url-pattern>
  </servlet-mapping>
  <listener>
	   <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
	</listener>
 
	<resource-env-ref>
	   <resource-env-ref-name>BeanManager</resource-env-ref-name>
	   <resource-env-ref-type>
	      javax.enterprise.inject.spi.BeanManager
	   </resource-env-ref-type>
	</resource-env-ref>
</web-app>

Segue o contexto.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context>
   <Manager pathname=""/> <!-- disables storage of sessions across restarts -->
   <Resource name="BeanManager"
      auth="Container"
      type="javax.enterprise.inject.spi.BeanManager"
      factory="org.jboss.weld.resources.ManagerObjectFactory"/>
</Context>

Quando resolver esse problema irei injetar a classe Cidade, e eu segui esse mesmo artigo da caelum, mesmo assim não deu certo.

@Named  
@ViewScoped  
public class CidadeBean implements Serializable {  
  
    private Cidade cidade = new Cidade();  
  
    private LazyDataModel<Cidade> lista;  
  
    public void grava() {  
        DAO<Cidade> dao = new DAO<Cidade>(Cidade.class);  // se vc esta usando cdi vc não deve dar new 
        if (this.cidade.getId() != null)  
            dao.atualiza(this.cidade);  
        else  
            dao.adiciona(this.cidade);  
        this.cidade = new Cidade();  
    }  
   //Restante de codigo  
}  

se vc der new no seu DAO o cdi não vai injetar o entityManager

e consequentimente vc tomara um nullpointer

tenta assim

@Named  
@ViewScoped  
public class CidadeBean implements Serializable {  
  
    private Cidade cidade = new Cidade();  
    @Inject 
    private DAO<Cidade> dao ;  
    private LazyDataModel<Cidade> lista;  
  
    public void grava() {    
        if (this.cidade.getId() != null)  
            dao.atualiza(this.cidade);  
        else  
            dao.adiciona(this.cidade);  
        this.cidade = new Cidade();  
    }  
   //Restante de codigo  
}  

e crie tambem essa classe

import java.lang.reflect.ParameterizedType;

import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import javax.persistence.EntityManager;

public class DAOFactory {

	@Inject
	private EntityManager em;

	public DAOFactory() {
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Produces @Dependent
	public DAO create(final InjectionPoint injectionPoint){
		ParameterizedType parameterizedType = (ParameterizedType) injectionPoint.getType();
		Class classe = (Class) parameterizedType.getActualTypeArguments()[0];
		return new DAO(classe, em);
	}
}

[quote=ivandasilva]Posta o seu web.xml para ver se as configurações JNDI estão OK e dá uma olhada em como o Sergio Lopes exemplificou o ciclo de vida do CDI com JPA, ficou muito bom,
link http://blog.caelum.com.br/use-cdi-no-seu-proximo-projeto-java/ .

Pq você não injeta Cidade também ?[/quote]

não vejo necessidade alguma em se injetar a Classe Cidade.

[quote=DaniloAndrade][quote=ivandasilva]Posta o seu web.xml para ver se as configurações JNDI estão OK e dá uma olhada em como o Sergio Lopes exemplificou o ciclo de vida do CDI com JPA, ficou muito bom,
link http://blog.caelum.com.br/use-cdi-no-seu-proximo-projeto-java/ .

Pq você não injeta Cidade também ?[/quote]

não vejo necessidade alguma em se injetar a Classe Cidade.[/quote]

DaniloAndrade, porque você não vê ?

Fiz as Alterações de acordo com o DaniloAndrade e agora apareceu as seguintes exceções, pelo que pesquisei o DAOFactory era pra não aparecer essa exceção

Em qual pasta você colocou o beans.xml ?

Em um projeto web o correto é em WEB-INF, mas, comigo já ocorreu este mesmo erro em um projeto web, então eu coloquei dentro do META-INF e funcionou Ok.

Eu Coloquei no META-INF, mais coloquei no WEB-INF pra fazer um teste

tira o @RequestScoped do metodo dessa classe pra teste

public class JPAUtil {  
  
    private static EntityManagerFactory emf = Persistence  
            .createEntityManagerFactory("tributoProduto");  
  
    @Produces  
    //@RequestScoped  //tire o  requestscoped
    public EntityManager getEntityManager() {  
        return emf.createEntityManager();  
    }  
  
    public void close(@Disposes EntityManager em) {  
        em.close();  
    }  
  
}  

e vê se muda a mensagem

tirei o @RequestScoped e nada…

vou colocar as libs, só pra desencargo

o seu EntityManagerFactory está static ainda ?

se estiver, põe um @Producer… e de quebra põe ele com o @ApplicationScoped para ser criado uma só vez


private EntityManagerFactory emf;

@Produces @ApplicationScoped
public void createEMF(EntityManagerFactory emf){
    this.emf = emf
}

e você pode também adicionar um @Dispose para fechar automágicamente a sua fábrica

public void createEMF(@Dispose EntityManagerFactory emf){
    emf.close();
}

velhinho faz o seguinte

vc disse que esta usando a versão 2.0 do weld

troca pra versão 1.1 final

a versão 2.0 é um beta ainda

Voltei pro Weld 1.1, mais voltou o erro inicial do nullPointer.

Era pra ser tão difícil assim?

não era não,

coloca o log do erro atual e o codigo das classes apos as alterações

ok, valeu Danilo, você está me ajudando muito.

public class JPAUtil {
	private static EntityManagerFactory emf = Persistence
			.createEntityManagerFactory("tributoProduto");

	@Produces
	@RequestScoped
	public EntityManager getEntityManager() {
		return emf.createEntityManager();
	}

	public void close(@Disposes EntityManager em) {
		em.close();
	}
}
public class DAO<T> implements Serializable {

	private static final long serialVersionUID = 1L;

	private final Class<T> classe;

	public DAO(Class<T> classe) {
		this.classe = classe;
	}

	@Inject
	private EntityManager em;

	public void adiciona(T t) {
		em.getTransaction().begin();
		em.persist(t);
		em.getTransaction().commit();
	}
}
public class DAOFactory {

	@Inject
	private EntityManager em;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Produces
	@Dependent
	public DAO create(final InjectionPoint injectionPoint) {
		ParameterizedType parameterizedType = (ParameterizedType) injectionPoint
				.getType();
		Class classe = (Class) parameterizedType.getActualTypeArguments()[0];
		return new DAO(classe);

	}

}

Acabei de notar que esse bean, no método getulista(), passa um DAO pra outra Classe;

@Named
@ViewScoped
public class CidadeBean implements Serializable {

	@Inject
	private Cidade cidade;

	@Inject
	private DAO<Cidade> dao;

	private LazyDataModel<Cidade> lista;

	public void grava() {
		if (this.cidade.getId() != null)
			dao.atualiza(this.cidade);
		else
			dao.adiciona(this.cidade);
		this.cidade = new Cidade();
	}

	public LazyDataModel<Cidade> getLista() {

		if (lista == null) {
			lista = new DataModel<Cidade>(dao);
		}
		return lista;
	}
public class DataModel<T> extends LazyDataModel<T> {

	private static final long serialVersionUID = 1L;
	private List<T> lista;	
	private DAO<T> dao;

	public DataModel(DAO<T> dao) {
		this.dao = dao;
	}

//Restante da Classe
}

cria um novo construtor aqui no DAO que vai receber a Classe e o EntityManager



public class DAO<T> implements Serializable {  
  
    private static final long serialVersionUID = 1L;  
  
    private final Class<T> classe;  
  
    public DAO(Class<T> classe, EntityManager em) {  // construtor com o entitymanager
        this.classe = classe;  
        this.em = em;
    }  
  
    @Inject  // pode tirar o inject daqui ele não sera mais necessario
    private EntityManager em;  
  
    public void adiciona(T t) {  
        em.getTransaction().begin();  
        em.persist(t);  
        em.getTransaction().commit();  
    }  
}  

na fabrica usa o novo construtor

public class DAOFactory {  
  
    @Inject  
    private EntityManager em;  
  
    @SuppressWarnings({ "rawtypes", "unchecked" })  
    @Produces  
    @Dependent  
    public DAO create(final InjectionPoint injectionPoint) {  
        ParameterizedType parameterizedType = (ParameterizedType) injectionPoint  
                .getType();  
        Class classe = (Class) parameterizedType.getActualTypeArguments()[0];  
        return new DAO(classe, em);  
  
    }  
  
}  

lembra o que eu falei antes, quando vc da new o conteiner não vai injetar as dependências que a classe venha precisar por isso vc deve passar pra classe essa dependência

se agente parar pra analisar vamos perceber que o cdi não tem como construir a classe DAO sozinha porque ele vai depender de onde vai ser injetada por isso criamos a fabrica

mas não adianta vc construir o dao passando a classe não passar o entitymanager tambem por que como estamos dando new no dao o cdi não vai injetar o entitymanager

Agora que eu entendi, funcionou Certinho…

Muito Obrigado pela ajuda de todos em especial o DaniloAndrade.

Abraços!