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
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
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.
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…
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
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.
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é?
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:
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>