VRaptor3 + Hibernate + @Transactional na Controller

hmmm
acho que não tem erro nenhum com a @Transactional não… :oops:

como prometi, fiz o projeto de teste
E FUNCIONOU!!

Tudo funcionou como deveria!
Na execução do Interceptor, a transação foi aberta e depois de exibido a jsp, commitada. Tanto que o LazyLoading funcionou normalmente.
Se tirar o @MyTransactional do método test() da TestController, o Interceptor não executa o intercept(), logo a transação não é aberta, e na JSP estoura, corretamente, uma LazyLoadingInitializationException.

a unica modificação deste projeto para o que estava dando o erro é que este não está usando Maven. Baixei as dependencias manualmente.
pode ser que a versão do AspectJ que configurei no pom.xml lá na empresa estava incorreta, ou precisava baixar mais coisas.

:arrow: enfim, estou anexando o projeto para avaliação.

PS: tirei a pasta lib para poupar espaço… mas segue as libs e suas versões que tenho na WEB-INF/lib

A versão que baixei do AspectJ foi a 1.6.10
dentro dela tem 4 jar’s… e incluí todos na pasta WEB-INF/lib

obrigado!

uhfuaha po,
agora que removi tudo que era Spring!!!

vou baixar e dar uma olhada, dps posto.
ah vc testou no Tomcat? qual versão?

hahahah

tb fiquei confuso!
amanhã no trabalho vou testar incluindo no maven a versão correta e ver se tem estas 4 libs do AspectJ
e se as outras libs também estão com as versões corretas

Sim, testei no Tomcat. Versão 6.0.29

abraços!

A linha onde dá o class-cast é onde o vraptor faz cast do getBean usando a própria classe passada como parametro.

As chances disso acontecer são quase nulas, a menos que tenha ocorrido algum erro na criação dos proxies, mas para investigar isso é necessário um stacktrace mais complexo. Claro, não estou dizendo que isso nunca vai acontecer, mas sim que é algo muito raro.

Isso é verdade, garcia-jj!

eu cheguei até a baixar os fontes do VRaptor pra ver o que tava acontecendo…

E o stacktrace era só aquele mesmo… está completo

Agora percebi um problema que estou tento neste projetinho que anexei… um pouco diferente do assunto principal…

O primeiro request no contexto vai perfeito… e tudo ocorre bem…

mas se eu der um F5 na página, parece que o Spring não consegue mais encontrar o Interceptor…

acontecendo esta exception:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test.interceptor.MyInterceptor] is defined: no bean for this type registered

estou fazendo alguma coisa de errado?

Pra testar, anotei o Interceptor com @ApplicationScoped do VRaptor. Mas aí o Interceptor nem executa… nenhuma vez…

Na base do adivinhometro é complicado saber…

Coloque a definição da classe aqui, ou seja, quais as anotações que estão declaradas na classe.

Ta tudo lá no projeto que anexei no 6º post acima deste.
Mas pra simplificar tenho o seguinte cenário:

TestController.java - A Controller devidamente anotada com @Resource

	@Path("/")
	@MyTransactional //minha annotation para o Interceptor pegar
	public void test() {
		
		User user = dao.getUser();
		if (user == null) {
			setup();
			user = dao.getUser();
		}
		
		result.include("user", user);
		result.include("test", "Test OK");
	}

MyTransactional.java - Minha annotation para o Interceptor pegar

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTransactional {

}

MyInterceptor.java - O Inteceptor

@Intercepts
public class MyInterceptor implements Interceptor {

	@Override
	public boolean accepts(ResourceMethod method) {
		return method.containsAnnotation(MyTransactional.class);
	}

	@Override
	@Transactional // do Spring 
	public void intercept(InterceptorStack stack, ResourceMethod method, Object obj) throws InterceptionException {
		System.out.println("===============>>>> MyInterceptor init  <<<=========================");
		stack.next(method, obj);
		System.out.println("===============>>>> MyInterceptor end  <<<=========================");
	}

}

Desta forma só 1 request funciona. Depois da NoSuchBeanDefinitionException.
E colocando @ApplicationScope no Interceptor, ele sequer é executado

Meu applicationContext.xml está em WEB-INF/classes
mas este tanto aí quanto no /src é lido e interpretado corretamente

valeu!

Creio que o problema seja porque o spring registra as classes que o vraptor já registrou.

Estou com uma dúvida… você precisa realmente usar esse hibrido de spring com vraptor? somente os componentes do vraptor deixando o spring apenas como provider transparente não dá? Não entendi porque ficar anotando manualmente os métodos como transaction se o vrapor já controla automagicamente as transações.

como o garcia falou, se vc vai colocar transaction no interceptor é melhor usar o que vem do VRaptor

a necessidade de usar o Spring é porque tenho jars de outros projetos que são usados em vários projetos.
Uma espécie de “Módulo Core” que é um simples projeto onde tem as entidades padrões das maiorias dos projetos daqui da empresa, assim como seus DAOs e alguns componentes comuns a varios projetos.
E tudo isso é usando Spring, pq este “módulo core” é usado tanto em projetos web, console e desktop.

Não sabia que o VRaptor ja controla automaticamente as transações.
Conheci agora o HibernateTransactionInterceptor é pra isto que este cara serve né?

valeu aí :slight_smile:

isso, o HibernateTransactionInterceptor é o cara pra isso =)
só que ele intercepta todas as requisições…

vc precisaria estendê-lo (sobrescrevendo o accepts) para só aceitar os métodos anotados

fiz uns testes estendendo o HibernateTransactionInterceptor
e vi que ele precisa de uma Session criada ja

Aí registrei o SessionCreator. Não usei o HibernateCustomProvider pq nao preciso do SessionFactoryCreator.

Ok… tudo certo… agora tenho a Session.
Mas acabou não funcionando como eu queria…
pq esta Session não é aquela gerenciada pelo Spring. Eu precisaria fechar ela manualmente, correto?

pois vi que o SessionCreator faz um factory.openSession() e nos meus DAOs eu faço factory.currentSession() que já é a com suporte a transação controlados pelo Spring

E como a maioria dos meus DAOs ficam em um Jar separado (o famoso “módulo core”) se eu mudasse ele, iria impactar diversos projetos, web ou não.
Este é um dos grandes motivos que tenho um misto de Spring e VRaptor.

Por isso a solução perfeita pra mim é colocar o @Transactional no intercepts() do Interceptor.
Só que com isso parece que o Interceptor acaba ficando registrado tanto no Spring quanto no VRaptor… e a partir do segundo request, da erro que o Spring não encontrou nenhum bean do meu Interceptor.
Isto pode ser classificado como um bug?

Obrigado!
e desculpa se eu estou sendo chato demais… hehehe… :oops:

talvez seja um bug sim…

o ideal é vc colocar o @Transactional nos lugares onde vc precisa de transação mesmo… não deveria ser no interceptor

ou anotar no próprio controller, ou dentro de uma classe que ele usa (no DAO por exemplo)…

vou investigar o bug e ver se tem salvação

:lol: :lol:

realmente o ideal seria anotar no próprio Controller
apesar que acho que faz sentido colocar a @Transactional no intercepts() sim… principalmente nos casos onde quer usar Lazy Loading iterando a collection na JSP com <c:forEach>

se vc usa o OpenSessionInViewFilter tanto faz se tah no Controller ou no Interceptor (qto ao Lazy Loading)

desculpa a demora, mas aparentemente eu corrigi o bug =)

testa aí com esse snapshot (substitua o seu vraptor-3.1.3.jar)

https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.2.1-SNAPSHOT/vraptor-3.2.1-20101214.180111-8.jar

Abraços

que da hora, cara!
vou testar daqui a pouco!

testo colocando a @Transactional na Controller, Interceptor, ou outra forma?

demora? que nada! foi bem rápido! menos de uma semana :smiley:
parabéns pelo EXCELENTE trabalho com o framework! :smiley:

tenta primeiro no interceptor (que foi o que funcionou pra mim)

mas no controller tb deve funcionar (só não vai ser open session in view, a menos que vc coloque o OpenSessionInViewFilter no web.xml)

[]'s