Flex: BlazeDS e LazyInitializationException

Fala galera.
Ao começar a mexer com BlazeDS + Hiberante, fatalmente o desenvolvedor receberá uma famigerada Lazy. Ao pesquisar na net, vai ver que isso ocorre por causa da serialização que o BlazeDS faz. Já vi algum workaround por aki, como não ter relacionamento nas tabelas ( :? ), alteração do Hibernate e etc.
Então comecei a pesquisar mais sobre o problema e achei esse link interessante. Baseado na idéia dele, efetuei as seguintes alterações em meu código:

  1. Extendendo a classe BeanProxy do BlazeDS:

[code]public class MyBeanProxy extends BeanProxy {

private static final long serialVersionUID = -855520030789863840L;

@Override
public Object getValue(Object instance, String propertyName) {
	try {
		super.getValue(instance, propertyName);
	} catch (LazyInitializationException exception) {
	}
	// Setting Null to avoid LazyInitializationException
	return null;
}

}
[/code]

  1. Registrar o proxy na inicialização do TOMCAT:

Com isso, em vez de levar a exceção, os valores são setados para null e enviados para o Flex. Estou escrevendo aki para deixar a solução documentada para futuros desenvolvedores e para servir de idéias para novas soluções.

[]s

Ótima iniciativa… Pretendo contruir um cenário parecido e provavelmente eu teria esse problema… =)… Parabéns

Eu jah vi esse workaround. Mas sinceramente, Interceptor para engolir excecao pra mim eh a maior gambiarra que tem.

Eu que implementei a solucao da modificacao do Hibernate, acho muito mais facil e mais elegante, qualquer coisa, tem como baixar o codigo fonte e a versao compilada lah no blog…

da um olhada la, eu pelo menos e muita gente achamos esse jeito mais interessante…
[]'s

[quote=AUser]Eu jah vi esse workaround. Mas sinceramente, Interceptor para engolir excecao pra mim eh a maior gambiarra que tem.

Eu que implementei a solucao da modificacao do Hibernate, acho muito mais facil e mais elegante, qualquer coisa, tem como baixar o codigo fonte e a versao compilada lah no blog…

da um olhada la, eu pelo menos e muita gente achamos esse jeito mais interessante…
[]'s[/quote]

Eu já tinha dado uma olhada na sua solução, mas sinceramente, mexer no src do Hibernate eu não fico confortável. Uma vez que o problema estava na serialização, achei bem melhor capturar a Exceção e setar nulo para o campo, podendo assim atualizar minha versão do Hibernate sem ter dor de cabeça. De qq forma, ficam as duas opções pro pessoal testar e usar a que preferir :smiley: . No link que mandei, achei bem interessante também um post do mesmo autor falando sobre segurança durante o uso do Flex/Air.

[]s

[quote=renzonuccitelli][quote=AUser]Eu jah vi esse workaround. Mas sinceramente, Interceptor para engolir excecao pra mim eh a maior gambiarra que tem.

Eu que implementei a solucao da modificacao do Hibernate, acho muito mais facil e mais elegante, qualquer coisa, tem como baixar o codigo fonte e a versao compilada lah no blog…

da um olhada la, eu pelo menos e muita gente achamos esse jeito mais interessante…
[]'s[/quote]

Eu já tinha dado uma olhada na sua solução, mas sinceramente, mexer no src do Hibernate eu não fico confortável. Uma vez que o problema estava na serialização, achei bem melhor capturar a Exceção e setar nulo para o campo, podendo assim atualizar minha versão do Hibernate sem ter dor de cabeça. De qq forma, ficam as duas opções pro pessoal testar e usar a que preferir :smiley: . No link que mandei, achei bem interessante também um post do mesmo autor falando sobre segurança durante o uso do Flex/Air.

[]s[/quote]

Bem, lá no blog tem assim como o source, o JAR já modificado lá, da última versão. Ficou bem grande a explicacao pq quis mostrar a todos o que acontece, com detalhes de classe, etc.

Mas enfim, verdade, opções não faltam, em pensar que há pouco tempo atrás tinha apenas uma…

[]'s!

[quote=AUser][quote=renzonuccitelli][quote=AUser]Eu jah vi esse workaround. Mas sinceramente, Interceptor para engolir excecao pra mim eh a maior gambiarra que tem.

Eu que implementei a solucao da modificacao do Hibernate, acho muito mais facil e mais elegante, qualquer coisa, tem como baixar o codigo fonte e a versao compilada lah no blog…

da um olhada la, eu pelo menos e muita gente achamos esse jeito mais interessante…
[]'s[/quote]

Eu já tinha dado uma olhada na sua solução, mas sinceramente, mexer no src do Hibernate eu não fico confortável. Uma vez que o problema estava na serialização, achei bem melhor capturar a Exceção e setar nulo para o campo, podendo assim atualizar minha versão do Hibernate sem ter dor de cabeça. De qq forma, ficam as duas opções pro pessoal testar e usar a que preferir :smiley: . No link que mandei, achei bem interessante também um post do mesmo autor falando sobre segurança durante o uso do Flex/Air.

[]s[/quote]

Bem, lá no blog tem assim como o source, o JAR já modificado lá, da última versão. Ficou bem grande a explicacao pq quis mostrar a todos o que acontece, com detalhes de classe, etc.

Mas enfim, verdade, opções não faltam, em pensar que há pouco tempo atrás tinha apenas uma…

[]'s![/quote]

Pois é, eu li os seus artigos e indiquei para amigos, achei bem interessantes. Mas como eu disse, eu prefiro não mexer no código do Hibernate. Como agora, haverá uma atualização dessa biblioteca. Eu teria que ir no código e refazer sua alteração, e torcer pra não acontecer nenhum efeito colateral. Mas assim com vc, acho bom ter várias soluções e cada desenvolver ver quais as vantagens e desvantagens de cada uma.

[]s

Bem, outra solução seria a implementação de um filter, semelhante ao padrão “Open Session In View”. Aliás, foi assim que consegui resolver o problema de forma efetiva nos projetos que desenvolvi utilizando estas tecnologias. Siga o mesmo conceito de conversação do Seam, por exemplo, e você já terá a base de como implementar o filter, que não deve fazer nada de mais além de gerenciar a abertura/fechamento das sessões/transações, liberando os objetos que estiverem à elas amarradas, pois por mais que você não encerre a sessão até garantir que todos os objetos tenham sido retornados, você vai ver outro erro, informando-o de que não é possível modificar objetos que estão atrelados à sessão corrente.

Exemplo:

	public void doFilter(
				ServletRequest servletRequest, 
				ServletResponse servletResponse,
				FilterChain filterChain ) throws IOException, ServletException {

		try{
			
			HibernateSessionFactory.getInstance().openSession();
			HibernateSessionFactory.getInstance().beginTransaction();
			
			filterChain.doFilter( servletRequest, servletResponse );
			
			HibernateSessionFactory.getInstance().commit();
			HibernateSessionFactory.getInstance().close();
			
		} catch( Exception e ){
			e.printStackTrace();
		}
				
	}

[quote=diego.hordi]Bem, outra solução seria a implementação de um filter, semelhante ao padrão “Open Session In View”. Aliás, foi assim que consegui resolver o problema de forma efetiva nos projetos que desenvolvi utilizando estas tecnologias. Siga o mesmo conceito de conversação do Seam, por exemplo, e você já terá a base de como implementar o filter, que não deve fazer nada de mais além de gerenciar a abertura/fechamento das sessões/transações, liberando os objetos que estiverem à elas amarradas, pois por mais que você não encerre a sessão até garantir que todos os objetos tenham sido retornados, você vai ver outro erro, informando-o de que não é possível modificar objetos que estão atrelados à sessão corrente.

Exemplo:

[code]
public void doFilter(
ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain ) throws IOException, ServletException {

	try{
		
		HibernateSessionFactory.getInstance().openSession();
		HibernateSessionFactory.getInstance().beginTransaction();
		
		filterChain.doFilter( servletRequest, servletResponse );
		
		HibernateSessionFactory.getInstance().commit();
		HibernateSessionFactory.getInstance().close();
		
	} catch( Exception e ){
		e.printStackTrace();
	}
			
}

[/code][/quote]

Na realidade essa solução não resolve, na minha opinião. Isso porque o serializador Blaze vai chamar todos os método get, e não só os que a View precisa, diferentemente do que ocorre com uma JSP. Assim, na prática vc estara carregando todos os dados da mesma forma que se setasse o fetch type para EAGER, uma vez que a sessão estará aberta e as coleções serão todas inicializadas.

Em tempo, um amigo deu uma melhorado no primeiro código que fiz, mas serve só para o Hibernate. Em vez de capturar a Exception, ele usa o Hibernate.isInitialized() (acho que é esse o nome) para verificar se o campo está inicializado. Mesmo assim dá pra usar para outros implementadores do JPA se eles fornecerem algum método parecido.

Sim, é a aplicação do conceito de instancialização “Eager”, que prima pela performance ao invés da preservação de memória. Todavia, este tipo de controle permite a construção do objeto e somente de suas dependências, e não de toda a coleção à qual faz referência.

Nos projetos de ERP que arquitetei que utilizavam estas tecnologias, após vários testes, vimos que esta estratégia era a melhor à ser adotada. Posso explicar isso através de um exemplo. Pense no gerenciamento dos lançamentos contábeis de uma empresa. Dificilmente, mas muito dificilmente mesmo, o usuário vai requisitar somente a descrição, a data e o valor do lançamento, sem também querer ver à quais contas ele foi creditado/debitado. Ao invés de fazer requisições para poupar o uso (temporário) de memória do servidor, não seria melhor eu transferir este objeto (Lançamento Contábil) completo, com todas e somente as suas dependências (Contas crédito, contas débito, histórico padrão…) para o front, fazendo uma espécie de load balance?

É claro, esta decisão vai depender muito da arquitetura/requisitos do seu software.

[]'s
Diego

[quote=diego.hordi]Sim, é a aplicação do conceito de instancialização “Eager”, que prima pela performance ao invés da preservação de memória. Todavia, este tipo de controle permite a construção do objeto e somente de suas dependências, e não de toda a coleção à qual faz referência.

Nos projetos de ERP que arquitetei que utilizavam estas tecnologias, após vários testes, vimos que esta estratégia era a melhor à ser adotada. Posso explicar isso através de um exemplo. Pense no gerenciamento dos lançamentos contábeis de uma empresa. Dificilmente, mas muito dificilmente mesmo, o usuário vai requisitar somente a descrição, a data e o valor do lançamento, sem também querer ver à quais contas ele foi creditado/debitado. Ao invés de fazer requisições para poupar o uso (temporário) de memória do servidor, não seria melhor eu transferir este objeto (Lançamento Contábil) completo, com todas e somente as suas dependências (Contas crédito, contas débito, histórico padrão…) para o front, fazendo uma espécie de load balance?

É claro, esta decisão vai depender muito da arquitetura/requisitos do seu software.

[]'s
Diego[/quote]

No caso de vc sempre querer enviar os dados, basta colocar como EAGER :smiley: . O problema que estou me referindo é outro. Dessa maneira, propriedade marcadas como LAZY serão inicializadas também. Um exemplo comum, uma classe pessoa tem várias referencias, como endereços, controles de pagamentos, controle de pessoal. Muito provavelmente a pessoa não vai querer ver seus endereços e controles de pagamentos ao mesmo tempo. Aí, se toda hora vc ficar enviando esses dados inuteis, vai ter problema de performance com certeza, trazendo um grafo completos de objetos e não utilizando muitos deles. Aki na empresa estamos passando por isso. Se o serializador conseguisse “pedir só o que necessita”, assim como um JSP, dava pra usar numa boa, mas como não é o caso, fica inviável.

Mas é sempre bom ter diversas opiniões, assim cada um pode colocar em prática todas elas e usar a que mais lhe parecer adequada.

[]s

É. É verdade, opiniões nunca são demais.

Mas o que posso te adiantar é: faça vários testes, vários mesmo. Ficamos aproximadamente umas 4 semanas testando e buscando soluções para contornar este problema e viabilizar uma solução que fosse de encontro à nossa necessidade. Você vai ver que “Lazy” é só um dos problemas ao se trabalhar com sistemas grandes utilizando o Flex, que por sinal é uma ferramenta excepcional.

[]'s
Diego.

[quote=viniciusfaleiro]2) Registrar o proxy na inicialização do TOMCAT:

PropertyProxyRegistry.getRegistry().register(Object.class, new MyBeanProxy());

Com isso, em vez de levar a exceção, os valores são setados para null e enviados para o Flex. Estou escrevendo aki para deixar a solução documentada para futuros desenvolvedores e para servir de idéias para novas soluções.
[/quote]

Como registrar o proxy na inicilizacao do TOMCAT?

[quote=wpsouto][quote=viniciusfaleiro]2) Registrar o proxy na inicialização do TOMCAT:

PropertyProxyRegistry.getRegistry().register(Object.class, new MyBeanProxy());

Com isso, em vez de levar a exceção, os valores são setados para null e enviados para o Flex. Estou escrevendo aki para deixar a solução documentada para futuros desenvolvedores e para servir de idéias para novas soluções.
[/quote]

Como registrar o proxy na inicilizacao do TOMCAT?[/quote]

Use um Listener.
Atualmente fiz um framework com uma arquitetura bem bacana de chamadas remotas em FLEX usando o Google App Engine, o JFera. O problema é que ainda estou documentando. Mas nesse projeto eu usei o GraniteDS e gostei muito. A documentação é bem melhor que a do Blaze, integra facilmente com Spring e, o melhor de tudo, resolve o problema de Lazy para o Hibernate. Para quem não tiver como requisito usar o Blaze, recomendo dar uma ulhada no graniteds.org.

[]s

Da uma olhada neste screencast bem bacana e fala sobre Adobe Flex 4, Java e Google App Engine - Alta escalabilidade para sua aplicação nas nuvens.

https://admin.na3.acrobat.com/_a204547676/p79647321/

Da uma olhada neste screencast bem bacana e fala sobre Adobe Flex 4, Java e Google App Engine - Alta escalabilidade para sua aplicação nas nuvens.

https://admin.na3.acrobat.com/_a204547676/p79647321/[/quote]

O problema era a arquitetura antiga do Cairgorm 2 e mesmo o 3 eu não gostei. Montei uma arquitetura que vc apenas lança eventos comuns no Flex e eles executam no servidor. Quando eu terminar a documentação, posto aki.

[]s

[quote=renzonuccitelli][quote=wpsouto][quote=viniciusfaleiro]2) Registrar o proxy na inicialização do TOMCAT:

PropertyProxyRegistry.getRegistry().register(Object.class, new MyBeanProxy());

Com isso, em vez de levar a exceção, os valores são setados para null e enviados para o Flex. Estou escrevendo aki para deixar a solução documentada para futuros desenvolvedores e para servir de idéias para novas soluções.
[/quote]

Como registrar o proxy na inicilizacao do TOMCAT?[/quote]

Use um Listener.
Atualmente fiz um framework com uma arquitetura bem bacana de chamadas remotas em FLEX usando o Google App Engine, o JFera. O problema é que ainda estou documentando. Mas nesse projeto eu usei o GraniteDS e gostei muito. A documentação é bem melhor que a do Blaze, integra facilmente com Spring e, o melhor de tudo, resolve o problema de Lazy para o Hibernate. Para quem não tiver como requisito usar o Blaze, recomendo dar uma ulhada no graniteds.org.

[]s[/quote]

Como registrar o Listener?

Assim da erro…

PropertyProxyRegistry.getRegistry().register(Object.class, new MyBeanProxy())

Oi wpsouto.

Vc primeiro precisa criar uma classe que será o ouvinte e registrar o ouvinte.

Olhe um exemplo:

[code]import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

// um listener de contexto
public class MeuListener implements ServletContextListener {

public void contextInitialized( ServletContextEvent sce ) {
    // aqui você coloca o código que deve ser executado quando o contexto foi iniciado,
    // ou seja, quando sua aplicação for para o ar (implentada, deploy) ou seja, o
    // PropertyProxyRegistry.getRegistry().register(Object.class, new MyBeanProxy()); 
}

public void contextDestroyed( ServletContextEvent sce ) {
    // igual ao primeiro, só que para quando a aplicação é tirada do ar ("desimplantada", undeploy)
}

}[/code]

Ai vc resgistra essa classe no web.xml

<listener> <listener-class>pacote.MeuListener</listener-class> </listener>

Você não deve colocar código dentro do e sim apontar para o ouvinte.

[]´s

Bom galera, apesar do tópico ser antigo vi que está solução atende só que fiz algumas alterações:
Meu projeto não utliza spring, por isso criei um listener para registrar meu MyBeanProxy.

public class ProxyInitialize implements ServletContextListener {

	@Override
	public void contextDestroyed(ServletContextEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void contextInitialized(ServletContextEvent arg0) {
		  
		PropertyProxyRegistry.getRegistry().register(Object.class, new MyBeanProxy());  

	}

}

E no meu MyBeanProxy sobrescrevi o getClassName do BeanProxy para evitar o erro de coerção quando converter objeto java para o flex.

public class MyBeanProxy extends BeanProxy {

	private static final long serialVersionUID = -855520030789863840L;

	@Override
	public Object getValue(Object instance, String propertyName) {
		Object resultado = null;


		resultado =  super.getValue(instance, propertyName);
		if (!Hibernate.isInitialized(resultado))
			resultado = null;
		return resultado;
	}



	protected String getClassName(Object o) {
		if (o instanceof HibernateProxy) {
			HibernateProxy object = (HibernateProxy) o;
			return object.getHibernateLazyInitializer().getEntityName();
		}
		else {
			return super.getClassName(o);
		}
	}	
	
	

}

Estou testando por enquanto… mas ateh agora funcionou perfeitamente. Aguardo comentários.

Jose,

Estou com o mesmo problema e estou tentando implementar a sua solução, mas aparentemente não estou executando ela. Existe alguma alteração a mais que deve ser feita alem de declarar no web.xml o ProxyInitialize.

exemplo:

ProxyInitialize

Obrigado,

Jean

Bom, ha algum tempo atras postei uma solucao para o Lazy Exception do Hibernate, com o codigo do Hibernate modificado. Assim sendo, quem quiser eh soh baixar aqui:

http://www.2shared.com/file/1pwLr8ce/hibernate-modified-320-RELEASE.html

A versao que modifiquei eh do Hibernate 3.2 . Basta substituir a sua versao do Hibernate por ela. Nao tem que fazer mais nada.

[]'s