Announcement Announcement Module
Collapse
No announcement yet.
AspectJ @Before problem Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • AspectJ @Before problem

    Having a problem getting my @Before Aspect to not cause havock upon Spring startup. Removing the @Before but leaving the @Aspect allows Spring to start.

    applicationContext.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           	xmlns:tx="http://www.springframework.org/schema/tx"
           	xmlns:context="http://www.springframework.org/schema/context"
           	xmlns:aop="http://www.springframework.org/schema/aop"
    	    xsi:schemaLocation="
    	    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    	    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    	    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.1.xsd
    	    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
        	default-autowire="byName">
        	
        <!-- Enable annotation config -->
    	<context:annotation-config/>
    	
    	<!-- Enable AOP annotations -->
    	<aop:aspectj-autoproxy/>
    
    	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        	<property name="locations">
            	<value>classpath:jdbc.properties</value>
        	</property>
        	<property name="ignoreResourceNotFound" value="true"/>
    	</bean>
    
    	<!-- Transaction behavior based on annotations -->
      	<tx:annotation-driven order="200"/>
    
    	<!-- Data source -->
    	<bean id="targetDataSource" 
    			class="org.apache.commons.dbcp.BasicDataSource" 
    			destroy-method="close" depends-on=" ">
    		<property name="driverClassName" value="${jdbc.driverClassName}"/>
    		<property name="url" value="${jdbc.url}"/>
    		<property name="username" value="${jdbc.username}"/>
    		<property name="password" value="${jdbc.password}"/>
    		<property name="maxActive" value="100"/>
    		<property name="maxWait" value="500"/>
    		<property name="validationQuery" value="SELECT SYSDATE FROM DUAL"/>
    	</bean>
    	
    	<bean id="dataSource"
    			class="com.mycompany.commons.data.datasource.CurrentStudyIdAwareDataSourceProxy">
    	</bean>
    
    	<!-- Hibernate -->
    	<bean id="sessionFactory"
    			class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    		<property name="annotatedClasses">
    			<list>
    				<value>com.mycompany.domain.Study</value>
    				<value>com.mycompany.domain.User</value>
    				<value>com.mycompany.domain.WebServiceSession</value>
    			</list>
    		</property>
    		<property name="hibernateProperties">
    			<props>
    				<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
    				<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
    				<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
    				<prop key="hibernate.use_sql_comments">${hibernate.use_sql_comments}</prop>
    				<prop key="hibernate.max_fetch_depth">3</prop>
    			</props>
    		</property>
    	</bean>
    	
    	<!-- Transaction -->
    	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"/>
    	
    	<!-- DAOs -->
    	<bean id="siteDAO" class="com.mycompany.commons.data.dao.impl.SiteDAOGenericHibernateImpl"/>
    	<bean id="userDAO" class="com.mycompany.commons.data.dao.impl.UserDAOGenericHibernateImpl"/>
    	<bean id="webServiceSessionDAO" class="com.mycompany.commons.data.dao.impl.WebServiceSessionDAOGenericHibernateImpl"/>
    	<bean id="studyDAO" class="com.mycompany.commons.data.dao.impl.StudyDAOGenericHibernateImpl"/>
    	
    	<!-- NativeJdbcExtractor for the Commons DBCP connection pool above -->
    	<bean id="nativeJdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" lazy-init="true"/>
    
    	<!-- LobHandler for Oracle JDBC drivers -->
    	<bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true"/>
    
    	<!-- Aspects -->
    	<bean class="com.mycompany.commons.data.support.CurrentStudyIdAspect"/>
    </beans>
    CurrentStudyIdAspect
    Code:
    package com.mycompany.commons.data.support;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.core.annotation.Order;
    
    import com.mycompany.commons.data.dao.WebServiceSessionDAO;
    import com.mycompany.domain.WebServiceSession;
    
    @Aspect
    @Order(100)
    public class CurrentStudyIdAspect {
    
    	private static Log logger = LogFactory.getLog(CurrentStudyIdAspect.class);
    	
    	@Autowired
    	private WebServiceSessionDAO webServiceSessionDAO;
    	
    	@Before("@annotation(com.mycompany.commons.data.annotation.CurrentStudyIdFromToken) && args(token, ..)")
    	public void setCurrentStudyIdFromToken(byte[] token) {
    		WebServiceSession session = webServiceSessionDAO.findByToken(token);
    		if (token != null) {
    			if (session != null) {
    				if (session.getStudy() != null) {
    					CurrentStudyIdHolder.setStudyId(session.getStudy().getId());
    				}
    				else {
    					logger.debug("session.study null");
    				}
    			}
    			else {
    				logger.debug("session null");
    			}
    		}
    		else {
    			logger.debug("token null or not size 16");
    		}
    	}
    	
    }
    CurrentStudyId
    Code:
    package com.mycompany.commons.data.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(value = { ElementType.METHOD })
    @Documented
    public @interface CurrentStudyIdFromToken {
    }

  • #2
    Stack trace from JUnit 4.4 test
    Code:
    [junit] Running com.mycompany.commons.testsuites.TestCurrentStudyId
        [junit] Testsuite: com.mycompany.commons.testsuites.TestCurrentStudyId
        [junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 0.886 sec
        [junit] Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 0.886 sec
        [junit] ------------- Standard Output ---------------
        [junit] [WARN,org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] Could not load properties from class path resource [jdbc.properties]: class path resource [jdbc.properties] cannot be opened because it does not exist
        [junit] ------------- ---------------- ---------------
        [junit] 
        [junit] Testcase: verifyFindStudy took 0.011 sec
        [junit]     Caused an ERROR
        [junit] Error creating bean with name 'org.springframework.context.annotation.internalRequiredAnnotationProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot create inner bean '(inner bean)' of type [org.springframework.transaction.interceptor.TransactionInterceptor] while setting bean property 'transactionInterceptor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)': Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'targetDataSource' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Failed to bind all argument names: 1 argument(s) could not be bound
        [junit] org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.annotation.internalRequiredAnnotationProcessor': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot create inner bean '(inner bean)' of type [org.springframework.transaction.interceptor.TransactionInterceptor] while setting bean property 'transactionInterceptor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)': Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'targetDataSource' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Failed to bind all argument names: 1 argument(s) could not be bound
        [junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:557)
        [junit]     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:238)
        [junit]     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:167)
        [junit]     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:235)
        [junit]     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:167)
        [junit]     at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:867)
        [junit]     at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:588)
        [junit]     at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:351)
        [junit]     at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:93)
        [junit]     at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:44)
        [junit]     at org.springframework.test.context.TestContext.buildApplicationContext(TestContext.java:127)
        [junit]     at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:167)
        [junit]     at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:58)
        [junit]     at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:184)
        [junit]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:95)
        [junit]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.invokeTestMethod(SpringJUnit4ClassRunner.java:144)
        [junit] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.config.internalTransactionAdvisor': Cannot create inner bean '(inner bean)' of type [org.springframework.transaction.interceptor.TransactionInterceptor] while setting bean property 'transactionInterceptor'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)': Cannot resolve reference to bean 'transactionManager' while setting bean property 'transactionManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'targetDataSource' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalStateException: Failed to bind all argument names: 1 argument(s) could not be bound
        [junit]     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:219)
        [junit]     at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:121)
        [junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1218)
        [junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:986)
        [junit]     at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:529)
        [junit]     at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:238)
        [junit]     at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:167)
        [junit]     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:235)
        [junit]     at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:167)
        [junit]     at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:87)
        [junit]     at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:98)
        [junit]     at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:83)
        [junit]     at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:84)
        [junit]     at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:66)
        [junit]     at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:296)
        [junit]     at
    ......

    Comment


    • #3
      TestCurrentStudyIdAspect
      Code:
      package com.mycompany.commons.support;
      
      import static org.junit.Assert.assertNotNull;
      import static org.junit.Assert.assertTrue;
      
      import org.junit.After;
      import org.junit.Before;
      import org.junit.Test;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.test.annotation.Rollback;
      
      import com.mycompany.commons.data.annotation.CurrentStudyIdFromToken;
      import com.mycompany.commons.data.dao.StudyDAO;
      import com.mycompany.commons.data.dao.UserDAO;
      import com.mycompany.commons.data.dao.WebServiceSessionDAO;
      import com.mycompany.commons.data.support.CurrentStudyIdHolder;
      import com.mycompany.domain.Study;
      import com.mycompany.domain.User;
      import com.mycompany.domain.WebServiceSession;
      
      public class TestCurrentStudyIdAspect extends CommonTestCase {
      
      	@Autowired
      	private WebServiceSessionDAO webServiceSessionDAO;
      	@Autowired
      	private UserDAO userDAO;
      	@Autowired
      	private StudyDAO studyDAO;
      	
      	@Before
      	@Rollback(false)
      	public void createSession() {
      		WebServiceSession session = new WebServiceSession();
      		User user = userDAO.findById(DEFAULT_USER_ID);
      		session.setUser(user);
      		Study study = studyDAO.findById(DEFAULT_STUDY_ID);
      		session.setStudy(study);
      		webServiceSessionDAO.saveOrUpdate(session);
      	}
      	
      	@After
      	@Rollback(false)
      	public void destroySession() {
      		deleteFromTables("HD.WEBSERVICE_SESSION");
      	}
      	
      	@Test
      	public void verifyFindStudy() throws Exception {
      		CurrentStudyIdHolder.setStudyId(999L);
      		User user = userDAO.findById(DEFAULT_USER_ID);
      		WebServiceSession session = webServiceSessionDAO.findByUser(user);
      		assertNotNull("WebServiceSession Study null", session.getStudy());
      		verifyAspectFired(session.getToken());
      	}
      	
      	@CurrentStudyIdFromToken
      	public void verifyAspectFired(byte[] token) {
      		assertTrue("StudyId still 999", CurrentStudyIdHolder.getStudyId() != 999);
      	}
      	
      	
      	
      }
      I've left out other irrelevant classes.

      Comment


      • #4
        So I managed to get it to startup without errors by replacing the asm*.jar and cglib*.jar from Hibernate with Spring's. But I cannot get the Aspect to fire.

        Comment


        • #5
          Anybody? I just need to fire my aspect before the @Transactional by specifying my own annotation. I can't seem to make it fire.

          Comment


          • #6
            Not to sound unhelpful, but could you try to make the example as minimal as possible?
            If you think it's a Spring AOP problem, removing annotation-driven IoC etc might be a good idea. What version of spring are you using? Did you try the latest stable release (2.0.7)?

            Comment


            • #7
              I'm using 2.1-m4, but I tried 2.0.6 and 2.0.7. I even tried not using the annotations. Oh well. I'll find another way.

              Comment


              • #8
                Can you provide a minimal example (just using a static main() to load a context and call a bean) that demonstrates the problem?

                Comment


                • #9
                  Based on the code samples you provided, it looks like the aspect might not be firing because you've added the @CurrentStudyIdFromToken annotation to a method on an object which is not managed by Spring (in this case, TestCurrentStudyIdAspect.verifyAspectFired()) . Spring AOP will only proxy objects created by the Spring container.

                  Comment


                  • #10
                    Interesting. I'll try adjusting my applicationContext.xml file. Thanks. I'll post back.

                    Comment


                    • #11
                      Seems that Hibernate ships with asm-*-1.5.3 but Spring 2.1-M4 ships with asm-*2.2.3. If I use asm-*-1.5.3 Spring breaks, but if I use asm-*-2.2.3 Hibernate breaks. So I can't test this either way.

                      Comment


                      • #12
                        First a little explaining. When I began this post, I was using Ant but since then I've switched to Maven. So I figured it out. First I found this article explaining the problem. Then I did this:

                        pom.xml
                        Code:
                        ...
                        <dependency>
                                <groupId>org.hibernate</groupId>
                                <artifactId>hibernate</artifactId>
                                <version>3.2.5.ga</version>
                                <exclusions>
                                  <exclusion>
                                    <artifactId>asm</artifactId>
                                    <groupId>asm</groupId>
                                  </exclusion>
                                  <exclusion>
                                    <artifactId>asm</artifactId>
                                    <groupId>asm-attrs</groupId>
                                  </exclusion>
                                  <exclusion>
                                  	<groupId>cglib</groupId>
                                  	<artifactId>cglib</artifactId>
                                  </exclusion>
                                </exclusions>
                              </dependency>
                              <dependency>
                            		<groupId>asm</groupId>
                            		<artifactId>asm</artifactId>
                            		<version>2.2.3</version>
                            	</dependency>
                            	<dependency>
                            		<groupId>asm</groupId>
                            		<artifactId>asm-attrs</artifactId>
                            		<version>2.2.3</version>
                            	</dependency>
                            	<dependency>
                            		<groupId>asm</groupId>
                            		<artifactId>asm-commons</artifactId>
                            		<version>2.2.3</version>
                            	</dependency>
                            	<dependency>
                            		<groupId>asm</groupId>
                            		<artifactId>asm-util</artifactId>
                            		<version>2.2.3</version>
                            	</dependency>
                            	<dependency>
                            		<groupId>cglib</groupId>
                            		<artifactId>cglib-nodep</artifactId>
                            		<version>2.1_3</version>
                            	</dependency>
                        ....
                        Notice the bolded cglib-nodep. nodep is very important. Then the last thing I discovered is I had to put the annotation on the implementation of my DAO, not the DAO interface, and not the TestCase as you pointed out. It had to be on a Spring managed bean. Then it worked like a champ! Thanks for your help.

                        Comment

                        Working...
                        X