Announcement Announcement Module
Collapse
No announcement yet.
Can't get Spring annotatons and @AspecJ to work together Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Can't get Spring annotatons and @AspecJ to work together

    I have a Spring 3 MVC app where all of my spring components are defined with annotations vs. being defined in the mvc-servlet.xml. I am trying to integrate AspectJ using the @AspectJ annotations. The problem that I have is that Spring needs to see the aspect as a Spring component as well as AspectJ needing to see the class defined as an Aspect so if I try to use both annotations @Aspect and @Component it blows up on me at application startup.

    All documentation that I've been diggin through only give an example of using @AspectJ with the standard definition of spring components(non-annotation based)

    How do you do this when using annotations for both spring components and @AspectJ definitions?

    mvc-servlet.xml
    Code:
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> 
    
    	
    	<context:component-scan base-package="com.jonsinfinity"/>
    		
    	<context:annotation-config />
    	<aop:aspectj-autoproxy />
              
            ...
    Advise class
    Code:
    @Component("hibernateAdvisor")
    @Aspect
    public class HibernateAdvisor {
    	
    	@Pointcut("execution(* com.jonsinfinity.hbm.custom.*.*(..))")
    	public void doRunAspect(){};
    	
    	@Autowired
    	HibernateTemplate template = null;
    	@Autowired
    	UserCredentialsDataSourceAdapter userCredentialsDataSourceAdapter = null;
    	
    	@Before("execution(* com.jonsinfinity.hbm.custom.*.*(..))")
    	public void changeCredentials(){
    		userCredentialsDataSourceAdapter.removeCredentialsFromCurrentThread();
    		userCredentialsDataSourceAdapter.setCredentialsForCurrentThread("joe", "blah");
    		userCredentialsDataSourceAdapter.setUsername("joe");
    		userCredentialsDataSourceAdapter.setPassword("blah");
    		
    		System.out.println("** HibernateAdvisor.changeCredentials() executed - New Credentials have been set. **");
    	}
    	
    	@AfterReturning
    	public void clearHibernateTemplate(){
    		//template.clear();
    		System.out.println("HibernateAdvisor.clearHibernateTemplate - Complete");
    	}
    
    }
    Stack Trace from startup failure
    Code:
    SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateAdvisor': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.springframework.orm.hibernate3.HibernateTemplate com.jonsinfinity.aspects.HibernateAdvisor.template; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateTemplate' defined in ServletContext resource [/WEB-INF/springmvc-servlet.xml]: Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/springmvc-servlet.xml]: Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/springmvc-servlet.xml]: Cannot resolve reference to bean 'targetDataSource' while setting bean property 'targetDataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'targetDataSource' defined in ServletContext resource [/WEB-INF/springmvc-servlet.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Must set property 'expression' before attempting to match
    	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:283)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1055)
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:511) ...

  • #2
    so i did some more digging and it seems that the use of the @Component annotation and the @Aspect annotation are not whats causing my problem. It looks like they are doing what their supposed to do for the most part. My error is being caused by the org.springframework.aop.aspectj.AspectJExpressionP ointcut class in the checkReadyToMatch() method. The javadocs on this method state that it is supposed to check wheather the pointcut expression is ready to match. If the getExpression() returns null it throws a IllegalStateException. That seems to be what is happening.

    Any thoughts on this?

    Code:
    /**
    	 * Check whether this pointcut is ready to match,
    	 * lazily building the underlying AspectJ pointcut expression.
    	 */
    	private void checkReadyToMatch() {
    		if (getExpression() == null) {
    			throw new IllegalStateException("Must set property 'expression' before attempting to match");
    		}
    		if (this.pointcutExpression == null) {
    			this.pointcutExpression = buildPointcutExpression();
    		}
    	}

    Comment


    • #3
      OK, got it figured out (I think). The @AfterReturning annotation needed the execution parameter set @AfterReturning("execution(* com.jonsinfinity.hbm.custom.*.*(..))") I thought that the void dummy method with the @Pointcut annotations was supposed to set the pointcut for other methods.

      Anyways after I got the execution parameter set on the AfterReturning I started getting a ClassNotFound exception for the asm class org.objectweb.asm.CodeVisitor class spring-asm does not contain this class. it is in the asm-1.5.3.jar and older only. once I brought that jar in things have been good. I don't know what is using the CodeVisitor class but obviously it is Depricated since it is not in any versions of the jar after 1.5.3. The current version of asm is 2.2.
      Last edited by jonsinfinity; Jan 16th, 2010, 11:11 PM.

      Comment


      • #4
        I would suggest you change your Aspect because you have a serious error in there. If an exception is thrown nothing is cleaned up. You want to implement this advice as an around advice not a @Before and @AfterReturning.

        You want to make sure that this advice is also called once (else you might call the @Before several times, generating overhead and possible errors) next to that you want to make sure it is called after the processing is done. Especially in the case where you have some batch jobs or scheduling also the threads are reused and thus the situation could occur that the wrong credentials are set.

        You can reference the pointcut by putting the name "doRunAspect" in the @Before and other advices instead of the expression, that is using a named pointcut.

        Comment

        Working...
        X