Spring não funciona

Bom, tenho meu applicationContext:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


<bean id="livroDAO" class="br.com.odontonew.dao.LivroDAO"/>
 
 <bean class="br.com.odontonew.bo.LivroBOImpl" id="livroBO">
   <property name="dao" ref="livroDAO" />
 </bean>
 
</beans>

pelo meu entendimento, posso utilizar o “livroBO” em qualquer *.xhtml, então fiz assim:

<!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:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui">

<h:head>
	<title>AppJSF2</title>
</h:head>
<h:body>
	<h1>Gerenciador de Livros</h1>
	<h:dataTable value="#{livroBO.listar}" var="l">
		<h:column>
			<f:facet name="header">
				<h:outputText value="Titulo" />
			</f:facet>
			<h:outputText value="#{l.titulo}" />
		</h:column>
	</h:dataTable>
</h:body>
</html>

mas simplesmente não funciona, nada acontece. Nenhum erro e nada é listado. Obs: tem dados no banco e o problema não estar na recuperação destes dados pois seu eu mudar o livroBO para livroBOImpl (que é o meu ManagedBean) funciona normal.

Vc está tentando acessar um recurso do Spring via tela diretamente. Vc deve fazer a sua view estar atrelada ao ManagedBean do JSF, e esse fazer os repasse para as outras camadas, como regra de negócio e DAO. O JSF não conhece LivroBO, e sim o ManagedBean LivroBOImpl.
Espero ter ajudado.

Bom, não ficou muito claro, vamos lá. Pelo que entendi não posso utilizar o Spring na camada View, apenas Controller e Model, ou seja, apenas nas Classes .Java

Pois bem, usando ainda o mesmo applicationContext.xml que mostrei logo acima, implementei minha classe LivroBOImpl da seguinte forma:

package br.com.odontonew.bo;


import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import org.apache.log4j.Logger;

import br.com.odontonew.bean.Livro;
import br.com.odontonew.dao.AbstractDAO;
import br.com.odontonew.dao.LivroDAO;

@ManagedBean(name="livroBOImpl")
@SessionScoped
public class LivroBOImpl implements BasicBO {
	
	private Logger log = Logger.getLogger(LivroBOImpl.class);

	private Livro livro;
	private DataModel listaLivros;

	private AbstractDAO<Livro> dao;

	public AbstractDAO<Livro> getDao() {
		return dao;
	}

	public void setDao(AbstractDAO<Livro> dao) {
		this.dao = dao;
	}

	@Override
	public DataModel getListar() {
		if (log.isDebugEnabled())
			log.debug("Buscando lista de livros");
		listaLivros = new ListDataModel(dao.findAll());
		return listaLivros;
	}

	@Override
	public String prepararInsecao() {
		livro = new Livro();
		return "gerenciarLivro";
	}

	@Override
	public String prepararAlteracao() {
		livro = (Livro) listaLivros.getRowData();
		return "gerenciarLivro";
	}

	@Override
	public String adicionar() {
		dao.save(livro);		
		return "index";
	}

	@Override
	public String excluir() {
		dao.delete(livro);
		return "index";
	}

	@Override
	public String alterar() {
		dao.update(livro);
		return "index";
	}

	public Livro getLivro() {
		return livro;
	}

	public void setLivro(Livro livro) {
		this.livro = livro;
	}

}

Perceba que faço um AbstractDAO dao (getters e setters) para tentar fazer a injeção de dependência neste atributo. Porém quando inicializo minha aplicação da o seguinte erro:

java.lang.NullPointerException
	br.com.odontonew.bo.LivroBOImpl.getListar(LivroBOImpl.java:38)

Acontece que a criação dos beans está sendo feita pelo JSF e não pelo Spring Framework.
Se você não setar no faces-config.xml que o Spring será o bean generator, nada funcionará.
Pesquise no google, tem um milhão de exemplos de JSF 2 + Spring Framework e em todos eles existe a configuração.

Bom, lendo os tutoriais, principalmente deste site(http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/), percebi que o Spring vai me ajudar a instanciar atributos dentro do ManagedBean (de forma automática e transparente), mas ainda assim eu preciso explicitamente dizer através do faces-config.xml quem é o ManagedBean para ser utilizado no *.xhtml, ou seja, o spring não se comunica com o XHTML, ele se comunica com as classes Java e o JSF faz a interseção entre XHTML e Java.

Estou correto ?

[quote=rlanhellas]Bom, lendo os tutoriais, principalmente deste site(http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/), percebi que o Spring vai me ajudar a instanciar atributos dentro do ManagedBean (de forma automática e transparente), mas ainda assim eu preciso explicitamente dizer através do faces-config.xml quem é o ManagedBean para ser utilizado no *.xhtml, ou seja, o spring não se comunica com o XHTML, ele se comunica com as classes Java e o JSF faz a interseção entre XHTML e Java.

Estou correto ?[/quote]
Tudo o que o xhtml vai apresentar precisa, obrigatoriamente, estar dentro da árvore do FacesContext. É isso que você faz quando explicita no faces-config.xml que o Spring Framework será o bean generator e, também, quando colocar os getters e setters no teu ManagedBean. Os getters tornam o objeto acessível ao xhtml e os setters permitem que você defina valores para os atributos do ManagedBean. Neste caso, a única responsabilidade do Spring Framework é dispor os objetos relacionados no MB quando a árvore de componentes do FacesContext é montada.

Obrigado pela explicação. Vou testar o projeto com a integração entre spring e jsf2 e retorno aqui assim que possível.

Caro, fiz as configurações necessárias mas não funcionou. Veja:

faces-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<faces-config
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
    version="2.0">
    
    <application>
     <el-resolver>
     org.springframework.web.jsf.el.SpringBeanFacesELResolver
     </el-resolver>
    </application>
    
    <managed-bean>
     <managed-bean-name>livroBO</managed-bean-name>
     <managed-bean-class>br.com.meuprojeto.LivroBOImpl</managed-bean-class>
     <managed-bean-scope>session</managed-bean-scope>
     <managed-property>
      <property-name>dao</property-name>
      <value>#{livroDAO}</value>
     </managed-property>
    </managed-bean>

</faces-config>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
 
</beans>

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>ApplicationJSF2</display-name>
  <welcome-file-list>
    <welcome-file>index.jsf</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>*.jsf</url-pattern>
  </servlet-mapping>
  
  <listener>
	  <listener-class>
	   	org.springframework.web.context.ContextLoaderListener
  	</listener-class>
  </listener>
  
  <listener>
  <listener-class>
   org.springframework.web.context.request.RequestContextListener
  </listener-class>
  </listener>
</web-app>

index.xhtml

<!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:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui">

<h:head>
	<title>AppJSF2</title>
</h:head>
<h:body>
	<h1>Gerenciador de Livros</h1>
	<h:dataTable value="#{livroBO.listar}" var="l">
		<h:column>
			<f:facet name="header">
				<h:outputText value="Titulo" />
			</f:facet>
			<h:outputText value="#{l.titulo}" />
		</h:column>
	</h:dataTable>
</h:body>
</html>

Eu inicio o Tomcat normalmente, porém quando acesso a página da o seguinte erro:

javax.servlet.ServletException: Não foi possível criar o bean gerenciado livroBO.  Os seguintes problemas foram encontrados:
     - O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
     - O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
	javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
root cause

com.sun.faces.mgbean.ManagedBeanCreationException: Não foi possível criar o bean gerenciado livroBO.  Os seguintes problemas foram encontrados:
     - O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.
     - O bean ou a classe da propriedade br.com.meuprojeto.LivroBOImpl do bean gerenciado livroBO não pôde ser encontrada.

Note que em teu applicationContext.xml você tem apenas o objeto livroDAO (id=“livroDAO”) mapeado. Isso significa que ele será o único a ser instanciado pelo container do Spring Framework.
Se você tiver isso em teu código

LivroDAO livroDAO = new LivroDAO();

Você não está obtendo o objeto instanciado pelo Spring. Logo, isso não tem relevância.

Como eu acredito que livroDAO não é um objeto que será isolado, você vai precisar mapear os demais objetos da hierarquia. Pelo que entendi do teu modelo, o livroDAO é um atributo de LivroBOImpl. Sendo assim, você precisa ter uma entrada parecida com esta no teu applicationContext.xml:

<bean id="livroBO" class="br.com.meuprojeto.bo.LivroBOImpl"> 
    <property name="livroDAO" ref="livroDAO"/>
    <!-- Demais atributos relevantes aqui -->
</bean>

Isso fará com que, você tenha o atributo livroDAO injetado em teu livroBO. Para que o livroBO tenha utilidade, você precisará fazer o mesmo (inserir mapeamento) até chegar no ManagedBean correspondente. Aí você tem toda estrutura controlada pelo Spring.

<bean id="livroBean" class="br.com.meuprojeto.pacote.LivroBean"> 
    <property name="livroBO" ref="livroBO"/>
</bean>

Veja que acima eu amarrei o livroBO ao livroBean. Como livroDAO está amarrado a livroBO, quando a instância de objeto referente ao atributo livroBO do livroBean for instanciada, automaticamente carregará o livroDAO consigo.

Na verdade estava errado o meu faces-config.xml eu estava chamando “br.com.meuprojeto.LivroBOImpl” quando o certo é “br.com.meuprojeto.bo.LivroBOImpl”.

Porém, testei das duas formas no applicationConext.xml e funcionou, gostaria de saber o porque:

forma 1:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
 
  <bean class="br.com.meuprojeto.bo.LivroBOImpl" id="livroBO">
   <property name="dao" ref="livroDAO" />
 </bean> 
 
</beans>

FOrma 2:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>
 
</beans>

Segue meu LivroBOImpl:

package br.com.meuprojeto.bo;


import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;

import org.apache.log4j.Logger;

import sun.org.mozilla.javascript.internal.Context;

import br.com.meuprojeto.bean.Livro;
import br.com.meuprojeto.dao.AbstractDAO;
import br.com.meuprojeto.dao.LivroDAO;

public class LivroBOImpl implements BasicBO {
	
	private Logger log = Logger.getLogger(LivroBOImpl.class);

	private Livro livro;
	private DataModel listaLivros;

	private AbstractDAO<Livro> dao;

	public AbstractDAO<Livro> getDao() {
		return dao;
	}

	public void setDao(AbstractDAO<Livro> dao) {
		this.dao = dao;
	}

	@Override
	public DataModel getListar() {
		listaLivros = new ListDataModel(dao.findAll());
		if (log.isInfoEnabled())
			log.info("Livros encontrados: "+listaLivros.getRowCount());
		return listaLivros;
	}

	@Override
	public String prepararInsecao() {
		livro = new Livro();
		return "gerenciarLivro";
	}

	@Override
	public String prepararAlteracao() {
		livro = (Livro) listaLivros.getRowData();
		return "gerenciarLivro";
	}

	@Override
	public String adicionar() {
		dao.save(livro);		
		return "index";
	}

	@Override
	public String excluir() {
		dao.delete(livro);
		return "index";
	}

	@Override
	public String alterar() {
		dao.update(livro);
		return "index";
	}

	public Livro getLivro() {
		return livro;
	}

	public void setLivro(Livro livro) {
		this.livro = livro;
	}

}

Você precisa ser coerente com o que está fazendo.
Veja que em teu applicationContext.xml você coloca:

<bean id="livroDAO" class="br.com.meuprojeto.dao.LivroDAO"/>  
  
  <bean class="br.com.meuprojeto.bo.LivroBOImpl" id="livroBO">  
   <property name="dao" ref="livroDAO" />  
</bean> 

Porém, não existe o mapeamento do teu ManagedBean. Sem isto, não funciona. Você não pode fazer, no ManagedBean:

LivroBO lb = new LivroBO();

Isto irá instanciar o objeto lb, mas não será o objeto que está sendo gerenciado pelo Spring.

Não existe mapeamento do meu ManagedBean ? Mas eu configurei isso no meu faces-config.xml, lá eu mapei todo meu managedBean.

Tirando isto

<?xml version="1.0" encoding="UTF-8"?>  
<faces-config  
    xmlns="http://java.sun.com/xml/ns/javaee"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"  
    version="2.0">        
    <application>  
     <el-resolver>  org.springframework.web.jsf.el.SpringBeanFacesELResolver  
     </el-resolver>  
    </application>  
</faces-config>  

Qualquer outra coisa é desnecessária no faces-config.xml. Afinal, você está dizendo que quem irá gerenciar os beans é o Spring. Logo, esse mapeamento de ManagedBean aqui é tão inútil quanto não mapeá-lo.
Você precisa dizer ao Spring que o ManagedBean é um bean que ele deve criar.

Então, no meu faces-config.xml só deve ter a chamada para o EL do Spring, assim digo a aplicação quem irá ser o principal “resolvedor” de EL.

No meu applicationContext.xml faço as injeções de dependência, inclusive a criação dos meus ManagedBean que serão utilizados no meu *.XHTML.

Achei estranho isso, pois neste tutorial (http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example/) ele ensina exatamente a utilizar o mapeamento do faces-config.xml e também no applicationContext.xml