Announcement Announcement Module
Collapse
No announcement yet.
Help with DefaultAdvisorAutoProxyCreator for ThrowsAdvice Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Help with DefaultAdvisorAutoProxyCreator for ThrowsAdvice

    Hi,
    I want to define a DefaultAdvisorAutoProxyCreator, to be able to generate a database entry containing the details of an Exception. I want to define it so that, whenever an Exception is thrown, I want a row to be inserted into a table containing the details...

    Here are my definitions:
    Code:
    	<bean id="exceptionAdvice" class="util.ExceptionAdvice" >
    		<property name="userDAO"><ref local="userDAO"/></property>
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    
    	<bean id="exceptionAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    		<property name="advice"><ref local="exceptionAdvice"/></property>
    		<property name="patterns">
    			<list>
    				<value>.*</value>
    			</list>			
    		</property>
    	</bean>
    	
    	<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">		
    		<property name="advisorBeanNamePrefix">
    				<value>exceptionAdv</value>			
    		</property>
    		<property name="usePrefix">
    				<value>true</value>			
    		</property>
    	</bean>
    Here is my ExceptionAdvice:
    Code:
    public class ExceptionAdvice implements ThrowsAdvice&#123;
    	private SystemDAO systemDAO = null;
    	private UserDAO userDAO = null;
    
    	public void setUserDAO&#40;UserDAO userDao&#41; &#123;
            this.userDAO = userDao;
        &#125;
    	public void setSystemDAO&#40;SystemDAO systemDao&#41; &#123;
            this.systemDAO = systemDao;
        &#125;
    
    	public void afterThrowing&#40;Method m,Object&#91;&#93; args,Object target,Exception ex&#41;&#123;
    		ApplicationErrorLog ael=new ApplicationErrorLog&#40;&#41;;
    		Timestamp now = new Timestamp&#40;System.currentTimeMillis&#40;&#41;&#41;;
    		ael.setCreatedTime&#40;now&#41;;
    		
    		ael.setCreatedUser&#40;userDAO.retrieveUserByUserName&#40;"admin"&#41;&#41;;
    		ael.setDescription&#40;"Method&#58;"+m+" Exception&#58;"+ex&#41;;
    		ael.setErrorNumber&#40;"111"&#41;;		
    		systemDAO.saveApplicationErrorLog&#40;ael&#41;;
    	&#125;
    &#125;
    I get the following Exception when I try to run this:
    Code:
    Exception in constructor&#58; testCreateAndDeleteUser &#40;org.springframework.beans.factory.BeanCreationException&#58; Error creating bean with name 'userManagerFacade' defined in class path resource &#91;applicationContext.xml&#93;&#58; Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException&#58; Unexpected AOP exception; nested exception is java.lang.IllegalArgumentException&#58; Cannot subclass final class class $Proxy3
    org.springframework.aop.framework.AopConfigException&#58; Unexpected AOP exception; nested exception is java.lang.IllegalArgumentException&#58; Cannot subclass final class class $Proxy3
    java.lang.IllegalArgumentException&#58; Cannot subclass final class class $Proxy3
    	at net.sf.cglib.proxy.Enhancer.generateClass&#40;Enhancer.java&#58;448&#41;
    	at net.sf.cglib.core.DefaultGeneratorStrategy.generate&#40;DefaultGeneratorStrategy.java&#58;63&#41;
    	at net.sf.cglib.core.AbstractClassGenerator.create&#40;AbstractClassGenerator.java&#58;192&#41;
    	at net.sf.cglib.proxy.Enhancer.createHelper&#40;Enhancer.java&#58;406&#41;
    	at net.sf.cglib.proxy.Enhancer.create&#40;Enhancer.java&#58;318&#41;
    	at org.springframework.aop.framework.Cglib2AopProxy.getProxy&#40;Cglib2AopProxy.java&#58;240&#41;
    	at org.springframework.aop.framework.Cglib2AopProxy.getProxy&#40;Cglib2AopProxy.java&#58;213&#41;
    	at org.springframework.aop.framework.ProxyFactoryBean.getSingletonInstance&#40;ProxyFactoryBean.java&#58;210&#41;
    	at org.springframework.aop.framework.ProxyFactoryBean.setBeanFactory&#40;ProxyFactoryBean.java&#58;177&#41;
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean&#40;AbstractAutowireCapableBeanFactory.java&#58;245&#41;
    	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean&#40;AbstractAutowireCapableBeanFactory.java&#58;177&#41;
    	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean&#40;AbstractBeanFactory.java&#58;159&#41;
    	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons&#40;DefaultListableBeanFactory.java&#58;177&#41;
    	at org.springframework.context.support.AbstractApplicationContext.refresh&#40;AbstractApplicationContext.java&#58;268&#41;
    	at org.springframework.context.support.ClassPathXmlApplicationContext.<init>&#40;ClassPathXmlApplicationContext.java&#58;68&#41;
    	at service.BaseServiceTestCase.<init>&#40;BaseServiceTestCase.java&#58;14&#41;
    	at service.UserManagerFacadeTest.<init>&#40;UserManagerFacadeTest.java&#58;12&#41;
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance0&#40;Native Method&#41;
    	at sun.reflect.NativeConstructorAccessorImpl.newInstance&#40;NativeConstructorAccessorImpl.java&#58;39&#41;
    	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance&#40;DelegatingConstructorAccessorImpl.java&#58;27&#41;
    	at java.lang.reflect.Constructor.newInstance&#40;Constructor.java&#58;274&#41;
    	at service.UserManagerFacadeTest.main&#40;UserManagerFacadeTest.java&#58;69&#41;
    &#41;
    	at service.UserManagerFacadeTest.main&#40;UserManagerFacadeTest.java&#58;69&#41;
    It complains about the bean 'userManagerFacade' , so here is the bean definition:
    Code:
    	<bean id="FacadeTemplate" lazy-init="true" 
    		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    		<property name="transactionManager"><ref local="transactionManager"/></property> 
    		<property name="transactionAttributes"> 
    			<props> 
    				<prop key="update_*">PROPAGATION_REQUIRED</prop> 
    				<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> 
    			</props> 
    		</property>	
    	</bean>
    		
    	<bean id="userManagerFacade" parent="FacadeTemplate" class="org.springframework.aop.framework.ProxyFactoryBean"> 
    		<property name="target"><ref local="userManagerFacadeTarget"/></property>
    		<property name="interceptorNames">
    			<list>
    				<value>securityAdvisor</value>
    			</list>
    		</property> 
    	</bean>	
    	
    	<bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl"> 
    		<property name="userDAO"><ref local="userDAO"/></property>
    		<property name="systemDAO"><ref local="systemDAO"/></property>
    	</bean>
    What can be the problem?
    Thanks a lot, regards,
    Turgay Zengin

  • #2
    It looks like one of the classes you're trying to advise is final. CGLIB generates a subclass at runtime to apply interception: it can't do this if a class is final.

    Comment


    • #3
      Thanks Rod,
      But I have no final classes.

      I suspect that the bean 'userManagerFacadeTarget' is causing the problem. I get the exception after the following:
      Code:
      DEBUG - AbstractAutowireCapableBeanFactory.destroyBean&#40;849&#41; | Applying DestructionAwareBeanPostProcessors to bean with name 'userManagerFacadeTarget'
      Probably there is an error with this bean definition, but I can't figure out how to fix it: (All configuration is in the first post)
      Code:
      <bean id="userManagerFacade" parent="FacadeTemplate" class="org.springframework.aop.framework.ProxyFactoryBean">
      Can I use both "parent" and "class" in the same bean definition?

      Regards,
      Turgay Zengin

      Comment


      • #4
        Solved

        While playing with the context definition, I made it work, but don't know why it works now. Looks like the order of definitions are important when using parent="a template" (first I define the TransactionalFacadeTemplate, then the SecureFacadeTemplate and then finally the facade bean).

        Also, there is one difference which may be the reason it works now: There is another template bean for the security advice now. The userManagerFacade bean uses this SecureFacadeTemplate bean to have security advice functionality.

        Here is the changed bean definitions:
        Code:
        	<bean id="TransactionalFacadeTemplate" lazy-init="true"
        		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        		<property name="transactionManager"><ref local="transactionManager"/></property> 
        		<property name="transactionAttributes"> 
        			<props> 
        				<prop key="update_*">PROPAGATION_REQUIRED</prop> 
        				<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> 
        			</props> 
        		</property>	
        
        	</bean>
        
        	<bean id="SecureFacadeTemplate" lazy-init="true" parent="TransactionalFacadeTemplate"
        		class="org.springframework.aop.framework.ProxyFactoryBean">
        		<property name="interceptorNames">
        			<list>
        				<value>securityAdvisor</value>
        			</list>
        		</property>
        
        	</bean>
        
            <bean id="userManagerFacade" parent="SecureFacadeTemplate" >
        		<property name="proxyInterfaces"><value>service.UserManagerFacade</value></property>
        		<property name="target"><ref local="userManagerFacadeTarget"/></property>
            </bean>    
        
        	<bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl"> 
        		<property name="userDAO"><ref local="userDAO"/></property>
        		<property name="systemDAO"><ref local="systemDAO"/></property>
        	</bean>
        Now the exception advice works...

        Regards,
        Turgay Zengin

        Comment


        • #5
          It sounds like you had DefaultAdvisorAutoProxyCreator trying to proxy a proxy. The JDK's proxies are final classes, thus they cannot be proxied by CBLIB.

          Comment


          • #6
            Thank you, that explains the exception java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy3

            Comment


            • #7
              It sounds like you had DefaultAdvisorAutoProxyCreator trying to proxy a proxy
              Proxying a proxy is usually a bad idea (although I've seen people doing it successfully, unintentionally) because of the additional performance overhead (not usually a problem, though) and the added depth to stack traces for debugging and analysing production problems.

              Comment


              • #8
                So, what is the recommended way to have the same service object (my userManagerFacade in this example) to have both TransactionProxyFactoryBean functionality, and another AOP functionality (securityAdvisor in this example)?

                Comment


                • #9
                  Originally posted by turgayz
                  So, what is the recommended way to have the same service object (my userManagerFacade in this example) to have both TransactionProxyFactoryBean functionality, and another AOP functionality (securityAdvisor in this example)?
                  You can use
                  Code:
                    <bean id="TransactionalFacadeTemplate" lazy-init="true"
                      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
                      <property name="transactionManager">
                        <ref local="transactionManager"/>
                      </property>
                      <property name="transactionAttributes">
                        <props>
                          <prop key="update_*">PROPAGATION_REQUIRED</prop>
                          <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
                        </props>
                      </property>
                    </bean>
                  
                    <bean id="SecureFacadeTemplate" lazy-init="true" parent="TransactionalFacadeTemplate">
                      <property name="preInterceptors">
                        <list>
                          <ref local="securityAdvisor"/>
                        </list>
                      </property>
                    </bean>
                  
                    <bean id="userManagerFacade" parent="SecureFacadeTemplate" >
                      <property name="proxyInterfaces"><value>service.UserManagerFacade</value></property>
                      <property name="target">
                  		  <bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl">
                  		    <property name="userDAO"><ref local="userDAO"/></property>
                  		    <property name="systemDAO"><ref local="systemDAO"/></property>
                  		  </bean>
                      </property>
                    </bean>

                  Comment


                  • #10
                    Thank you,
                    I used the part that you insert "userManagerFacadeTarget" as a nested bean. But the other part caused problems (where you set the preInterceptors). I got an exception saying:

                    Code:
                    testCreateAndDeleteUser&#40;service.UserManagerFacadeTest&#41;org.springframework.orm.hibernate.HibernateSystemException&#58; a different object with the same identifier value was already associated with the session&#58; 2, of class&#58; domain.User; nested exception is net.sf.hibernate.NonUniqueObjectException&#58; a different object with the same identifier value was already associated with the session&#58; 2, of class&#58; domain.User
                    I understood the pre-post interceptors, thank you. But I couldn't make it work that way. My config works the other way (described in post dated Sep 02, 2004 4:08 am), so I'll use that.

                    Regards,
                    Turgay Zengin

                    Comment

                    Working...
                    X