Problemas com Vraptor + AspectJ

Prezados,

Estou tentando usar o AspectJ para interceptar alguns metodos que não estão em escopo de requisição.
Já está tudo configurado corretamente e já consigo interceptar algumas coisas, usando Aspect. Porém estou com o seguinte problema:
As classes que tento interceptar que estão anotadas com @componet do Vraptor, estou obtendo o seguinte erro:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'cidadeController' defined in file [/home/usuario/projetosCaelum/workspace/meta/webapp/WEB-INF/classes/br/com/caelum/meta/controller/CidadeController.class]: Unsatisfied dependency expressed through constructor argument with index 1 of type [br.com.caelum.meta.business.CidadeBusiness]: : Error creating bean with name 'cidadeBusiness' defined in file [/home/usuario/projetosCaelum/workspace/meta/webapp/WEB-INF/classes/br/com/caelum/meta/business/CidadeBusiness.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [br.com.caelum.meta.business.CidadeBusiness]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cidadeBusiness' defined in file [/home/usuario/projetosCaelum/workspace/meta/webapp/WEB-INF/classes/br/com/caelum/meta/business/CidadeBusiness.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [br.com.caelum.meta.business.CidadeBusiness]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:698) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:192) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450) at org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:328) at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:43) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:385) at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:375) at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1069) at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:221) at br.com.caelum.vraptor.ioc.spring.VRaptorApplicationContext.getBean(VRaptorApplicationContext.java:240) at br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.instanceFor(SpringBasedContainer.java:58) at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:41) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.architecture.locales.LocalesInterceptor.intercept(LocalesInterceptor.java:71) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.architecture.vraptor.ErrorInterceptor.intercept(ErrorInterceptor.java:38) at br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:41) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:46) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:46) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:48) at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:59) at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:62) at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91) at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:55) at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583) at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454) at java.lang.Thread.run(Thread.java:595) Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cidadeBusiness' defined in file [/home/usuario/projetosCaelum/workspace/meta/webapp/WEB-INF/classes/br/com/caelum/meta/business/CidadeBusiness.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [br.com.caelum.meta.business.CidadeBusiness]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:283) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:984) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:886) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:479) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:450) at org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:328) at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:43) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:189) at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:820) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:762) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:680) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:771) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:691) ... 51 more Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [br.com.caelum.meta.business.CidadeBusiness]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:137) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:107) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:275) ... 64 more Caused by: java.lang.IllegalArgumentException: argument type mismatch at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:494) at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126) ... 66 more

Meu aplicationContext.xml:

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

<aop:aspectj-autoproxy/>

<context:component-scan base-package="br.com.caelum.aspects" />

[/code]

Classe anotada com Aspect:

[code]@Aspect
@org.springframework.stereotype.Component
public class DAOAspect {

@Around("execution (public java.util.List<Object> *.listAll()))")
public void around(ProceedingJoinPoint jp) throws Throwable {

	System.out.println("Passou-----> #################");

	// continua
	jp.proceed();

}

}
[/code]
A classe que está apresentando erro, está com a anotação @Componet do Vraptor (Todas as classes de negocio e dao estão anotadas com @Componet do VRaport e as de Controller com @Resource). A classe que está anotada com Aspect, possui também a anotação de @componet do Spring. Mas vale salientar que tudo está aparentemente OK, quando tento interceptar uma classe que não possui nenhum vinculo com as anotações do VRaptor. Me parece que da forma como está, está se perdendo as anotações do VRaptor…

quando vc usa os componentes do Spring que usam aspectos, vc precisa que as classes atingidas pelos aspectos tenham um construtor padrão…

ou seja, vc vai ter que usar injeção de dependências via setter:

pegue o construtor da classe
para cada argumento do construtor crie um setter respectivo
anote o setter com @Autowired
remova o construtor da classe ou adicione um construtor sem argumentos

isso deve funcionar… só é chato ser obrigado a usar injeção por setter, mas é o padrão do spring, não tem o que fazer

Lucas, fiz o que voce falou. Agora estou tendo a exception abaixo…
Lembrando que CidadeDAO implementa DAO… nao entendi porque está dando argument type mismatch…

[code]@Component
public class CidadeBusiness extends AbstractBusiness{

public CidadeBusiness() {
	super();
}

@Autowired
public void setDao(CidadeDAO dao) {
	super.setDao(dao);
}

}[/code]

[code]public abstract class AbstractBusiness implements Business {

private DAO dao;

public AbstractBusiness() {

}

public void setDao(DAO dao) {
	this.dao = dao;
}


}[/code]

[code]@Component
public class CidadeDAO extends DAOImpl implements DAO {

public CidadeDAO() {
}

@Override
@Autowired
public void setSession(Session session) {
	super.setSession(session);
}

}[/code]

Funcionou com a seguinte saida:

[code]@Component
public class CidadeBusiness extends AbstractBusiness{

public CidadeBusiness() {
	super();
}

   @Autowired
@Override
public void setDao(@Qualifier("cidadeDAO")DAO dao) {
	this.dao = dao;
}

}[/code]

Observe que alem de deixar no set, e anotar com autowired, eu tive que explicitar que o atributo é uma interface DAO e anotar com o @Qualifier(“cidadeDAO”)…
Não gostei da solução… achei que ficou com muito codigo de configuração… estava tão simples… :frowning:

O Spring provavelmente está se perdendo com esse monte de herança que vc fez… repare que o setDao do AbstractBusiness recebe DAO e não CidadeDao… e isso faz com que ele se confunda

o setDao não deveria estar na classe AbstractBusiness, se vc tirar, acho que vai funcionar direito sem precisar do @Qualifier

[quote=Lucas Cavalcanti]O Spring provavelmente está se perdendo com esse monte de herança que vc fez… repare que o setDao do AbstractBusiness recebe DAO e não CidadeDao… e isso faz com que ele se confunda

o setDao não deveria estar na classe AbstractBusiness, se vc tirar, acho que vai funcionar direito sem precisar do @Qualifier[/quote]

Eu removi o setDAO do abstract… sem problemas…
Mas continuo precisando usar o @Qualifier DAO, pois se eu fizer diretamente com CidadeDAO, dá IllegalArgumentException: argument type mismatch …
Considerando que CidadeDao é uma implementação de DAO e DAO é uma interface, não era pra funcionar???

Além de tudo, continuo com outro problema mais adiante, pois passando @Qualifier(“cidadeDAO”) DAO, quando tento dar um cast nesses metodospara cidadeDAO, obtenho o classcastexception…

entendi… vc tah aplicando aspectos no Dao, não no controller…

as classes que serão aplicadas aspectos precisam ter construtor padrão sem argumentos… ou seja, vc vai ter que usar injeção via setters no CidadeDao tb

tenta isso e vê se funciona, e tira o @Qualifier DAO

[quote=Lucas Cavalcanti]entendi… vc tah aplicando aspectos no Dao, não no controller…
as classes que serão aplicadas aspectos precisam ter construtor padrão sem argumentos… ou seja, vc vai ter que usar injeção via setters no CidadeDao tb
tenta isso e vê se funciona, e tira o @Qualifier DAO[/quote]

estou usando injeção via setters em todas as classes, pra ver se consigo resolver isso.
Mas não consegui retirar o @qualifeier, pois se eu fizer diretamente com CidadeDAO (tirando o qualifier), dá IllegalArgumentException: argument type mismatch …

Além de tudo, continuo com outro problema mais adiante, pois passando @Qualifier(“cidadeDAO”) DAO, quando tento dar um cast nesses metodospara cidadeDAO, obtenho o classcastexception…

bom… testei aqui na minha máquina, e os proxies que o aspectJ gera não estendem as suas classes concretas: só herdam as interfaces! por isso vc recebeu um classCAstException

então, se vc criar, por exemplo, uma INTERFACE CidadeDao que estende de DAO, e tivesse a implementação separada, funcionaria a injeção…

bom, é mais um nível de indireção, mas infelizmente é assim que o spring AOP trabalha: vc precisa de interfaces… Assim funcionou pra mim:

public interface CidadeDAO extends DAO<Cidade> {
  // métodos a mais que só tem no cidadeDAo
}

@Component
public class CidadeDAOImpl implements CidadeDAO {
   //...
}

@Resource
public class CidadeController {
     public CidadeController(..., CidadeDAO dao) {...}
}

E o mais importante: assim vc não precisa usar injeção via setter!!! pode voltar pra injeção por construtor… se vc extrair as interfaces e sempre referenciar interfaces, o AOP consegue instanciar as classes sem problema

Lucas,
Quase funcionou!!!
kkkkkk
Seguinte, fiz como voce falou, realmente está ok dessa forma.
Contudo eu estava testando, como exemplo, o metodo listAll do meu dao. Ai quando começou a funcionar porem quando o metodo listAll é interceptado pelo AOP, o retorno do metodo vem null…
Se eu remover a classe que intercepta este listAll, o retorno vem populado corretamente…

[code] @Around(“execution (public java.util.List *.listAll()))”)
public void around(ProceedingJoinPoint jp) throws Throwable {

	System.out.println("Funciona");

	// continua
	jp.proceed();

}

[/code]

Alguma sugestão?

vc precisa retornar no aspecto tb:

	@Around("execution (public java.util.List<Object> *.listAll()))")
	public Object around(ProceedingJoinPoint jp) throws Throwable {

		System.out.println("Funciona");

		// continua
		return jp.proceed();

	}