Problemas com escopo view no JSF + Spring[RESOLVIDO]

Olá pessoal! Estou com um problema bem estranho. Estou usando jsf + spring + hibernate.
Eu tenho uma classe ViewScope para definir meus managed beans como view do spring:

public class ViewScope implements Scope {
	public Object get(String name, ObjectFactory<?> objectFactory) {
		if (FacesContext.getCurrentInstance().getViewRoot() != null) {
			Map<String, Object> viewMap = FacesContext.getCurrentInstance()
					.getViewRoot().getViewMap();
			if (viewMap.containsKey(name)) {
				return viewMap.get(name);
			} else {
				Object object = objectFactory.getObject();
				viewMap.put(name, object);
				return object;
			}
		} else {
			return null;
		}
	}

	public Object remove(String name) {
		if (FacesContext.getCurrentInstance().getViewRoot() != null) {
			return FacesContext.getCurrentInstance().getViewRoot().getViewMap()
					.remove(name);
		} else {
			return null;
		}
	}

	public void registerDestructionCallback(String name, Runnable callback) {
		// Do nothing
	}

	public Object resolveContextualObject(String key) {
		return null;
	}

	public String getConversationId() {
		return null;
	}

}

Ela está mapeada certinho no applicationContext:

<!-- View scope -->
	<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
		<property name="scopes">
			<map>
				<entry key="view">
					<bean class="com.brazcom.escopos.ViewScope" />
				</entry>
			</map>
		</property>
	</bean>

O problema é que dentro de algumas páginas xhtml que usa o managed bean anotado como Scope(“view”) eu tenho alguns botões e diálogos que não mudam de página, apenas atualizam a mesma via ajax. Quando clico em algum botão, meu managed bean instancia novamente, sem mudar a página.
Alguem tem uma solução? O view scope funciona assim mesmo? Se sim qual escopo eu precisaria utilizar para o managed bean seja instanciado uma vez por página e não instanciar novamente dentro da mesma página?

Cara o comportamento do scopo view é esse mesmo… Toda vez que você clicar em algum botão mesmo ele tendo alguma ação que utilize ajax, na próxima vez o seu manegedBean será instanciado novamente…

Eu vejo para você duas opções:

Ou utilizar o scopo @Session, o qual eu não recomendo, pelo fato de que ele só se perde quando o navegador for finalizado, causando assim uma sobrecarga de objetos na memória.

E a outra opção seria o @CustomScoped que você controla da maneira que você achar melhor.

Caso você estiver em uma aplicação com javaEE utilize o @ConversationScoped, que pode controlar da maneira que achar melhor…

Falow

[quote=narutor99]Cara o comportamento do scopo view é esse mesmo… Toda vez que você clicar em algum botão mesmo ele tendo alguma ação que utilize ajax, na próxima vez o seu manegedBean será instanciado novamente…

Eu vejo para você duas opções:

Ou utilizar o scopo @Session, o qual eu não recomendo, pelo fato de que ele só se perde quando o navegador for finalizado, causando assim uma sobrecarga de objetos na memória.

E a outra opção seria o @CustomScoped que você controla da maneira que você achar melhor.

Caso você estiver em uma aplicação com javaEE utilize o @ConversationScoped, que pode controlar da maneira que achar melhor…

Falow[/quote]
É que meu problema era com checkbox no dataTable do primefaces 3, daí quando clicava em um botão para ver os selecionados ele instanciava de novo. Acho que estou conseguindo fazer com o sessionScoped. Achava que eu tinha um problema no meu viewScoped, pois estou usando um do spring.

Mesmo assim obrigado! Vou ver se dou uma olhada nesse customScoped.

Olha o comportamento do viewScope não era para ser este.
Vide exemplo do JSF 2.0 que tem este escopo.

Eu não sei se você implementou corretamente o seu escopo pelo spring, afinal eu nunca vi este meio de criação.

O que posso te adiantar é que em escopo de visão (ViewScope) você deveria fazer quantas requisições ajax que desejar e manteria o seu backing bean vivo, afinal ele é o escopo intermediário do request e session, ele só deve mudar de instancia quando você efetuar a navegação.

Mas eu acho que isso você já sabia, só estava em dúvida.

Eu só acho que o comentário do narutor99 foi um pouco equivocado.

Se estiver no JSF 1.2 e puder não fazer o seu escopo de visão pelo spring, você pode usar o @KeepAlive do richfaces para ter um escopo de visão.
Abraços.

Então… Na verdade o viewScoped está funcionando exatamente dessa maneira em outras páginas, e o engraçado que quando eu dou um println no construtor para ver que foi instanciado, ele instancia novamente a cada requisição ajax e os valores não mudam. Consigo atualizar tabelas com base em filtro com o viewScoped, mesmo ele sendo instanciado mas os valores não perdem. Oo mistério…

Ah entendi.
Então você não esta com problema com perda de dados a cada requisição ajax, era somente um dúvida de o “porque” ele passa pelo construtor outras vezes!

Talvez este tipo de backing bean feito pelo spring tenha este detalhe.
Eu vou fazer um teste igual ao seu no JSF 2.0 e já posto um retorno!

até.

[quote=guilhermehkr]Ah entendi.
Então você não esta com problema com perda de dados a cada requisição ajax, era somente um dúvida de o “porque” ele passa pelo construtor outras vezes!

Talvez este tipo de backing bean feito pelo spring tenha este detalhe.
Eu vou fazer um teste igual ao seu no JSF 2.0 e já posto um retorno!

até.[/quote]
Na verdade eu estava com problema porque com uma ação isso não estava funcionando. Mas resolvi com sessionScoped.

Realmente o seu viewScoped tem um comportamento diferente.
Fiz o teste no JSF 2.0 com a anotação @ViewScoped e foi passado somente UM vez no construtor.

Ah se o sessionScoped resolve seu problema tudo bem, mas sai da regra né, afinal backing bean de sessão seria para a sessão do usuário mesmo.

Abraços, até.

É. Não estou conseguindo usar o viewScoped do próprio JSF.

esdras_63 me tire uma dúvida, você está declarando seus beans no applicationcontext?

Não. Estou declarando como managed bean e usando a anotação view(“scope”) do spring configurado certinho. Uso sessionScoped também em alguns beans desse projeto.

Estranho que o meu tive que declarar.

O meu view está igual ao seu, até na configuração.

Segue exemplo de pedaços da configuração para você ver se estou fazendo algo errado.

Declaração do PageBean

@Controller("usuarioBean")
@Scope("view")
public class UsuarioPageBean implements Serializable{
..........
}

FaceConfig

      &lt;managed-bean&gt;
		&lt;managed-bean-name&gt;usuarioBean&lt;/managed-bean-name&gt;
		&lt;managed-bean-class&gt;br.com.telemedicina.seguranca.web.bean.UsuarioPageBean&lt;/managed-bean-class&gt;
		&lt;managed-bean-scope&gt;#{view}&lt;/managed-bean-scope&gt;
		&lt;managed-property&gt;
			&lt;property-name&gt;usuarioService&lt;/property-name&gt;
			&lt;value&gt;#{usuarioService}&lt;/value&gt;
		&lt;/managed-property&gt;
		&lt;managed-property&gt;
			&lt;property-name&gt;perfilService&lt;/property-name&gt;
			&lt;value&gt;#{perfilService}&lt;/value&gt;
		&lt;/managed-property&gt;
	&lt;/managed-bean&gt;

       &lt;application&gt;
		&lt;!--variable-resolver&gt;org.springframework.web.jsf.DelegatingVariableResolver&lt;/variable-resolver--&gt;
		&lt;el-resolver&gt;org.springframework.web.jsf.el.SpringBeanFacesELResolver&lt;/el-resolver&gt;
		&lt;locale-config&gt;
			&lt;default-locale&gt;pt_BR&lt;/default-locale&gt;
			&lt;supported-locale&gt;en_US&lt;/supported-locale&gt;
		&lt;/locale-config&gt;
		&lt;message-bundle&gt;messages&lt;/message-bundle&gt;
		
		&lt;!-- system-event-listener&gt;
			&lt;system-event-listener-class&gt;br.com.telemedicina.web.scope.ViewScopeCallbackRegistrar&lt;/system-event-listener-class&gt;
			&lt;system-event-class&gt;javax.faces.event.PostConstructViewMapEvent&lt;/system-event-class&gt;
			&lt;source-class&gt;javax.faces.component.UIViewRoot&lt;/source-class&gt;
		&lt;/system-event-listener&gt;
		 
		&lt;system-event-listener&gt;
			&lt;system-event-listener-class&gt;br.com.telemedicina.web.scope.ViewScopeCallbackRegistrar&lt;/system-event-listener-class&gt;
			&lt;system-event-class&gt;javax.faces.event.PreDestroyViewMapEvent&lt;/system-event-class&gt;
			&lt;source-class&gt;javax.faces.component.UIViewRoot&lt;/source-class&gt;
		&lt;/system-event-listener--&gt;
	&lt;/application&gt;

Se tiver alguma ideia agradeço a ajuda, pois se não coloco no applicationcontext ele não

Os beans eu não estou declarando no applicationContext. Mas a configuração do viewScope do spring eu coloco no applicationContext referenciando para uma classe como está no meu primeiro post. Eu peguei na internet, se você procurar como configurar escopo view no JSF com Spring você já acha a classe e a configuração necessária.

Na verdade meu amigo,

queria tirar umas duvidas com você, percebi que no momento que faço uma submissão ser ser pelo Ajax que tenhos os problemas que venho enfrentando.

Discutindo arquitetura, você tem um bean para cada XHTML, eu fazia isso por funcionalidade, exemplo UsuarioPageBean, que atende tanto a tela de consulta, como a tela de cadastro.

Uma outra questão que tenho, caso você saiba responder é o fato de quando faço a tentativa de editar um registro que se encontra numa tabela que foi populada via ajax e essa edição leva a uma outra tela a mesma não executa a navegação, fazendo uma espécie de refresf na tela de consulta.

Obrigado pela ajuda.

[quote=afamorim]Na verdade meu amigo,

queria tirar umas duvidas com você, percebi que no momento que faço uma submissão ser ser pelo Ajax que tenhos os problemas que venho enfrentando.

Discutindo arquitetura, você tem um bean para cada XHTML, eu fazia isso por funcionalidade, exemplo UsuarioPageBean, que atende tanto a tela de consulta, como a tela de cadastro.

Uma outra questão que tenho, caso você saiba responder é o fato de quando faço a tentativa de editar um registro que se encontra numa tabela que foi populada via ajax e essa edição leva a uma outra tela a mesma não executa a navegação, fazendo uma espécie de refresf na tela de consulta.

Obrigado pela ajuda.[/quote]
Na verdade esse foi meu primeiro projeto grande em jsf e estou programando um pouco diferente para web. Como estou usando a biblioteca de componentes do primefaces, eu estou programando para web como se fosse desktop, então eu tenho uma tela que exibe uma tabela com dados do banco e um botão em baixo incluir. Quando clica no incluir eu abro um diálogo para incluir registro e já atualizo tudo via ajax. E se ele clica em um registro da tabela já abro um outro diálogo para alterar o registro e para excluir. Assim fica muito mais simples para o usuário e até mesmo para o programador caso ele use uma biblioteca rica. Assim eu acabo em uma tela tendo todas as funcionalidades e por isso uso um bean por tela, pois tudo que preciso está na mesma tela.
Já essa dúvida sua de requisições sem ser pelo ajax, pelo que eu sei você der um forward e não um redirect, seu bean não instanciará novamente caso use o viewScoped. Caso use um requestScoped ele irá ser instanciado novamente. No caso o certo seria você passar parâmetros via post ou get.