moved ApplicationContext-dependent .aop.* unit tests from .testsuite -> .context

in the process, identified and refactored two genuine integration tests (AopNamespaceHandlerScopeIntegrationTests, AdvisorAutoProxyCreatorIntegrationTests), which will remain in .testsuite due to broad-ranging dependencies
This commit is contained in:
Chris Beams
2008-12-19 21:58:42 +00:00
parent 2d37eb722b
commit be53a80657
137 changed files with 703 additions and 345 deletions

View File

@@ -0,0 +1,18 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="annotationBindingAspect" ref="testAspect">
<aop:around pointcut="@annotation(testAnnotation)" method="doWithAnnotation"/>
</aop:aspect>
</aop:config>
<bean id="testAspect" class="org.springframework.aop.aspectj.autoproxy.AnnotationBindingTestAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.autoproxy.AnnotatedTestBeanImpl"/>
</beans>

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AnnotationBindingTests {
private AnnotatedTestBean testBean;
@Before
public void setUp() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
testBean = (AnnotatedTestBean) ctx.getBean("testBean");
}
@Test
public void testAnnotationBindingInAroundAdvice() {
assertEquals("this value", testBean.doThis());
assertEquals("that value", testBean.doThat());
}
@Test
public void testNoMatchingWithoutAnnotationPresent() {
assertEquals("doTheOther", testBean.doTheOther());
}
}

View File

@@ -0,0 +1,22 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:advisor advice-ref="testInterceptor" pointcut-ref="myPointcut"/>
</aop:config>
<bean id="testInterceptor" class="org.springframework.aop.aspectj.autoproxy.TestMethodInterceptor"/>
<bean id="myPointcut" class="org.springframework.aop.support.annotation.AnnotationMatchingPointcut" factory-method="forMethodAnnotation">
<constructor-arg value="org.springframework.aop.aspectj.autoproxy.TestAnnotation"/>
</bean>
<bean id="testAspect" class="org.springframework.aop.aspectj.autoproxy.AnnotationBindingTestAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.autoproxy.AnnotatedTestBeanImpl"/>
</beans>

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static org.junit.Assert.assertEquals;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AnnotationPointcutTests {
private AnnotatedTestBean testBean;
@Before
public void setUp() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
testBean = (AnnotatedTestBean) ctx.getBean("testBean");
}
@Test
public void testAnnotationBindingInAroundAdvice() {
assertEquals("this value", testBean.doThis());
}
@Test
public void testNoMatchingWithoutAnnotationPresent() {
assertEquals("doTheOther", testBean.doTheOther());
}
}
class TestMethodInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
return "this value";
}
}

View File

@@ -0,0 +1,20 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect ref="interfaceExtendingAspect">
<aop:pointcut id="anyOperation"
expression="execution(* *(..))"/>
<aop:around pointcut-ref="anyOperation" method="increment"/>
</aop:aspect>
</aop:config>
<bean id="testBean" class="org.springframework.beans.TestBean" />
<bean id="interfaceExtendingAspect"
class="org.springframework.aop.aspectj.autoproxy.InterfaceExtendingAspect"/>
</beans>

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static org.junit.Assert.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.ITestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Test for ensuring the aspects aren't advised. See SPR-3893 for more details.
*
* @author Ramnivas Laddad
* @author Chris Beams
*/
public final class AspectImplementingInterfaceTests {
@Test
public void testProxyCreation() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
ITestBean testBean = (ITestBean) ctx.getBean("testBean");
AnInterface interfaceExtendingAspect = (AnInterface) ctx.getBean("interfaceExtendingAspect");
assertTrue(testBean instanceof Advised);
assertFalse(interfaceExtendingAspect instanceof Advised);
}
}
interface AnInterface {
public void interfaceMethod();
}
class InterfaceExtendingAspect implements AnInterface {
public void increment(ProceedingJoinPoint pjp) throws Throwable {
pjp.proceed();
}
public void interfaceMethod() {
}
}

View File

@@ -0,0 +1,28 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator">
<property name="customTargetSourceCreators">
<bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator"/>
</property>
</bean>
<bean class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue">
<property name="multiple" value="2"/>
</bean>
<bean id="adrianParent" abstract="true">
<property name="name" value="adrian"/>
</bean>
<!-- parent="adrianParent" -->
<bean id="adrian" class="org.springframework.aop.aspectj.autoproxy.LazyTestBean" lazy-init="true">
<property name="age" value="34"/>
<property name="name" value="adrian"/>
</bean>
</beans>

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Rod Johnson
* @author Rob Harrop
* @author Chris Beams
*/
public final class AspectJAutoProxyCreatorAndLazyInitTargetSourceTests {
@Test
public void testAdrian() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
ITestBean adrian = (ITestBean) ctx.getBean("adrian");
assertEquals(0, LazyTestBean.instantiations);
assertNotNull(adrian);
adrian.getAge();
assertEquals(68, adrian.getAge());
assertEquals(1, LazyTestBean.instantiations);
}
}
class LazyTestBean extends TestBean {
public static int instantiations;
public LazyTestBean() {
++instantiations;
}
}

View File

@@ -0,0 +1,39 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!--
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
-->
<aop:aspectj-autoproxy/>
<bean class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue">
<property name="multiple" value="2"/>
</bean>
<bean class="org.springframework.aop.aspectj.autoproxy.DummyAspect"/>
<bean class="org.springframework.aop.aspectj.autoproxy.DummyAspectWithParameter"/>
<bean id="adrianParent" abstract="true">
<property name="name" value="adrian"/>
</bean>
<bean id="adrian" class="org.springframework.beans.TestBean" parent="adrianParent">
<property name="age" value="34"/>
</bean>
<bean id="adrian2Parent" class="org.springframework.beans.TestBean" abstract="true">
<property name="name" value="adrian"/>
</bean>
<bean id="factoryBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="adrian"/>
<property name="targetMethod" value="toString"/>
</bean>
</beans>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean id="aspect" class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue">
<property name="multiple" value="3"/>
</bean>
<bean id="adrian" class="org.springframework.beans.TestBean">
<property name="name" value="Adrian"/>
<property name="age" value="34"/>
</bean>
<bean id="adrian2" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="Adrian"/>
<property name="age" value="34"/>
</bean>
<bean id="i21" class="org.springframework.beans.NestedTestBean" scope="prototype">
<property name="company" value="i21"/>
</bean>
<bean id="advisor" class="org.springframework.aop.aspectj.autoproxy.TestBeanAdvisor"/>
</beans>

View File

@@ -0,0 +1,29 @@
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"
default-lazy-init="true">
<aop:aspectj-autoproxy/>
<bean class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue">
<property name="multiple" value="2"/>
</bean>
<bean id="factoryBean" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="adrian"/>
<property name="targetMethod" value="toString"/>
</bean>
<bean id="adrianParent" abstract="true">
<property name="name" value="adrian"/>
</bean>
<bean id="adrian" class="org.springframework.beans.TestBean" parent="adrianParent">
<property name="age" value="34"/>
</bean>
<bean id="adrian2Parent" class="org.springframework.aop.aspectj.autoproxy.DummyFactoryBean" abstract="true"/>
</beans>

View File

@@ -0,0 +1,16 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!--
<bean
class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

View File

@@ -0,0 +1,25 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!--
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
-->
<aop:aspectj-autoproxy/>
<bean class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue">
<property name="multiple" value="2"/>
</bean>
<bean class="org.springframework.aop.aspectj.autoproxy.IncreaseReturnValue"/>
<bean id="adrian" class="org.springframework.beans.TestBean">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean class="test.aspect.PerTargetAspect"
scope="prototype">
<property name="order" value="5"/>
</bean>
<bean id="adrian" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
<bean id="juergen" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="juergen"/>
<property name="age" value="30"/>
</bean>
</beans>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean class="test.aspect.PerThisAspect" scope="prototype"/>
<bean id="adrian" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>

View File

@@ -0,0 +1,15 @@
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="retryAspect" class="org.springframework.aop.aspectj.autoproxy.RetryAspect"/>
<bean id="unreliableBean" class="org.springframework.aop.aspectj.autoproxy.UnreliableBean"/>
</beans>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean id="aspect" class="test.aspect.TwoAdviceAspect"/>
<bean id="adrian" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean id="aspect" class="test.aspect.TwoAdviceAspect"
scope="prototype"/>
<bean id="adrian" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>

View File

@@ -0,0 +1,26 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy>
<aop:include name="aspectOne"/>
</aop:aspectj-autoproxy>
<bean id="aspectOne" class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue" >
<property name="multiple" value="2" />
</bean>
<bean id="aspectTwo"
class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue" >
<property name="multiple" value="2" />
</bean>
<bean id="adrian" class="org.springframework.beans.TestBean">
<property name="name" value="adrian" />
<property name="age" value="34" />
</bean>
</beans>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/>
<bean id="aspect" class="org.springframework.aop.aspectj.autoproxy.AdviceUsingThisJoinPoint"/>
<bean id="adrian" class="org.springframework.beans.TestBean" scope="prototype">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>

View File

@@ -0,0 +1,584 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static java.lang.String.format;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.aspectj.annotation.AspectMetadata;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.aop.framework.ProxyConfig;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
import org.springframework.beans.INestedTestBean;
import org.springframework.beans.ITestBean;
import org.springframework.beans.NestedTestBean;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.NestedRuntimeException;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StopWatch;
/**
* Integration tests for AspectJ auto-proxying. Includes mixing with Spring AOP Advisors
* to demonstrate that existing autoproxying contract is honoured.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AspectJAutoProxyCreatorTests {
private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class);
@Test
public void testAspectsAreApplied() {
ClassPathXmlApplicationContext bf = newContext("aspects.xml");
ITestBean tb = (ITestBean) bf.getBean("adrian");
assertEquals(68, tb.getAge());
MethodInvokingFactoryBean factoryBean = (MethodInvokingFactoryBean) bf.getBean("&factoryBean");
assertTrue(AopUtils.isAopProxy(factoryBean.getTargetObject()));
assertEquals(68, ((ITestBean) factoryBean.getTargetObject()).getAge());
}
@Test
public void testMultipleAspectsWithParameterApplied() {
ClassPathXmlApplicationContext bf = newContext("aspects.xml");
ITestBean tb = (ITestBean) bf.getBean("adrian");
tb.setAge(10);
assertEquals(20, tb.getAge());
}
@Test
public void testAspectsAreAppliedInDefinedOrder() {
ClassPathXmlApplicationContext bf = newContext("aspectsWithOrdering.xml");
ITestBean tb = (ITestBean) bf.getBean("adrian");
assertEquals(71, tb.getAge());
}
@Test
public void testAspectsAndAdvisorAreApplied() {
ClassPathXmlApplicationContext ac = newContext("aspectsPlusAdvisor.xml");
ITestBean shouldBeWeaved = (ITestBean) ac.getBean("adrian");
doTestAspectsAndAdvisorAreApplied(ac, shouldBeWeaved);
}
@Test
public void testAspectsAndAdvisorAppliedToPrototypeIsFastEnough() {
if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
// Skip this test: Trace logging blows the time limit.
return;
}
ClassPathXmlApplicationContext ac = newContext("aspectsPlusAdvisor.xml");
StopWatch sw = new StopWatch();
sw.start("prototype");
for (int i = 0; i < 10000; i++) {
ITestBean shouldBeWeaved = (ITestBean) ac.getBean("adrian2");
if (i < 10) {
doTestAspectsAndAdvisorAreApplied(ac, shouldBeWeaved);
}
}
sw.stop();
System.out.println(sw.getTotalTimeMillis());
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000);
}
@Test
public void testAspectsAndAdvisorNotAppliedToPrototypeIsFastEnough() {
if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
// Skip this test: Trace logging blows the time limit.
return;
}
ClassPathXmlApplicationContext ac = newContext("aspectsPlusAdvisor.xml");
StopWatch sw = new StopWatch();
sw.start("prototype");
for (int i = 0; i < 100000; i++) {
INestedTestBean shouldNotBeWeaved = (INestedTestBean) ac.getBean("i21");
if (i < 10) {
assertFalse(AopUtils.isAopProxy(shouldNotBeWeaved));
}
}
sw.stop();
System.out.println(sw.getTotalTimeMillis());
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 3000);
}
@Test
public void testAspectsAndAdvisorNotAppliedToManySingletonsIsFastEnough() {
if (factoryLog.isTraceEnabled() || factoryLog.isDebugEnabled()) {
// Skip this test: Trace logging blows the time limit.
return;
}
GenericApplicationContext ac = new GenericApplicationContext();
new XmlBeanDefinitionReader(ac).loadBeanDefinitions(
new ClassPathResource(qName("aspectsPlusAdvisor.xml"), getClass()));
for (int i = 0; i < 10000; i++) {
ac.registerBeanDefinition("singleton" + i, new RootBeanDefinition(NestedTestBean.class));
}
StopWatch sw = new StopWatch();
sw.start("singleton");
ac.refresh();
sw.stop();
System.out.println(sw.getTotalTimeMillis());
assertTrue("Singleton creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 4000);
}
@Test
public void testAspectsAndAdvisorAreAppliedEvenIfComingFromParentFactory() {
ClassPathXmlApplicationContext ac = newContext("aspectsPlusAdvisor.xml");
GenericApplicationContext childAc = new GenericApplicationContext(ac);
// Create a child factory with a bean that should be weaved
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
bd.getPropertyValues().addPropertyValue(new PropertyValue("name", "Adrian")).
addPropertyValue(new PropertyValue("age", new Integer(34)));
childAc.registerBeanDefinition("adrian2", bd);
// Register the advisor auto proxy creator with subclass
childAc.registerBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class.getName(),
new RootBeanDefinition(AnnotationAwareAspectJAutoProxyCreator.class));
childAc.refresh();
ITestBean beanFromChildContextThatShouldBeWeaved = (ITestBean) childAc.getBean("adrian2");
//testAspectsAndAdvisorAreApplied(childAc, (ITestBean) ac.getBean("adrian"));
doTestAspectsAndAdvisorAreApplied(childAc, beanFromChildContextThatShouldBeWeaved);
}
protected void doTestAspectsAndAdvisorAreApplied(ApplicationContext ac, ITestBean shouldBeWeaved) {
TestBeanAdvisor tba = (TestBeanAdvisor) ac.getBean("advisor");
MultiplyReturnValue mrv = (MultiplyReturnValue) ac.getBean("aspect");
assertEquals(3, mrv.getMultiple());
tba.count = 0;
mrv.invocations = 0;
assertTrue("Autoproxying must apply from @AspectJ aspect", AopUtils.isAopProxy(shouldBeWeaved));
assertEquals("Adrian", shouldBeWeaved.getName());
assertEquals(0, mrv.invocations);
assertEquals(34 * mrv.getMultiple(), shouldBeWeaved.getAge());
assertEquals("Spring advisor must be invoked", 2, tba.count);
assertEquals("Must be able to hold state in aspect", 1, mrv.invocations);
}
@Test
public void testPerThisAspect() {
ClassPathXmlApplicationContext bf = newContext("perthis.xml");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian1));
assertEquals(0, adrian1.getAge());
assertEquals(1, adrian1.getAge());
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
assertNotSame(adrian1, adrian2);
assertTrue(AopUtils.isAopProxy(adrian1));
assertEquals(0, adrian2.getAge());
assertEquals(1, adrian2.getAge());
assertEquals(2, adrian2.getAge());
assertEquals(3, adrian2.getAge());
assertEquals(2, adrian1.getAge());
}
@Test
public void testPerTargetAspect() throws SecurityException, NoSuchMethodException {
ClassPathXmlApplicationContext bf = newContext("pertarget.xml");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian1));
// Does not trigger advice or count
int explicitlySetAge = 25;
adrian1.setAge(explicitlySetAge);
assertEquals("Setter does not initiate advice", explicitlySetAge, adrian1.getAge());
// Fire aspect
AspectMetadata am = new AspectMetadata(PerTargetAspect.class, "someBean");
assertTrue(am.getPerClausePointcut().getMethodMatcher().matches(TestBean.class.getMethod("getSpouse"), null));
adrian1.getSpouse();
assertEquals("Advice has now been instantiated", 0, adrian1.getAge());
adrian1.setAge(11);
assertEquals("Any int setter increments", 2, adrian1.getAge());
adrian1.setName("Adrian");
//assertEquals("Any other setter does not increment", 2, adrian1.getAge());
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
assertNotSame(adrian1, adrian2);
assertTrue(AopUtils.isAopProxy(adrian1));
assertEquals(34, adrian2.getAge());
adrian2.getSpouse();
assertEquals("Aspect now fired", 0, adrian2.getAge());
assertEquals(1, adrian2.getAge());
assertEquals(2, adrian2.getAge());
assertEquals(3, adrian1.getAge());
}
@Test
public void testTwoAdviceAspectSingleton() {
doTestTwoAdviceAspectWith("twoAdviceAspect.xml");
}
@Test
public void testTwoAdviceAspectPrototype() {
doTestTwoAdviceAspectWith("twoAdviceAspectPrototype.xml");
}
private void doTestTwoAdviceAspectWith(String location) {
ClassPathXmlApplicationContext bf = newContext(location);
boolean aspectSingleton = bf.isSingleton("aspect");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
testPrototype(adrian1, 0);
ITestBean adrian2 = (ITestBean) bf.getBean("adrian");
assertNotSame(adrian1, adrian2);
testPrototype(adrian2, aspectSingleton ? 2 : 0);
}
@Test
public void testAdviceUsingJoinPoint() {
ClassPathXmlApplicationContext bf = newContext("usesJoinPointAspect.xml");
ITestBean adrian1 = (ITestBean) bf.getBean("adrian");
adrian1.getAge();
AdviceUsingThisJoinPoint aspectInstance = (AdviceUsingThisJoinPoint) bf.getBean("aspect");
//(AdviceUsingThisJoinPoint) Aspects.aspectOf(AdviceUsingThisJoinPoint.class);
//assertEquals("method-execution(int TestBean.getAge())",aspectInstance.getLastMethodEntered());
assertTrue(aspectInstance.getLastMethodEntered().indexOf("TestBean.getAge())") != 0);
}
@Test
public void testIncludeMechanism() {
ClassPathXmlApplicationContext bf = newContext("usesInclude.xml");
ITestBean adrian = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian));
assertEquals(68, adrian.getAge());
}
private void testPrototype(ITestBean adrian1, int start) {
assertTrue(AopUtils.isAopProxy(adrian1));
//TwoAdviceAspect twoAdviceAspect = (TwoAdviceAspect) bf.getBean(TwoAdviceAspect.class.getName());
adrian1.setName("");
assertEquals(start++, adrian1.getAge());
int newAge = 32;
adrian1.setAge(newAge);
assertEquals(start++, adrian1.getAge());
adrian1.setAge(0);
assertEquals(start++, adrian1.getAge());
}
@Test
public void testForceProxyTargetClass() {
ClassPathXmlApplicationContext bf = newContext("aspectsWithCGLIB.xml");
ProxyConfig pc = (ProxyConfig) bf.getBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
assertTrue("should be proxying classes", pc.isProxyTargetClass());
}
@Test
public void testWithAbstractFactoryBeanAreApplied() {
ClassPathXmlApplicationContext bf = newContext("aspectsWithAbstractBean.xml");
ITestBean adrian = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian));
assertEquals(68, adrian.getAge());
}
@Test
public void testRetryAspect() throws Exception {
ClassPathXmlApplicationContext bf = newContext("retryAspect.xml");
UnreliableBean bean = (UnreliableBean) bf.getBean("unreliableBean");
RetryAspect aspect = (RetryAspect) bf.getBean("retryAspect");
int attempts = bean.unreliable();
assertEquals(2, attempts);
assertEquals(2, aspect.getBeginCalls());
assertEquals(1, aspect.getRollbackCalls());
assertEquals(1, aspect.getCommitCalls());
}
/**
* Returns a new {@link ClassPathXmlApplicationContext} for the file ending in <var>fileSuffix</var>.
*/
private ClassPathXmlApplicationContext newContext(String fileSuffix) {
return new ClassPathXmlApplicationContext(qName(fileSuffix), getClass());
}
/**
* Returns the relatively qualified name for <var>fileSuffix</var>.
* e.g. for a fileSuffix='foo.xml', this method will return
* 'AspectJAutoProxyCreatorTests-foo.xml'
*/
private String qName(String fileSuffix) {
return format("%s-%s", getClass().getSimpleName(), fileSuffix);
}
}
@Aspect("pertarget(execution(* *.getSpouse()))")
class PerTargetAspect implements Ordered {
public int count;
private int order = Ordered.LOWEST_PRECEDENCE;
@Around("execution(int *.getAge())")
public int returnCountAsAge() {
return count++;
}
@Before("execution(void *.set*(int))")
public void countSetter() {
++count;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
}
@Aspect
class AdviceUsingThisJoinPoint {
private String lastEntry = "";
public String getLastMethodEntered() {
return this.lastEntry;
}
@Pointcut("execution(* *(..))")
public void methodExecution() {}
@Before("methodExecution()")
public void entryTrace(JoinPoint jp) {
this.lastEntry = jp.toString();
}
}
@Aspect
class DummyAspect {
@Around("execution(* setAge(int))")
public Object test(ProceedingJoinPoint pjp) throws Throwable {
return pjp.proceed();
}
}
@Aspect
class DummyAspectWithParameter {
@Around("execution(* setAge(int)) && args(age)")
public Object test(ProceedingJoinPoint pjp, int age) throws Throwable {
return pjp.proceed();
}
}
class DummyFactoryBean implements FactoryBean<Object> {
public Object getObject() throws Exception {
throw new UnsupportedOperationException();
}
public Class<?> getObjectType() {
throw new UnsupportedOperationException();
}
public boolean isSingleton() {
throw new UnsupportedOperationException();
}
}
@Aspect
@Order(10)
class IncreaseReturnValue {
@Around("execution(int *.getAge())")
public Object doubleReturnValue(ProceedingJoinPoint pjp) throws Throwable {
int result = (Integer) pjp.proceed();
return result + 3;
}
}
@Aspect
class MultiplyReturnValue {
private int multiple = 2;
public int invocations;
public void setMultiple(int multiple) {
this.multiple = multiple;
}
public int getMultiple() {
return this.multiple;
}
@Around("execution(int *.getAge())")
public Object doubleReturnValue(ProceedingJoinPoint pjp) throws Throwable {
++this.invocations;
int result = (Integer) pjp.proceed();
return result * this.multiple;
}
}
@Aspect
class RetryAspect {
private int beginCalls;
private int commitCalls;
private int rollbackCalls;
@Pointcut("execution(public * UnreliableBean.*(..))")
public void execOfPublicMethod() {
}
/**
* Retry Advice
*/
@Around("execOfPublicMethod()")
public Object retry(ProceedingJoinPoint jp) throws Throwable {
boolean retry = true;
Object o = null;
while (retry) {
try {
retry = false;
this.beginCalls++;
try {
o = jp.proceed();
this.commitCalls++;
}
catch (RetryableException e) {
this.rollbackCalls++;
throw e;
}
}
catch (RetryableException re) {
retry = true;
}
}
return o;
}
public int getBeginCalls() {
return this.beginCalls;
}
public int getCommitCalls() {
return this.commitCalls;
}
public int getRollbackCalls() {
return this.rollbackCalls;
}
}
@SuppressWarnings("serial")
class RetryableException extends NestedRuntimeException {
public RetryableException(String msg) {
super(msg);
}
public RetryableException(String msg, Throwable cause) {
super(msg, cause);
}
}
class UnreliableBean {
private int calls;
public int unreliable() {
this.calls++;
if (this.calls % 2 != 0) {
throw new RetryableException("foo");
}
return this.calls;
}
}
@SuppressWarnings("serial")
class TestBeanAdvisor extends StaticMethodMatcherPointcutAdvisor {
public int count;
public TestBeanAdvisor() {
setAdvice(new MethodBeforeAdvice() {
public void before(Method method, Object[] args, Object target) throws Throwable {
++count;
}
});
}
public boolean matches(Method method, Class<?> targetClass) {
return ITestBean.class.isAssignableFrom(targetClass);
}
}

View File

@@ -0,0 +1,13 @@
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="aspect" class="org.springframework.aop.aspectj.autoproxy.ExceptionHandlingAspect"/>
</beans>

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static org.junit.Assert.*;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Test;
import org.springframework.beans.ITestBean;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.io.IOException;
/**
* @author Rob Harrop
* @author Chris Beams
* @since 2.0
*/
public final class AtAspectJAfterThrowingTests {
@Test
public void testAccessThrowable() throws Exception {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
ITestBean bean = (ITestBean) ctx.getBean("testBean");
ExceptionHandlingAspect aspect = (ExceptionHandlingAspect) ctx.getBean("aspect");
assertTrue(AopUtils.isAopProxy(bean));
try {
bean.unreliableFileOperation();
}
catch (IOException e) {
//
}
assertEquals(1, aspect.handled);
assertNotNull(aspect.lastException);
}
}
@Aspect
class ExceptionHandlingAspect {
public int handled;
public IOException lastException;
@AfterThrowing(pointcut = "within(org.springframework.beans.ITestBean+)", throwing = "ex")
public void handleIOException(IOException ex) {
handled++;
lastException = ex;
}
}

View File

@@ -0,0 +1,18 @@
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="testAspect" class="org.springframework.aop.aspectj.autoproxy.AtAspectJAnnotationBindingTestAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.autoproxy.AnnotatedTestBeanImpl"/>
<bean id="arrayFactoryBean" class="org.springframework.aop.aspectj.autoproxy.ResourceArrayFactoryBean"/>
</beans>

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import static org.junit.Assert.assertEquals;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
/**
* @author Adrian Colyer
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AtAspectJAnnotationBindingTests {
private AnnotatedTestBean testBean;
private ClassPathXmlApplicationContext ctx;
@Before
public void setUp() {
ctx = new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
testBean = (AnnotatedTestBean) ctx.getBean("testBean");
}
@Test
public void testAnnotationBindingInAroundAdvice() {
assertEquals("this value doThis", testBean.doThis());
assertEquals("that value doThat", testBean.doThat());
assertEquals(2, testBean.doArray().length);
}
@Test
public void testNoMatchingWithoutAnnotationPresent() {
assertEquals("doTheOther", testBean.doTheOther());
}
@Test
public void testPointcutEvaulatedAgainstArray() {
ctx.getBean("arrayFactoryBean");
}
}
@Aspect
class AtAspectJAnnotationBindingTestAspect {
@Around("execution(* *(..)) && @annotation(testAnn)")
public Object doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnn)
throws Throwable {
String annValue = testAnn.value();
Object result = pjp.proceed();
return (result instanceof String ? annValue + " " + result : result);
}
}
class ResourceArrayFactoryBean implements FactoryBean<Object> {
@TestAnnotation("some value")
public Object getObject() throws Exception {
return new Resource[0];
}
@TestAnnotation("some value")
public Class<?> getObjectType() {
return Resource[].class;
}
public boolean isSingleton() {
return true;
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* Definitions of testing types for use in within this package.
* Wherever possible, test types should be defined local to the java
* file that makes use of them. In some cases however, a test type may
* need to be shared across tests. Such types reside here, with the
* intention of reducing the surface area of java files within this
* package. This allows developers to think about tests first, and deal
* with these second class testing artifacts on an as-needed basis.
*
* Types here should be defined as package-private top level classes in
* order to avoid needing to fully qualify, e.g.: _TestTypes$Foo.
*
* @author Chris Beams
*/
final class _TestTypes { }
/**
* @author Adrian Colyer
* @since 2.0
*/
interface AnnotatedTestBean {
String doThis();
String doThat();
String doTheOther();
String[] doArray();
}
/**
* @author Adrian Colyer
* @since 2.0
*/
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
String value() ;
}
/**
* @author Adrian Colyer
* @since 2.0
*/
class AnnotatedTestBeanImpl implements AnnotatedTestBean {
@TestAnnotation("this value")
public String doThis() {
return "doThis";
}
@TestAnnotation("that value")
public String doThat() {
return "doThat";
}
@TestAnnotation("array value")
public String[] doArray() {
return new String[] {"doThis", "doThat"};
}
// not annotated
public String doTheOther() {
return "doTheOther";
}
}
/**
* @author Adrian Colyer
*/
class AnnotationBindingTestAspect {
public String doWithAnnotation(ProceedingJoinPoint pjp, TestAnnotation testAnnotation) throws Throwable {
return testAnnotation.value();
}
}

View File

@@ -0,0 +1,32 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!--
<bean
class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
-->
<aop:aspectj-autoproxy/>
<bean
class="org.springframework.aop.aspectj.autoproxy.MultiplyReturnValue" >
<property name="multiple" value="2" />
</bean>
<bean
class="org.springframework.aop.aspectj.autoproxy.benchmark.TraceAspect" >
</bean>
<bean id="adrian" class="org.springframework.beans.TestBean">
<property name="name" value="adrian" />
<property name="age" value="34" />
</bean>
</beans>

View File

@@ -0,0 +1,39 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!--
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
-->
<aop:aspectj-autoproxy>
<!-- Explicit testing the whitespace body variant here -->
</aop:aspectj-autoproxy>
<bean class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor" >
<property name="advice" ref="multiplyReturnValueInterceptor" />
<property name="mappedName" value="getAge" />
</bean>
<bean id="multiplyReturnValueInterceptor"
class="org.springframework.aop.aspectj.autoproxy.benchmark.MultiplyReturnValueInterceptor" >
<property name="multiple" value="2" />
</bean>
<bean class="org.springframework.aop.aspectj.autoproxy.benchmark.TraceBeforeAdvice"
factory-method="advisor" />
<bean class="org.springframework.aop.aspectj.autoproxy.benchmark.TraceAfterReturningAdvice"
factory-method="advisor" />
<bean class="org.springframework.aop.aspectj.autoproxy.benchmark.TraceAspect"/>
<bean id="adrian" class="org.springframework.beans.TestBean">
<property name="name" value="adrian"/>
<property name="age" value="34"/>
</bean>
</beans>

View File

@@ -0,0 +1,278 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy.benchmark;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.beans.ITestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StopWatch;
/**
* Integration tests for AspectJ auto proxying. Includes mixing with Spring AOP
* Advisors to demonstrate that existing autoproxying contract is honoured.
*
* @author Rod Johnson
* @author Chris Beams
*/
public final class BenchmarkTests {
private static final Class<?> CLASS = BenchmarkTests.class;
private static final String ASPECTJ_CONTEXT = CLASS.getSimpleName() + "-aspectj.xml";
private static final String SPRING_AOP_CONTEXT = CLASS.getSimpleName() + "-springAop.xml";
@Test
public void testRepeatedAroundAdviceInvocationsWithAspectJ() {
testRepeatedAroundAdviceInvocations(ASPECTJ_CONTEXT, getCount(), "AspectJ");
}
@Test
public void testRepeatedAroundAdviceInvocationsWithSpringAop() {
testRepeatedAroundAdviceInvocations(SPRING_AOP_CONTEXT, getCount(), "Spring AOP");
}
@Test
public void testRepeatedBeforeAdviceInvocationsWithAspectJ() {
testBeforeAdviceWithoutJoinPoint(ASPECTJ_CONTEXT, getCount(), "AspectJ");
}
@Test
public void testRepeatedBeforeAdviceInvocationsWithSpringAop() {
testBeforeAdviceWithoutJoinPoint(SPRING_AOP_CONTEXT, getCount(), "Spring AOP");
}
@Test
public void testRepeatedAfterReturningAdviceInvocationsWithAspectJ() {
testAfterReturningAdviceWithoutJoinPoint(ASPECTJ_CONTEXT, getCount(), "AspectJ");
}
@Test
public void testRepeatedAfterReturningAdviceInvocationsWithSpringAop() {
testAfterReturningAdviceWithoutJoinPoint(SPRING_AOP_CONTEXT, getCount(), "Spring AOP");
}
@Test
public void testRepeatedMixWithAspectJ() {
testMix(ASPECTJ_CONTEXT, getCount(), "AspectJ");
}
@Test
public void testRepeatedMixWithSpringAop() {
testMix(SPRING_AOP_CONTEXT, getCount(), "Spring AOP");
}
/**
* Change the return number to a higher number to make this test useful.
*/
protected int getCount() {
return 10;
}
private long testRepeatedAroundAdviceInvocations(String file, int howmany, String technology) {
ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file, CLASS);
StopWatch sw = new StopWatch();
sw.start(howmany + " repeated around advice invocations with " + technology);
ITestBean adrian = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian));
assertEquals(68, adrian.getAge());
for (int i = 0; i < howmany; i++) {
adrian.getAge();
}
sw.stop();
System.out.println(sw.prettyPrint());
return sw.getLastTaskTimeMillis();
}
private long testBeforeAdviceWithoutJoinPoint(String file, int howmany, String technology) {
ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file, CLASS);
StopWatch sw = new StopWatch();
sw.start(howmany + " repeated before advice invocations with " + technology);
ITestBean adrian = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian));
Advised a = (Advised) adrian;
assertTrue(a.getAdvisors().length >= 3);
assertEquals("adrian", adrian.getName());
for (int i = 0; i < howmany; i++) {
adrian.getName();
}
sw.stop();
System.out.println(sw.prettyPrint());
return sw.getLastTaskTimeMillis();
}
private long testAfterReturningAdviceWithoutJoinPoint(String file, int howmany, String technology) {
ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file, CLASS);
StopWatch sw = new StopWatch();
sw.start(howmany + " repeated after returning advice invocations with " + technology);
ITestBean adrian = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian));
Advised a = (Advised) adrian;
assertTrue(a.getAdvisors().length >= 3);
// Hits joinpoint
adrian.setAge(25);
for (int i = 0; i < howmany; i++) {
adrian.setAge(i);
}
sw.stop();
System.out.println(sw.prettyPrint());
return sw.getLastTaskTimeMillis();
}
private long testMix(String file, int howmany, String technology) {
ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext(file, CLASS);
StopWatch sw = new StopWatch();
sw.start(howmany + " repeated mixed invocations with " + technology);
ITestBean adrian = (ITestBean) bf.getBean("adrian");
assertTrue(AopUtils.isAopProxy(adrian));
Advised a = (Advised) adrian;
assertTrue(a.getAdvisors().length >= 3);
for (int i = 0; i < howmany; i++) {
// Hit all 3 joinpoints
adrian.getAge();
adrian.getName();
adrian.setAge(i);
// Invoke three non-advised methods
adrian.getDoctor();
adrian.getLawyer();
adrian.getSpouse();
}
sw.stop();
System.out.println(sw.prettyPrint());
return sw.getLastTaskTimeMillis();
}
}
class MultiplyReturnValueInterceptor implements MethodInterceptor {
private int multiple = 2;
public int invocations;
public void setMultiple(int multiple) {
this.multiple = multiple;
}
public int getMultiple() {
return this.multiple;
}
public Object invoke(MethodInvocation mi) throws Throwable {
++invocations;
int result = (Integer) mi.proceed();
return result * this.multiple;
}
}
class TraceAfterReturningAdvice implements AfterReturningAdvice {
public int afterTakesInt;
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
++afterTakesInt;
}
public static Advisor advisor() {
return new DefaultPointcutAdvisor(
new StaticMethodMatcherPointcut() {
public boolean matches(Method method, Class<?> targetClass) {
return method.getParameterTypes().length == 1 &&
method.getParameterTypes()[0].equals(Integer.class);
}
},
new TraceAfterReturningAdvice());
}
}
@Aspect
class TraceAspect {
public int beforeStringReturn;
public int afterTakesInt;
@Before("execution(String *.*(..))")
public void traceWithoutJoinPoint() {
++beforeStringReturn;
}
@AfterReturning("execution(void *.*(int))")
public void traceWithoutJoinPoint2() {
++afterTakesInt;
}
}
class TraceBeforeAdvice implements MethodBeforeAdvice {
public int beforeStringReturn;
public void before(Method method, Object[] args, Object target) throws Throwable {
++beforeStringReturn;
}
public static Advisor advisor() {
return new DefaultPointcutAdvisor(
new StaticMethodMatcherPointcut() {
public boolean matches(Method method, Class<?> targetClass) {
return method.getReturnType().equals(String.class);
}
},
new TraceBeforeAdvice());
}
}

View File

@@ -0,0 +1,88 @@
/**
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.autoproxy.spr3064;
import static org.junit.Assert.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class SPR3064Tests {
private Service service;
@Test
public void testServiceIsAdvised() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + ".xml", getClass());
service = (Service) ctx.getBean("service");
try {
this.service.serveMe();
fail("service operation has not been advised by transaction interceptor");
}
catch(RuntimeException ex) {
assertEquals("advice invoked",ex.getMessage());
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface Transaction {
}
@Aspect
class TransactionInterceptor {
@Around(value="execution(* *..Service.*(..)) && @annotation(transaction)")
public Object around(ProceedingJoinPoint pjp, Transaction transaction) throws Throwable {
throw new RuntimeException("advice invoked");
//return pjp.proceed();
}
}
interface Service {
void serveMe();
}
class ServiceImpl implements Service {
@Transaction
public void serveMe() {
}
}

View File

@@ -0,0 +1,14 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="service" class="org.springframework.aop.aspectj.autoproxy.spr3064.ServiceImpl"/>
<bean id="transactionInterceptor" class="org.springframework.aop.aspectj.autoproxy.spr3064.TransactionInterceptor"/>
</beans>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="counterAspect" class="org.springframework.aop.aspectj.generic.CounterAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.generic.GenericReturnTypeVariationClass"/>
</beans>

View File

@@ -0,0 +1,175 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.generic;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Collection;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.beans.Employee;
/**
* Tests ensuring that after-returning advice for generic parameters bound to
* the advice and the return type follow AspectJ semantics.
*
* <p>See SPR-3628 for more details.
*
* @author Ramnivas Laddad
* @author Chris Beams
*/
public final class AfterReturningGenericTypeMatchingTests {
private GenericReturnTypeVariationClass testBean;
private CounterAspect counterAspect;
@Before
public void setUp() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
counterAspect = (CounterAspect) ctx.getBean("counterAspect");
counterAspect.reset();
testBean = (GenericReturnTypeVariationClass) ctx.getBean("testBean");
}
@Test
public void testReturnTypeExactMatching() {
testBean.getStrings();
assertEquals(1, counterAspect.getStringsInvocationsCount);
assertEquals(0, counterAspect.getIntegersInvocationsCount);
counterAspect.reset();
testBean.getIntegers();
assertEquals(0, counterAspect.getStringsInvocationsCount);
assertEquals(1, counterAspect.getIntegersInvocationsCount);
}
@Test
public void testReturnTypeRawMatching() {
testBean.getStrings();
assertEquals(1, counterAspect.getRawsInvocationsCount);
counterAspect.reset();
testBean.getIntegers();
assertEquals(1, counterAspect.getRawsInvocationsCount);
}
@Test
public void testReturnTypeUpperBoundMatching() {
testBean.getIntegers();
assertEquals(1, counterAspect.getNumbersInvocationsCount);
}
@Test
public void testReturnTypeLowerBoundMatching() {
testBean.getTestBeans();
assertEquals(1, counterAspect.getTestBeanInvocationsCount);
counterAspect.reset();
testBean.getEmployees();
assertEquals(0, counterAspect.getTestBeanInvocationsCount);
}
}
class GenericReturnTypeVariationClass {
public Collection<String> getStrings() {
return new ArrayList<String>();
}
public Collection<Integer> getIntegers() {
return new ArrayList<Integer>();
}
public Collection<TestBean> getTestBeans() {
return new ArrayList<TestBean>();
}
public Collection<Employee> getEmployees() {
return new ArrayList<Employee>();
}
}
@Aspect
class CounterAspect {
int getRawsInvocationsCount;
int getStringsInvocationsCount;
int getIntegersInvocationsCount;
int getNumbersInvocationsCount;
int getTestBeanInvocationsCount;
@Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericReturnTypeVariationClass.*(..))")
public void anyTestMethod() {
}
@AfterReturning(pointcut = "anyTestMethod()", returning = "ret")
public void incrementGetRawsInvocationsCount(Collection<?> ret) {
getRawsInvocationsCount++;
}
@AfterReturning(pointcut = "anyTestMethod()", returning = "ret")
public void incrementGetStringsInvocationsCount(Collection<String> ret) {
getStringsInvocationsCount++;
}
@AfterReturning(pointcut = "anyTestMethod()", returning = "ret")
public void incrementGetIntegersInvocationsCount(Collection<Integer> ret) {
getIntegersInvocationsCount++;
}
@AfterReturning(pointcut = "anyTestMethod()", returning = "ret")
public void incrementGetNumbersInvocationsCount(Collection<? extends Number> ret) {
getNumbersInvocationsCount++;
}
@AfterReturning(pointcut = "anyTestMethod()", returning = "ret")
public void incrementTestBeanInvocationsCount(Collection<? super TestBean> ret) {
getTestBeanInvocationsCount++;
}
public void reset() {
getRawsInvocationsCount = 0;
getStringsInvocationsCount = 0;
getIntegersInvocationsCount = 0;
getNumbersInvocationsCount = 0;
getTestBeanInvocationsCount = 0;
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id="counterAspect" class="org.springframework.aop.aspectj.generic.GenericCounterAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.generic.DerivedStringParameterizedClass"/>
</beans>

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.generic;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
/**
* Tests for AspectJ pointcut expression matching when working with bridge methods.
*
* <p>This class focuses on class proxying.
*
* <p>See GenericBridgeMethodMatchingTests for more details.
*
* @author Ramnivas Laddad
* @author Chris Beams
*/
public final class GenericBridgeMethodMatchingClassProxyTests extends GenericBridgeMethodMatchingTests {
@Test
public void testGenericDerivedInterfaceMethodThroughClass() {
((DerivedStringParameterizedClass) testBean).genericDerivedInterfaceMethod("");
assertEquals(1, counterAspect.count);
}
@Test
public void testGenericBaseInterfaceMethodThroughClass() {
((DerivedStringParameterizedClass) testBean).genericBaseInterfaceMethod("");
assertEquals(1, counterAspect.count);
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="false"/>
<bean id="counterAspect" class="org.springframework.aop.aspectj.generic.GenericCounterAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.generic.DerivedStringParameterizedClass"/>
</beans>

View File

@@ -0,0 +1,108 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.generic;
import static org.junit.Assert.*;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Tests for AspectJ pointcut expression matching when working with bridge methods.
*
* <p>Depending on the caller's static type either the bridge method or the user-implemented method
* gets called as the way into the proxy. Therefore, we need tests for calling a bean with
* static type set to type with generic method and to type with specific non-generic implementation.
*
* <p>This class focuses on JDK proxy, while a subclass, GenericBridgeMethodMatchingClassProxyTests,
* focuses on class proxying.
*
* See SPR-3556 for more details.
*
* @author Ramnivas Laddad
* @author Chris Beams
*/
public class GenericBridgeMethodMatchingTests {
protected DerivedInterface<String> testBean;
protected GenericCounterAspect counterAspect;
@SuppressWarnings("unchecked")
@org.junit.Before
public void setUp() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
counterAspect = (GenericCounterAspect) ctx.getBean("counterAspect");
counterAspect.count = 0;
testBean = (DerivedInterface<String>) ctx.getBean("testBean");
}
@Test
public void testGenericDerivedInterfaceMethodThroughInterface() {
testBean.genericDerivedInterfaceMethod("");
assertEquals(1, counterAspect.count);
}
@Test
public void testGenericBaseInterfaceMethodThroughInterface() {
testBean.genericBaseInterfaceMethod("");
assertEquals(1, counterAspect.count);
}
}
interface BaseInterface<T> {
void genericBaseInterfaceMethod(T t);
}
interface DerivedInterface<T> extends BaseInterface<T> {
public void genericDerivedInterfaceMethod(T t);
}
class DerivedStringParameterizedClass implements DerivedInterface<String> {
public void genericDerivedInterfaceMethod(String t) {
}
public void genericBaseInterfaceMethod(String t) {
}
}
@Aspect
class GenericCounterAspect {
public int count;
@Before("execution(* *..BaseInterface+.*(..))")
public void increment() {
count++;
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="counterAspect" class="org.springframework.aop.aspectj.generic.GenericParameterMatchingTests$CounterAspect"/>
<bean id="testBean" class="org.springframework.aop.aspectj.generic.GenericParameterMatchingTests$GenericImpl"/>
</beans>

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.aspectj.generic;
import static org.junit.Assert.assertEquals;
import java.util.Collection;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Tests that poitncut matching is correct with generic method parameter.
* See SPR-3904 for more details.
*
* @author Ramnivas Laddad
* @author Chris Beams
*/
public final class GenericParameterMatchingTests {
private CounterAspect counterAspect;
private GenericInterface<String> testBean;
@SuppressWarnings("unchecked")
@org.junit.Before
public void setUp() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
counterAspect = (CounterAspect) ctx.getBean("counterAspect");
counterAspect.reset();
testBean = (GenericInterface<String>) ctx.getBean("testBean");
}
@Test
public void testGenericInterfaceGenericArgExecution() {
testBean.save("");
assertEquals(1, counterAspect.genericInterfaceGenericArgExecutionCount);
}
@Test
public void testGenericInterfaceGenericCollectionArgExecution() {
testBean.saveAll(null);
assertEquals(1, counterAspect.genericInterfaceGenericCollectionArgExecutionCount);
}
@Test
public void testGenericInterfaceSubtypeGenericCollectionArgExecution() {
testBean.saveAll(null);
assertEquals(1, counterAspect.genericInterfaceSubtypeGenericCollectionArgExecutionCount);
}
static interface GenericInterface<T> {
public void save(T bean);
public void saveAll(Collection<T> beans);
}
static class GenericImpl<T> implements GenericInterface<T> {
public void save(T bean) {
}
public void saveAll(Collection<T> beans) {
}
}
@Aspect
static class CounterAspect {
int genericInterfaceGenericArgExecutionCount;
int genericInterfaceGenericCollectionArgExecutionCount;
int genericInterfaceSubtypeGenericCollectionArgExecutionCount;
public void reset() {
genericInterfaceGenericArgExecutionCount = 0;
genericInterfaceGenericCollectionArgExecutionCount = 0;
genericInterfaceSubtypeGenericCollectionArgExecutionCount = 0;
}
@Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericParameterMatchingTests.GenericInterface.save(..))")
public void genericInterfaceGenericArgExecution() {}
@Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericParameterMatchingTests.GenericInterface.saveAll(..))")
public void GenericInterfaceGenericCollectionArgExecution() {}
@Pointcut("execution(* org.springframework.aop.aspectj.generic.GenericParameterMatchingTests.GenericInterface+.saveAll(..))")
public void genericInterfaceSubtypeGenericCollectionArgExecution() {}
@Before("genericInterfaceGenericArgExecution()")
public void incrementGenericInterfaceGenericArgExecution() {
genericInterfaceGenericArgExecutionCount++;
}
@Before("GenericInterfaceGenericCollectionArgExecution()")
public void incrementGenericInterfaceGenericCollectionArgExecution() {
genericInterfaceGenericCollectionArgExecutionCount++;
}
@Before("genericInterfaceSubtypeGenericCollectionArgExecution()")
public void incrementGenericInterfaceSubtypeGenericCollectionArgExecution() {
genericInterfaceSubtypeGenericCollectionArgExecutionCount++;
}
}
}

View File

@@ -0,0 +1,26 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:pointcut id="pc" expression="execution(* getAge())"/>
<aop:before pointcut-ref="pc" method="myBeforeAdvice" returning="age" />
</aop:aspect>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,27 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:pointcut id="pc" expression="execution(* getAge())"/>
<aop:before pointcut-ref="pc" method="myBeforeAdvice" />
<aop:after pointcut-ref="pc" method="myAfterAdvice" />
<aop:after-returning pointcut-ref="pc" method="myAfterReturningAdvice" returning="age"/>
<aop:after-throwing pointcut-ref="pc" method="myAfterThrowingAdvice" throwing="ex"/>
<aop:around pointcut-ref="pc" method="myAroundAdvice"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.xml.sax.SAXParseException;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AopNamespaceHandlerAdviceTypeTests {
@Test
public void testParsingOfAdviceTypes() {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-ok.xml", getClass());
}
@Test
public void testParsingOfAdviceTypesWithError() {
try {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-error.xml", getClass());
fail("Expected BeanDefinitionStoreException");
}
catch (BeanDefinitionStoreException ex) {
assertTrue(ex.contains(SAXParseException.class));
}
}
}

View File

@@ -0,0 +1,23 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:before pointcut="execution(* setAge(..)) and args(age) and this(bean)"
method="mySetAgeAdvice" arg-names="age bean"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,23 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:before pointcut="execution(* setAge(..)) and args(age) and this(bean)"
method="mySetAgeAdvice" arg-names="age,bean"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AopNamespaceHandlerArgNamesTests {
@Test
public void testArgNamesOK() {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-ok.xml", getClass());
}
@Test
public void testArgNamesError() {
try {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-error.xml", getClass());
fail("Expected BeanCreationException");
}
catch (BeanCreationException ex) {
assertTrue(ex.contains(IllegalArgumentException.class));
}
}
}

View File

@@ -0,0 +1,30 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config proxy-target-class="true">
<aop:pointcut id="getNameCalls" expression="execution(* getName(..)) and within(*..ITestBean+)"/>
<aop:advisor id="getAgeAdvisor" pointcut="execution(* *..ITestBean.getAge(..))" advice-ref="getAgeCounter"/>
<aop:advisor id="getNameAdvisor" pointcut-ref="getNameCalls" advice-ref="getNameCounter"/>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:pointcut id="setCalls" expression="execution(* *..ITestBean.set*(..))"/>
<aop:before pointcut="execution(* *..ITestBean.set*(..))" method="myBeforeAdvice"/>
<aop:after pointcut-ref="setCalls" method="myAfterAdvice"/>
<aop:around pointcut-ref="setCalls" method="myAroundAdvice"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.aop.config;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
/**
* @author Rob Harrop
* @author Chris Beams
*/
public final class AopNamespaceHandlerProxyTargetClassTests extends AopNamespaceHandlerTests {
@Test
public void testIsClassProxy() {
ITestBean bean = getTestBean();
assertTrue("Should be a CGLIB proxy", AopUtils.isCglibProxy(bean));
}
}

View File

@@ -0,0 +1,22 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:after pointcut="execution(int getAge(..))" method="myAfterAdvice" returning="age"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,22 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:after-returning pointcut="execution(int getAge(..))" method="myAfterReturningAdvice" returning="age"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.xml.sax.SAXParseException;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AopNamespaceHandlerReturningTests {
@Test
public void testReturningOnReturningAdvice() {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-ok.xml", getClass());
}
@Test
public void testParseReturningOnOtherAdviceType() {
try {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-error.xml", getClass());
fail("Expected BeanDefinitionStoreException");
}
catch (BeanDefinitionStoreException ex) {
assertTrue(ex.contains(SAXParseException.class));
}
}
}

View File

@@ -0,0 +1,30 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:pointcut id="getNameCalls" expression="execution(* getName(..)) and within(*..ITestBean+)"/>
<aop:advisor id="getAgeAdvisor" pointcut="execution(* *..ITestBean.getAge(..))" advice-ref="getAgeCounter"/>
<aop:advisor id="getNameAdvisor" pointcut-ref="getNameCalls" advice-ref="getNameCounter"/>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:pointcut id="setCalls" expression="execution(* *..ITestBean.set*(..))"/>
<aop:before pointcut="execution(* *..ITestBean.set*(..))" method="myBeforeAdvice"/>
<aop:after pointcut-ref="setCalls" method="myAfterAdvice"/>
<aop:around pointcut-ref="setCalls" method="myAroundAdvice"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import static org.junit.Assert.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.advice.CountingBeforeAdvice;
/**
* Unit tests for aop namespace.
*
* @author Rob Harrop
* @author Chris Beams
*/
public class AopNamespaceHandlerTests {
private ApplicationContext context;
@Before
public void setUp() {
this.context =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
}
@Test
public void testIsProxy() throws Exception {
ITestBean bean = getTestBean();
assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean));
// check the advice details
Advised advised = (Advised) bean;
Advisor[] advisors = advised.getAdvisors();
assertTrue("Advisors should not be empty", advisors.length > 0);
}
@Test
public void testAdviceInvokedCorrectly() throws Exception {
CountingBeforeAdvice getAgeCounter = (CountingBeforeAdvice) this.context.getBean("getAgeCounter");
CountingBeforeAdvice getNameCounter = (CountingBeforeAdvice) this.context.getBean("getNameCounter");
ITestBean bean = getTestBean();
assertEquals("Incorrect initial getAge count", 0, getAgeCounter.getCalls("getAge"));
assertEquals("Incorrect initial getName count", 0, getNameCounter.getCalls("getName"));
bean.getAge();
assertEquals("Incorrect getAge count on getAge counter", 1, getAgeCounter.getCalls("getAge"));
assertEquals("Incorrect getAge count on getName counter", 0, getNameCounter.getCalls("getAge"));
bean.getName();
assertEquals("Incorrect getName count on getName counter", 1, getNameCounter.getCalls("getName"));
assertEquals("Incorrect getName count on getAge counter", 0, getAgeCounter.getCalls("getName"));
}
@Test
public void testAspectApplied() throws Exception {
ITestBean testBean = getTestBean();
CountingAspectJAdvice advice = (CountingAspectJAdvice) this.context.getBean("countingAdvice");
assertEquals("Incorrect before count", 0, advice.getBeforeCount());
assertEquals("Incorrect after count", 0, advice.getAfterCount());
testBean.setName("Sally");
assertEquals("Incorrect before count", 1, advice.getBeforeCount());
assertEquals("Incorrect after count", 1, advice.getAfterCount());
testBean.getName();
assertEquals("Incorrect before count", 1, advice.getBeforeCount());
assertEquals("Incorrect after count", 1, advice.getAfterCount());
}
protected ITestBean getTestBean() {
return (ITestBean) this.context.getBean("testBean");
}
}
class CountingAspectJAdvice {
private int beforeCount;
private int afterCount;
private int aroundCount;
public void myBeforeAdvice() throws Throwable {
this.beforeCount++;
}
public void myAfterAdvice() throws Throwable {
this.afterCount++;
}
public void myAroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
this.aroundCount++;
pjp.proceed();
}
public void myAfterReturningAdvice(int age) {
this.afterCount++;
}
public void myAfterThrowingAdvice(RuntimeException ex) {
this.afterCount++;
}
public void mySetAgeAdvice(int newAge, ITestBean bean) {
// no-op
}
public int getBeforeCount() {
return this.beforeCount;
}
public int getAfterCount() {
return this.afterCount;
}
public int getAroundCount() {
return this.aroundCount;
}
}

View File

@@ -0,0 +1,22 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:after pointcut="execution(int getAge(..))" method="myAfterAdvice" throwing="ex"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,22 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:after-throwing pointcut="execution(int getAge(..))" method="myAfterThrowingAdvice" throwing="ex"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="test.advice.CountingBeforeAdvice"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.xml.sax.SAXParseException;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AopNamespaceHandlerThrowingTests {
@Test
public void testThrowingOnThrowingAdvice() {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-ok.xml", getClass());
}
@Test
public void testParseThrowingOnOtherAdviceType() {
try {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-error.xml", getClass());
fail("Expected BeanDefinitionStoreException");
}
catch (BeanDefinitionStoreException ex) {
assertTrue(ex.contains(SAXParseException.class));
}
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
/**
* @author Rick Evans
* @author Chris Beams
*/
public final class MethodLocatingFactoryBeanTests {
private static final String BEAN_NAME = "string";
private MethodLocatingFactoryBean factory;
private BeanFactory beanFactory;
@Before
public void setUp() {
factory = new MethodLocatingFactoryBean();
// methods must set up expectations and call replay() manually for this mock
beanFactory = createMock(BeanFactory.class);
}
@After
public void tearDown() {
verify(beanFactory);
}
@Test
public void testIsSingleton() {
replay(beanFactory);
assertTrue(factory.isSingleton());
}
@Test
public void testGetObjectType() {
replay(beanFactory);
assertEquals(Method.class, factory.getObjectType());
}
@Test(expected=IllegalArgumentException.class)
public void testWithNullTargetBeanName() {
replay(beanFactory);
factory.setMethodName("toString()");
factory.setBeanFactory(beanFactory);
}
@Test(expected=IllegalArgumentException.class)
public void testWithEmptyTargetBeanName() {
replay(beanFactory);
factory.setTargetBeanName("");
factory.setMethodName("toString()");
factory.setBeanFactory(beanFactory);
}
@Test(expected=IllegalArgumentException.class)
public void testWithNullTargetMethodName() {
replay(beanFactory);
factory.setTargetBeanName(BEAN_NAME);
factory.setBeanFactory(beanFactory);
}
@Test(expected=IllegalArgumentException.class)
public void testWithEmptyTargetMethodName() {
replay(beanFactory);
factory.setTargetBeanName(BEAN_NAME);
factory.setMethodName("");
factory.setBeanFactory(beanFactory);
}
@Test(expected=IllegalArgumentException.class)
public void testWhenTargetBeanClassCannotBeResolved() {
expect(beanFactory.getType(BEAN_NAME)).andReturn(null);
replay(beanFactory);
factory.setTargetBeanName(BEAN_NAME);
factory.setMethodName("toString()");
factory.setBeanFactory(beanFactory);
}
@Test
public void testSunnyDayPath() throws Exception {
expect(beanFactory.getType(BEAN_NAME)).andReturn(String.class);
replay(beanFactory);
factory.setTargetBeanName(BEAN_NAME);
factory.setMethodName("toString()");
factory.setBeanFactory(beanFactory);
Object result = factory.getObject();
assertNotNull(result);
assertTrue(result instanceof Method);
Method method = (Method) result;
assertEquals("Bingo", method.invoke("Bingo", new Object[]{}));
}
@Test(expected=IllegalArgumentException.class)
public void testWhereMethodCannotBeResolved() {
expect(beanFactory.getType(BEAN_NAME)).andReturn(String.class);
replay(beanFactory);
factory.setTargetBeanName(BEAN_NAME);
factory.setMethodName("loadOfOld()");
factory.setBeanFactory(beanFactory);
}
}

View File

@@ -0,0 +1,27 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="service" class="org.springframework.beans.TestBean" scope="prototype"/>
<bean id="serviceDependent1" class="org.springframework.beans.TestBean">
<constructor-arg ref="service"/>
</bean>
<bean id="serviceDependent2" class="org.springframework.beans.TestBean">
<constructor-arg ref="service"/>
</bean>
<bean id="nullInstance" class="test.beans.FactoryMethods" factory-method="nullInstance"/>
<bean id="serviceInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<aop:config proxy-target-class="false">
<aop:pointcut id="servicePointcut" expression="target(org.springframework.beans.ITestBean)"/>
<aop:advisor advice-ref="serviceInterceptor" pointcut-ref="servicePointcut"/>
</aop:config>
</beans>

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.config;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class PrototypeProxyTests {
@Test
public void testInjectionBeforeWrappingCheckDoesNotKickInForPrototypeProxy() {
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans default-dependency-check="all">
<bean id="testBean" class="org.springframework.aop.framework.CglibTestBean">
<property name="name" value="Rob Harrop"/>
<lookup-method name="getName" bean="fixedName"/>
</bean>
<bean id="fixedName" class="java.lang.String"/>
</beans>

View File

@@ -0,0 +1,497 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;
import java.io.Serializable;
import net.sf.cglib.core.CodeGenerationException;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.advice.CountingBeforeAdvice;
import test.interceptor.NopInterceptor;
import test.mixin.LockMixinAdvisor;
/**
* Additional and overridden tests for the CGLIB proxy.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rob Harrop
* @author Ramnivas Laddad
* @author Chris Beams
*/
@SuppressWarnings("serial")
public final class CglibProxyTests extends AbstractAopProxyTests implements Serializable {
private static final String DEPENDENCY_CHECK_CONTEXT = CglibProxyTests.class.getSimpleName() + "-with-dependency-checking.xml";
protected Object createProxy(ProxyCreatorSupport as) {
as.setProxyTargetClass(true);
Object proxy = as.createAopProxy().getProxy();
assertTrue(AopUtils.isCglibProxy(proxy));
return proxy;
}
protected AopProxy createAopProxy(AdvisedSupport as) {
as.setProxyTargetClass(true);
return new Cglib2AopProxy(as);
}
protected boolean requiresTarget() {
return true;
}
@Test
public void testNullConfig() {
try {
new Cglib2AopProxy(null);
fail("Shouldn't allow null interceptors");
}
catch (IllegalArgumentException ex) {
// Ok
}
}
@Test
public void testNoTarget() {
AdvisedSupport pc = new AdvisedSupport(new Class[]{ITestBean.class});
pc.addAdvice(new NopInterceptor());
try {
AopProxy aop = createAopProxy(pc);
aop.getProxy();
fail("Shouldn't allow no target with CGLIB proxy");
}
catch (AopConfigException ex) {
// Ok
}
}
@Test
public void testProtectedMethodInvocation() {
ProtectedMethodTestBean bean = new ProtectedMethodTestBean();
mockTargetSource.setTarget(bean);
AdvisedSupport as = new AdvisedSupport(new Class[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
AopProxy aop = new Cglib2AopProxy(as);
Object proxy = aop.getProxy();
assertTrue(AopUtils.isCglibProxy(proxy));
}
@Test
public void testProxyCanBeClassNotInterface() throws Exception {
TestBean raw = new TestBean();
raw.setAge(32);
mockTargetSource.setTarget(raw);
AdvisedSupport pc = new AdvisedSupport();
pc.setTargetSource(mockTargetSource);
AopProxy aop = new Cglib2AopProxy(pc);
Object proxy = aop.getProxy();
assertTrue(AopUtils.isCglibProxy(proxy));
assertTrue(proxy instanceof ITestBean);
assertTrue(proxy instanceof TestBean);
TestBean tb = (TestBean) proxy;
assertEquals(32, tb.getAge());
}
@Test
public void testCglibProxyingGivesMeaningfulExceptionIfAskedToProxyNonvisibleClass() {
class YouCantSeeThis {
void hidden() {
}
}
YouCantSeeThis mine = new YouCantSeeThis();
try {
ProxyFactory pf = new ProxyFactory(mine);
pf.getProxy();
fail("Shouldn't be able to proxy non-visible class with CGLIB");
}
catch (AopConfigException ex) {
// Check that stack trace is preserved
assertTrue(ex.getCause() instanceof CodeGenerationException ||
ex.getCause() instanceof IllegalArgumentException);
// Check that error message is helpful
assertTrue(ex.getMessage().indexOf("final") != -1);
assertTrue(ex.getMessage().indexOf("visible") != -1);
}
}
@Test
public void testMethodInvocationDuringConstructor() {
CglibTestBean bean = new CglibTestBean();
bean.setName("Rob Harrop");
AdvisedSupport as = new AdvisedSupport(new Class[]{});
as.setTarget(bean);
as.addAdvice(new NopInterceptor());
AopProxy aop = new Cglib2AopProxy(as);
CglibTestBean proxy = (CglibTestBean) aop.getProxy();
assertEquals("The name property has been overwritten by the constructor",
"Rob Harrop", proxy.getName());
}
@Test
public void testUnadvisedProxyCreationWithCallDuringConstructor() throws Exception {
CglibTestBean target = new CglibTestBean();
target.setName("Rob Harrop");
AdvisedSupport pc = new AdvisedSupport(new Class[]{});
pc.setFrozen(true);
pc.setTarget(target);
Cglib2AopProxy aop = new Cglib2AopProxy(pc);
CglibTestBean proxy = (CglibTestBean) aop.getProxy();
assertNotNull("Proxy should not be null", proxy);
assertEquals("Constructor overrode the value of name", "Rob Harrop", proxy.getName());
}
@Test
public void testMultipleProxies() {
TestBean target = new TestBean();
target.setAge(20);
TestBean target2 = new TestBean();
target2.setAge(21);
ITestBean proxy1 = getAdvisedProxy(target);
ITestBean proxy2 = getAdvisedProxy(target2);
assertTrue(proxy1.getClass() == proxy2.getClass());
assertEquals(target.getAge(), proxy1.getAge());
assertEquals(target2.getAge(), proxy2.getAge());
}
private ITestBean getAdvisedProxy(TestBean target) {
ProxyFactory pf = new ProxyFactory(new Class[]{ITestBean.class});
pf.setProxyTargetClass(true);
MethodInterceptor advice = new NopInterceptor();
Pointcut pointcut = new Pointcut() {
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}
public boolean equals(Object obj) {
return true;
}
};
pf.addAdvisor(new DefaultPointcutAdvisor(pointcut, advice));
pf.setTarget(target);
pf.setFrozen(true);
pf.setExposeProxy(false);
return (ITestBean) pf.getProxy();
}
@Test
public void testMultipleProxiesForIntroductionAdvisor() {
TestBean target = new TestBean();
target.setAge(20);
TestBean target2 = new TestBean();
target2.setAge(21);
ITestBean proxy1 = getIntroductionAdvisorProxy(target);
ITestBean proxy2 = getIntroductionAdvisorProxy(target2);
assertTrue("Incorrect duplicate creation of proxy classes", proxy1.getClass() == proxy2.getClass());
}
private ITestBean getIntroductionAdvisorProxy(TestBean target) {
ProxyFactory pf = new ProxyFactory(new Class[]{ITestBean.class});
pf.setProxyTargetClass(true);
pf.addAdvisor(new LockMixinAdvisor());
pf.setTarget(target);
pf.setFrozen(true);
pf.setExposeProxy(false);
return (ITestBean) pf.getProxy();
}
@Test
public void testWithNoArgConstructor() {
NoArgCtorTestBean target = new NoArgCtorTestBean("b", 1);
target.reset();
mockTargetSource.setTarget(target);
AdvisedSupport pc = new AdvisedSupport(new Class[]{});
pc.setTargetSource(mockTargetSource);
Cglib2AopProxy aop = new Cglib2AopProxy(pc);
aop.setConstructorArguments(new Object[] {"Rob Harrop", new Integer(22)},
new Class[] {String.class, int.class});
NoArgCtorTestBean proxy = (NoArgCtorTestBean) aop.getProxy();
proxy = (NoArgCtorTestBean) aop.getProxy();
assertNotNull("Proxy should be null", proxy);
}
@Test
public void testProxyAProxy() {
ITestBean target = new TestBean();
mockTargetSource.setTarget(target);
AdvisedSupport as = new AdvisedSupport(new Class[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
Cglib2AopProxy cglib = new Cglib2AopProxy(as);
ITestBean proxy1 = (ITestBean) cglib.getProxy();
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
cglib = new Cglib2AopProxy(as);
assertThat(cglib.getProxy(), instanceOf(ITestBean.class));
}
@Test
public void testProxyAProxyWithAdditionalInterface() {
ITestBean target = new TestBean();
mockTargetSource.setTarget(target);
AdvisedSupport as = new AdvisedSupport(new Class[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
as.addInterface(Serializable.class);
Cglib2AopProxy cglib = new Cglib2AopProxy(as);
ITestBean proxy1 = (ITestBean) cglib.getProxy();
mockTargetSource.setTarget(proxy1);
as = new AdvisedSupport(new Class[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
cglib = new Cglib2AopProxy(as);
ITestBean proxy2 = (ITestBean) cglib.getProxy();
assertTrue(proxy2 instanceof Serializable);
}
@Test
public void testExceptionHandling() {
ExceptionThrower bean = new ExceptionThrower();
mockTargetSource.setTarget(bean);
AdvisedSupport as = new AdvisedSupport(new Class[]{});
as.setTargetSource(mockTargetSource);
as.addAdvice(new NopInterceptor());
AopProxy aop = new Cglib2AopProxy(as);
ExceptionThrower proxy = (ExceptionThrower) aop.getProxy();
try {
proxy.doTest();
}
catch (Exception ex) {
assertTrue("Invalid exception class", ex instanceof ApplicationContextException);
}
assertTrue("Catch was not invoked", proxy.isCatchInvoked());
assertTrue("Finally was not invoked", proxy.isFinallyInvoked());
}
@Test
public void testWithDependencyChecking() {
ApplicationContext ctx =
new ClassPathXmlApplicationContext(DEPENDENCY_CHECK_CONTEXT, getClass());
ctx.getBean("testBean");
}
@Test
public void testAddAdviceAtRuntime() {
TestBean bean = new TestBean();
CountingBeforeAdvice cba = new CountingBeforeAdvice();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(bean);
pf.setFrozen(false);
pf.setOpaque(false);
pf.setProxyTargetClass(true);
TestBean proxy = (TestBean) pf.getProxy();
assertTrue(AopUtils.isCglibProxy(proxy));
proxy.getAge();
assertEquals(0, cba.getCalls());
((Advised) proxy).addAdvice(cba);
proxy.getAge();
assertEquals(1, cba.getCalls());
}
@Test
public void testProxyProtectedMethod() throws Exception {
CountingBeforeAdvice advice = new CountingBeforeAdvice();
ProxyFactory proxyFactory = new ProxyFactory(new MyBean());
proxyFactory.addAdvice(advice);
proxyFactory.setProxyTargetClass(true);
MyBean proxy = (MyBean) proxyFactory.getProxy();
assertEquals(4, proxy.add(1, 3));
assertEquals(1, advice.getCalls("add"));
}
public static class MyBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected int add(int x, int y) {
return x + y;
}
}
public static class ExceptionThrower {
private boolean catchInvoked;
private boolean finallyInvoked;
public boolean isCatchInvoked() {
return catchInvoked;
}
public boolean isFinallyInvoked() {
return finallyInvoked;
}
public void doTest() throws Exception {
try {
throw new ApplicationContextException("foo");
}
catch (Exception ex) {
catchInvoked = true;
throw ex;
}
finally {
finallyInvoked = true;
}
}
}
public static class HasFinalMethod {
public final void foo() {
}
}
}
class CglibTestBean {
private String name;
public CglibTestBean() {
setName("Some Default");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
class NoArgCtorTestBean {
private boolean called = false;
public NoArgCtorTestBean(String x, int y) {
called = true;
}
public boolean wasCalled() {
return called;
}
public void reset() {
called = false;
}
}
class ProtectedMethodTestBean {
protected String getString() {
return "foo";
}
}
class UnsupportedInterceptor implements MethodInterceptor {
/**
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation mi) throws Throwable {
throw new UnsupportedOperationException(mi.getMethod().getName());
}
}

View File

@@ -0,0 +1,212 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.*;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.IOther;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
/**
* @since 13.03.2003
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
*/
@SuppressWarnings("serial")
public final class JdkDynamicProxyTests extends AbstractAopProxyTests implements Serializable {
protected Object createProxy(ProxyCreatorSupport as) {
assertFalse("Not forcible CGLIB", as.isProxyTargetClass());
Object proxy = as.createAopProxy().getProxy();
assertTrue("Should be a JDK proxy: " + proxy.getClass(), AopUtils.isJdkDynamicProxy(proxy));
return proxy;
}
protected AopProxy createAopProxy(AdvisedSupport as) {
return new JdkDynamicAopProxy(as);
}
public void testNullConfig() {
try {
new JdkDynamicAopProxy(null);
fail("Shouldn't allow null interceptors");
}
catch (IllegalArgumentException ex) {
// Ok
}
}
public void testProxyIsJustInterface() throws Throwable {
TestBean raw = new TestBean();
raw.setAge(32);
AdvisedSupport pc = new AdvisedSupport(new Class[] {ITestBean.class});
pc.setTarget(raw);
JdkDynamicAopProxy aop = new JdkDynamicAopProxy(pc);
Object proxy = aop.getProxy();
assertTrue(proxy instanceof ITestBean);
assertTrue(!(proxy instanceof TestBean));
}
public void testInterceptorIsInvokedWithNoTarget() throws Throwable {
// Test return value
int age = 25;
MethodInterceptor mi = createMock(MethodInterceptor.class);
AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class });
pc.addAdvice(mi);
AopProxy aop = createAopProxy(pc);
expect(mi.invoke(null)).andReturn(age);
replay(mi);
ITestBean tb = (ITestBean) aop.getProxy();
assertTrue("correct return value", tb.getAge() == age);
verify(mi);
}
public void testTargetCanGetInvocationWithPrivateClass() throws Throwable {
final ExposedInvocationTestBean expectedTarget = new ExposedInvocationTestBean() {
protected void assertions(MethodInvocation invocation) {
assertTrue(invocation.getThis() == this);
assertTrue("Invocation should be on ITestBean: " + invocation.getMethod(),
invocation.getMethod().getDeclaringClass() == ITestBean.class);
}
};
AdvisedSupport pc = new AdvisedSupport(new Class[] { ITestBean.class, IOther.class });
pc.addAdvice(ExposeInvocationInterceptor.INSTANCE);
TrapTargetInterceptor tii = new TrapTargetInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
// Assert that target matches BEFORE invocation returns
assertEquals("Target is correct", expectedTarget, invocation.getThis());
return super.invoke(invocation);
}
};
pc.addAdvice(tii);
pc.setTarget(expectedTarget);
AopProxy aop = createAopProxy(pc);
ITestBean tb = (ITestBean) aop.getProxy();
tb.getName();
// Not safe to trap invocation
//assertTrue(tii.invocation == target.invocation);
//assertTrue(target.invocation.getProxy() == tb);
// ((IOther) tb).absquatulate();
//MethodInvocation minv = tii.invocation;
//assertTrue("invoked on iother, not " + minv.getMethod().getDeclaringClass(), minv.getMethod().getDeclaringClass() == IOther.class);
//assertTrue(target.invocation == tii.invocation);
}
public void testProxyNotWrappedIfIncompatible() {
FooBar bean = new FooBar();
ProxyCreatorSupport as = new ProxyCreatorSupport();
as.setInterfaces(new Class[] {Foo.class});
as.setTarget(bean);
Foo proxy = (Foo) createProxy(as);
assertSame("Target should be returned when return types are incompatible", bean, proxy.getBarThis());
assertSame("Proxy should be returned when return types are compatible", proxy, proxy.getFooThis());
}
public void testEqualsAndHashCodeDefined() throws Exception {
AdvisedSupport as = new AdvisedSupport(new Class[]{Named.class});
as.setTarget(new Person());
JdkDynamicAopProxy aopProxy = new JdkDynamicAopProxy(as);
Named proxy = (Named) aopProxy.getProxy();
Named named = new Person();
assertEquals("equals() returned false", proxy, named);
assertEquals("hashCode() not equal", proxy.hashCode(), named.hashCode());
}
public static interface Foo {
Bar getBarThis();
Foo getFooThis();
}
public static interface Bar {
}
public static class FooBar implements Foo, Bar {
public Bar getBarThis() {
return this;
}
public Foo getFooThis() {
return this;
}
}
public static interface Named {
String getName();
boolean equals(Object other);
int hashCode();
}
public static class Person implements Named {
private final String name = "Rob Harrop";
public String getName() {
return this.name;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Person person = (Person) o;
if (!name.equals(person.name)) return false;
return true;
}
public int hashCode() {
return name.hashCode();
}
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="debugInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- Target is autowired, so can check type of parent without a guard -->
<property name="target">
<bean class="org.springframework.beans.TestBean" autowire="byType"/>
</property>
<property name="interceptorNames" value="debugInterceptor"/>
</bean>
</beans>

View File

@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Simple target -->
<bean id="test" class="org.springframework.beans.TestBean">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
</bean>
<bean id="debugInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="test1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="target"><ref local="test"/></property>
<property name="interceptorNames"><value>debugInterceptor</value></property>
</bean>
<!--
Check that invoker is automatically added to wrap target.
Non pointcut bean name should be wrapped in invoker.
-->
<bean id="autoInvoker" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--
Aspect interfaces don't need to be included here.
They may, for example, be added by global interceptors.
-->
<property name="interfaces"><value>org.springframework.beans.ITestBean</value></property>
<!--
Note that "test" is a target. An InvokerInterceptor
will be added automatically.
-->
<property name="interceptorNames"><value>global*,test</value></property>
</bean>
<bean id="prototype" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces">
<value>
org.springframework.beans.ITestBean
</value>
</property>
<property name="singleton"><value>false</value></property>
<property name="interceptorNames"><value>test</value></property>
</bean>
<bean id="test2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>
org.springframework.beans.ITestBean
</value>
</property>
<property name="singleton"><value>false</value></property>
<property name="targetName"><value>test</value></property>
</bean>
<bean id="test3" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="autodetectInterfaces"><value>true</value></property>
<property name="target"><ref local="test"/></property>
<property name="interceptorNames"><value>debugInterceptor</value></property>
</bean>
<bean id="test4" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="autodetectInterfaces"><value>true</value></property>
<property name="singleton"><value>false</value></property>
<property name="targetName"><value>test</value></property>
</bean>
<bean id="testCircle1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="autodetectInterfaces"><value>true</value></property>
<property name="targetName"><value>testCircleTarget1</value></property>
</bean>
<bean id="testCircleTarget1" class="org.springframework.beans.TestBean">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
<property name="spouse"><ref bean="testCircle2"/></property>
</bean>
<bean id="testCircle2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="autodetectInterfaces"><value>true</value></property>
<property name="targetName"><value>testCircleTarget2</value></property>
</bean>
<bean id="testCircleTarget2" class="org.springframework.beans.TestBean">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
<property name="spouse"><ref bean="testCircle1"/></property>
</bean>
<bean id="pointcuts" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>pointcutForVoid</value></property>
<property name="targetName"><value>test</value></property>
</bean>
<bean id="pointcutForVoid" class="org.springframework.aop.framework.ProxyFactoryBeanTests$PointcutForVoid"/>
<!--
Invalid test for global pointcuts.
Must have target because there are no interceptors.
-->
<!--
<bean id="noInterceptorNamesWithoutTarget"
class="org.springframework.aop.framework.ProxyFactoryBean"
>
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
</bean>
<bean id="noInterceptorNamesWithTarget"
class="org.springframework.aop.framework.ProxyFactoryBean"
>
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="target"><ref local="test"/></property>
</bean>
-->
<bean id="validGlobals" scope="singleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.context.ApplicationListener</value></property>
<property name="interceptorNames"><value>debugInterceptor,global*,target2</value></property>
</bean>
<!--
Global debug interceptor
-->
<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<!--
Will add aspect interface to all beans exposing globals
-->
<bean id="global_aspectInterface" class="org.springframework.aop.framework.ProxyFactoryBeanTests$GlobalIntroductionAdvice"/>
<bean id="prototypeLockMixinAdvisor" class="test.mixin.LockMixinAdvisor" scope="prototype"/>
<bean id="prototypeTestBean" class="org.springframework.beans.TestBean" scope="prototype"/>
<bean id="prototypeTestBeanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="singleton"><value>false</value></property>
<property name="interceptorNames">
<list>
<value>prototypeLockMixinAdvisor</value>
<value>prototypeTestBean</value>
</list>
</property>
</bean>
<bean id="prototypeLockMixinInterceptor" class="test.mixin.LockMixin" scope="prototype"/>
<bean id="prototypeTestBeanProxySingletonTarget" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces">
<list>
<value>org.springframework.beans.ITestBean</value>
<value>test.mixin.Lockable</value>
</list>
</property>
<property name="singleton"><value>false</value></property>
<property name="target"><ref local="prototypeTestBean"/></property>
<property name="interceptorNames">
<list>
<value>prototypeLockMixinInterceptor</value>
</list>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for misconfiguring the proxy factory bean using a target source in the
interceptor list as well as set by the targetSource property
-->
<beans>
<bean id="eveTargetSource" class="org.springframework.aop.target.SingletonTargetSource">
<constructor-arg>
<bean class="org.springframework.beans.TestBean">
<property name="name"><value>Eve</value></property>
</bean>
</constructor-arg>
</bean>
<bean id="adam" class="org.springframework.beans.TestBean">
<property name="name"><value>Adam</value></property>
</bean>
<bean id="adamTargetSource" class="org.springframework.aop.target.SingletonTargetSource">
<constructor-arg>
<ref local="adam"/>
</constructor-arg>
</bean>
<bean id="countingBeforeAdvice"
class="test.advice.CountingBeforeAdvice"
/>
<bean id="doubleTarget"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<!-- this is the one used and NOT the one set by targetSource -->
<property name="interceptorNames"><value>countingBeforeAdvice,adamTargetSource</value></property>
<property name="targetSource"><ref bean="eveTargetSource"/></property>
</bean>
<!-- but this is also possible -->
<bean id="arbitraryTarget"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<!-- this is the one used and NOT the one set by targetSource -->
<property name="interceptorNames"><value>adam</value></property>
<property name="targetSource"><ref local="eveTargetSource"/></property>
</bean>
</beans>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Simple target -->
<bean id="test" class="org.springframework.beans.TestBean">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
</bean>
<bean id="debugInterceptor" class="test.interceptor.NopInterceptor">
</bean>
<bean id="frozen"
class="org.springframework.aop.framework.ProxyFactoryBean"
>
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="target"><ref local="test"/></property>
<property name="interceptorNames"><value>debugInterceptor</value></property>
<property name="frozen"><value>true</value></property>
<property name="optimize"><value>true</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Test that inner bean for target means that we can use
autowire without ambiguity from target and proxy.
$Id: innerBeanTarget.xml,v 1.4 2006/08/20 19:08:40 jhoeller Exp $
-->
<beans>
<bean id="nopInterceptor" class="test.interceptor.NopInterceptor">
</bean>
<bean id="testBean"
class="org.springframework.aop.framework.ProxyFactoryBean"
>
<property name="target">
<bean class="org.springframework.beans.TestBean">
<property name="name"><value>innerBeanTarget</value></property>
</bean>
</property>
<property name="interceptorNames">
<value>nopInterceptor</value>
</property>
</bean>
<!--
Autowire would fail if distinct target and proxy:
we expect just to have proxy
-->
<bean id="autowireCheck"
class="org.springframework.aop.framework.ProxyFactoryBeanTests$DependsOnITestBean"
autowire="constructor" />
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Same effect as noInterceptor names: also invalid -->
<bean id="emptyInterceptorNames" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value></value></property>
</bean>
<!--
Invalid test for global pointcuts.
Must have target after *.
-->
<bean id="globalsWithoutTarget" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>global*</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for misconfiguring the proxy factory bean using a target source in the
interceptor list as well as set by the targetSource property
-->
<beans>
<bean id="adam" class="org.springframework.beans.TestBean">
<property name="name"><value>Adam</value></property>
</bean>
<bean id="countingBeforeAdvice"
class="test.advice.CountingBeforeAdvice"
/>
<!--
An error, as the target source or non-advice object
must be last
-->
<bean id="targetSourceNotLast"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<!-- this is the one used and NOT the one set by targetSource -->
<property name="interceptorNames"><value>adam,countingBeforeAdvice</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for independent prototype behavior.
-->
<beans>
<!-- Simple target -->
<bean id="test" class="test.beans.SideEffectBean">
<property name="count"><value>10</value></property>
</bean>
<bean id="prototypeTarget" class="test.beans.SideEffectBean" scope="prototype">
<property name="count"><value>10</value></property>
</bean>
<bean id="debugInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="singleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,test</value></property>
</bean>
<bean id="prototype" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,prototypeTarget</value></property>
<property name="singleton"><value>false</value></property>
</bean>
<bean id="cglibPrototype"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,prototypeTarget</value></property>
<property name="singleton"><value>false</value></property>
<!-- Force the use of CGLIB -->
<property name="proxyTargetClass"><value>true</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for independent prototype behaviour.
-->
<beans>
<bean id="nopInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="serializableNopInterceptor" class="test.interceptor.SerializableNopInterceptor"/>
<bean id="serializableSingleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>serializableNopInterceptor</value></property>
<property name="proxyInterfaces"><value>org.springframework.beans.Person</value></property>
<property name="target">
<bean class="org.springframework.beans.SerializablePerson">
<property name="name"><value>serializableSingleton</value></property>
</bean>
</property>
</bean>
<bean id="prototypeTarget" class="org.springframework.beans.SerializablePerson">
<property name="name"><value>serializablePrototype</value></property>
</bean>
<bean id="serializablePrototype" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>serializableNopInterceptor,prototypeTarget</value></property>
<property name="proxyInterfaces"><value>org.springframework.beans.Person</value></property>
<property name="singleton"><value>false</value></property>
</bean>
<bean id="interceptorNotSerializableSingleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>nopInterceptor</value></property>
<property name="target">
<bean class="org.springframework.beans.SerializablePerson"/>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for independent prototype behaviour.
-->
<beans>
<!-- Simple target -->
<bean id="target" class="org.springframework.beans.TestBean">
<!-- initial value :-) -->
<property name="name"><value>Adam</value></property>
</bean>
<bean id="nopInterceptor" class="test.interceptor.NopInterceptor">
</bean>
<bean id="countingBeforeAdvice"
class="test.advice.CountingBeforeAdvice"
/>
<!--
Note that there's normally no reason to create objects of this type
in a BeanFactory. If for some strange reason you want to, use Type 3 IoC.
-->
<bean id="targetSource" class="org.springframework.aop.target.SingletonTargetSource">
<constructor-arg><ref local="target"/></constructor-arg>
</bean>
<bean id="directTarget"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames" value="countingBeforeAdvice,nopInterceptor,target"/>
<property name="proxyTargetClass" value="true"/>
</bean>
<bean id="viaTargetSource"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>nopInterceptor,targetSource</value></property>
<property name="proxyTargetClass" value="true"/>
</bean>
<bean id ="unsupportedInterceptor"
class="org.springframework.aop.framework.UnsupportedInterceptor"
/>
<!--
No target or target source, just the interceptor
-->
<bean id="noTarget"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>nopInterceptor,unsupportedInterceptor</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for throws advice.
$Id: throwsAdvice.xml,v 1.6 2006/08/20 19:08:40 jhoeller Exp $
-->
<beans>
<!-- Simple target -->
<bean id="target" class="org.springframework.aop.framework.Echo"/>
<bean id="nopInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="countingBeforeAdvice" class="test.advice.CountingBeforeAdvice" />
<bean id="throwsAdvice" class="test.advice.MyThrowsHandler"/>
<bean id="throwsAdvised" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<value>countingBeforeAdvice,nopInterceptor,throwsAdvice,target</value>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,774 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;
import java.util.List;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.IntroductionInterceptor;
import org.springframework.aop.interceptor.DebugInterceptor;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;
import org.springframework.beans.ITestBean;
import org.springframework.beans.Person;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.TestListener;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.SerializationTestUtils;
import test.advice.CountingBeforeAdvice;
import test.advice.MyThrowsHandler;
import test.interceptor.NopInterceptor;
import test.interceptor.TimestampIntroductionInterceptor;
import test.mixin.Lockable;
import test.mixin.LockedException;
import test.util.TimeStamped;
import test.beans.SideEffectBean;
/**
* @since 13.03.2003
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class ProxyFactoryBeanTests {
private static final Class<?> CLASS = ProxyFactoryBeanTests.class;
private static final String CLASSNAME = CLASS.getSimpleName();
private static final String CONTEXT = CLASSNAME + "-context.xml";
private static final String SERIALIZATION_CONTEXT = CLASSNAME + "-serialization.xml";
private static final String AUTOWIRING_CONTEXT = CLASSNAME + "-autowiring.xml";
private static final String DBL_TARGETSOURCE_CONTEXT = CLASSNAME + "-double-targetsource.xml";
private static final String NOTLAST_TARGETSOURCE_CONTEXT = CLASSNAME + "-notlast-targetsource.xml";
private static final String TARGETSOURCE_CONTEXT = CLASSNAME + "-targetsource.xml";
private static final String INVALID_CONTEXT = CLASSNAME + "-invalid.xml";
private static final String FROZEN_CONTEXT = CLASSNAME + "-frozen.xml";
private static final String PROTOTYPE_CONTEXT = CLASSNAME + "-prototype.xml";
private static final String THROWS_ADVICE_CONTEXT = CLASSNAME + "-throws-advice.xml";
private static final String INNER_BEAN_TARGET_CONTEXT = CLASSNAME + "-inner-bean-target.xml";
private BeanFactory factory;
@Before
public void setUp() throws Exception {
DefaultListableBeanFactory parent = new DefaultListableBeanFactory();
parent.registerBeanDefinition("target2", new RootBeanDefinition(TestListener.class));
this.factory = new XmlBeanFactory(new ClassPathResource(CONTEXT, getClass()), parent);
}
@Test
public void testIsDynamicProxyWhenInterfaceSpecified() {
ITestBean test1 = (ITestBean) factory.getBean("test1");
assertTrue("test1 is a dynamic proxy", Proxy.isProxyClass(test1.getClass()));
}
@Test
public void testIsDynamicProxyWhenInterfaceSpecifiedForPrototype() {
ITestBean test1 = (ITestBean) factory.getBean("test2");
assertTrue("test2 is a dynamic proxy", Proxy.isProxyClass(test1.getClass()));
}
@Test
public void testIsDynamicProxyWhenAutodetectingInterfaces() {
ITestBean test1 = (ITestBean) factory.getBean("test3");
assertTrue("test3 is a dynamic proxy", Proxy.isProxyClass(test1.getClass()));
}
@Test
public void testIsDynamicProxyWhenAutodetectingInterfacesForPrototype() {
ITestBean test1 = (ITestBean) factory.getBean("test4");
assertTrue("test4 is a dynamic proxy", Proxy.isProxyClass(test1.getClass()));
}
/**
* Test that it's forbidden to specify TargetSource in both
* interceptor chain and targetSource property.
*/
@Test
public void testDoubleTargetSourcesAreRejected() {
testDoubleTargetSourceIsRejected("doubleTarget");
// Now with conversion from arbitrary bean to a TargetSource
testDoubleTargetSourceIsRejected("arbitraryTarget");
}
private void testDoubleTargetSourceIsRejected(String name) {
try {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(DBL_TARGETSOURCE_CONTEXT, CLASS));
bf.getBean(name);
fail("Should not allow TargetSource to be specified in interceptorNames as well as targetSource property");
}
catch (BeanCreationException ex) {
// Root cause of the problem must be an AOP exception
AopConfigException aex = (AopConfigException) ex.getCause();
assertTrue(aex.getMessage().indexOf("TargetSource") != -1);
}
}
@Test
public void testTargetSourceNotAtEndOfInterceptorNamesIsRejected() {
try {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(NOTLAST_TARGETSOURCE_CONTEXT, CLASS));
bf.getBean("targetSourceNotLast");
fail("TargetSource or non-advised object must be last in interceptorNames");
}
catch (BeanCreationException ex) {
// Root cause of the problem must be an AOP exception
AopConfigException aex = (AopConfigException) ex.getCause();
assertTrue(aex.getMessage().indexOf("interceptorNames") != -1);
}
}
@Test
public void testGetObjectTypeWithDirectTarget() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
// We have a counting before advice here
CountingBeforeAdvice cba = (CountingBeforeAdvice) bf.getBean("countingBeforeAdvice");
assertEquals(0, cba.getCalls());
ITestBean tb = (ITestBean) bf.getBean("directTarget");
assertTrue(tb.getName().equals("Adam"));
assertEquals(1, cba.getCalls());
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&directTarget");
assertTrue("Has correct object type", TestBean.class.isAssignableFrom(pfb.getObjectType()));
}
@Test
public void testGetObjectTypeWithTargetViaTargetSource() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
ITestBean tb = (ITestBean) bf.getBean("viaTargetSource");
assertTrue(tb.getName().equals("Adam"));
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&viaTargetSource");
assertTrue("Has correct object type", TestBean.class.isAssignableFrom(pfb.getObjectType()));
}
@Test
public void testGetObjectTypeWithNoTargetOrTargetSource() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(TARGETSOURCE_CONTEXT, CLASS));
ITestBean tb = (ITestBean) bf.getBean("noTarget");
try {
tb.getName();
fail();
}
catch (UnsupportedOperationException ex) {
assertEquals("getName", ex.getMessage());
}
FactoryBean<?> pfb = (ProxyFactoryBean) bf.getBean("&noTarget");
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(pfb.getObjectType()));
}
/**
* The instances are equal, but do not have object identity.
* Interceptors and interfaces and the target are the same.
*/
@Test
public void testSingletonInstancesAreEqual() {
ITestBean test1 = (ITestBean) factory.getBean("test1");
ITestBean test1_1 = (ITestBean) factory.getBean("test1");
//assertTrue("Singleton instances ==", test1 == test1_1);
assertEquals("Singleton instances ==", test1, test1_1);
test1.setAge(25);
assertEquals(test1.getAge(), test1_1.getAge());
test1.setAge(250);
assertEquals(test1.getAge(), test1_1.getAge());
Advised pc1 = (Advised) test1;
Advised pc2 = (Advised) test1_1;
assertArrayEquals(pc1.getAdvisors(), pc2.getAdvisors());
int oldLength = pc1.getAdvisors().length;
NopInterceptor di = new NopInterceptor();
pc1.addAdvice(1, di);
assertArrayEquals(pc1.getAdvisors(), pc2.getAdvisors());
assertEquals("Now have one more advisor", oldLength + 1, pc2.getAdvisors().length);
assertEquals(di.getCount(), 0);
test1.setAge(5);
assertEquals(test1_1.getAge(), test1.getAge());
assertEquals(di.getCount(), 3);
}
@Test
public void testPrototypeInstancesAreNotEqual() {
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("prototype")));
ITestBean test2 = (ITestBean) factory.getBean("prototype");
ITestBean test2_1 = (ITestBean) factory.getBean("prototype");
assertTrue("Prototype instances !=", test2 != test2_1);
assertTrue("Prototype instances equal", test2.equals(test2_1));
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("prototype")));
}
/**
* Uses its own bean factory XML for clarity
* @param beanName name of the ProxyFactoryBean definition that should
* be a prototype
*/
private Object testPrototypeInstancesAreIndependent(String beanName) {
// Initial count value set in bean factory XML
int INITIAL_COUNT = 10;
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(PROTOTYPE_CONTEXT, CLASS));
// Check it works without AOP
SideEffectBean raw = (SideEffectBean) bf.getBean("prototypeTarget");
assertEquals(INITIAL_COUNT, raw.getCount() );
raw.doWork();
assertEquals(INITIAL_COUNT+1, raw.getCount() );
raw = (SideEffectBean) bf.getBean("prototypeTarget");
assertEquals(INITIAL_COUNT, raw.getCount() );
// Now try with advised instances
SideEffectBean prototype2FirstInstance = (SideEffectBean) bf.getBean(beanName);
assertEquals(INITIAL_COUNT, prototype2FirstInstance.getCount() );
prototype2FirstInstance.doWork();
assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount() );
SideEffectBean prototype2SecondInstance = (SideEffectBean) bf.getBean(beanName);
assertFalse("Prototypes are not ==", prototype2FirstInstance == prototype2SecondInstance);
assertEquals(INITIAL_COUNT, prototype2SecondInstance.getCount() );
assertEquals(INITIAL_COUNT + 1, prototype2FirstInstance.getCount() );
return prototype2FirstInstance;
}
@Test
public void testCglibPrototypeInstance() {
Object prototype = testPrototypeInstancesAreIndependent("cglibPrototype");
assertTrue("It's a cglib proxy", AopUtils.isCglibProxy(prototype));
assertFalse("It's not a dynamic proxy", AopUtils.isJdkDynamicProxy(prototype));
}
/**
* Test invoker is automatically added to manipulate target.
*/
@Test
public void testAutoInvoker() {
String name = "Hieronymous";
TestBean target = (TestBean) factory.getBean("test");
target.setName(name);
ITestBean autoInvoker = (ITestBean) factory.getBean("autoInvoker");
assertTrue(autoInvoker.getName().equals(name));
}
@Test
public void testCanGetFactoryReferenceAndManipulate() {
ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test1");
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(config.getObjectType()));
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("test1")));
// Trigger lazy initialization.
config.getObject();
assertEquals("Have one advisors", 1, config.getAdvisors().length);
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(config.getObjectType()));
assertTrue("Has correct object type", ITestBean.class.isAssignableFrom(factory.getType("test1")));
ITestBean tb = (ITestBean) factory.getBean("test1");
// no exception
tb.hashCode();
final Exception ex = new UnsupportedOperationException("invoke");
// Add evil interceptor to head of list
config.addAdvice(0, new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
throw ex;
}
});
assertEquals("Have correct advisor count", 2, config.getAdvisors().length);
tb = (ITestBean) factory.getBean("test1");
try {
// Will fail now
tb.toString();
fail("Evil interceptor added programmatically should fail all method calls");
}
catch (Exception thrown) {
assertTrue(thrown == ex);
}
}
public static class DependsOnITestBean {
public final ITestBean tb;
public DependsOnITestBean(ITestBean tb) {
this.tb = tb;
}
}
/**
* Test that inner bean for target means that we can use
* autowire without ambiguity from target and proxy
*/
@Test
public void testTargetAsInnerBean() {
ListableBeanFactory bf = new XmlBeanFactory(new ClassPathResource(INNER_BEAN_TARGET_CONTEXT, CLASS));
ITestBean itb = (ITestBean) bf.getBean("testBean");
assertEquals("innerBeanTarget", itb.getName());
assertEquals("Only have proxy and interceptor: no target", 3, bf.getBeanDefinitionCount());
DependsOnITestBean doit = (DependsOnITestBean) bf.getBean("autowireCheck");
assertSame(itb, doit.tb);
}
/**
* Try adding and removing interfaces and interceptors on prototype.
* Changes will only affect future references obtained from the factory.
* Each instance will be independent.
*/
@Test
public void testCanAddAndRemoveAspectInterfacesOnPrototype() {
assertThat("Shouldn't implement TimeStamped before manipulation",
factory.getBean("test2"), not(instanceOf(TimeStamped.class)));
ProxyFactoryBean config = (ProxyFactoryBean) factory.getBean("&test2");
long time = 666L;
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor();
ti.setTime(time);
// Add to head of interceptor chain
int oldCount = config.getAdvisors().length;
config.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
assertTrue(config.getAdvisors().length == oldCount + 1);
TimeStamped ts = (TimeStamped) factory.getBean("test2");
assertEquals(time, ts.getTimeStamp());
// Can remove
config.removeAdvice(ti);
assertTrue(config.getAdvisors().length == oldCount);
// Check no change on existing object reference
assertTrue(ts.getTimeStamp() == time);
assertThat("Should no longer implement TimeStamped",
factory.getBean("test2"), not(instanceOf(TimeStamped.class)));
// Now check non-effect of removing interceptor that isn't there
config.removeAdvice(new DebugInterceptor());
assertTrue(config.getAdvisors().length == oldCount);
ITestBean it = (ITestBean) ts;
DebugInterceptor debugInterceptor = new DebugInterceptor();
config.addAdvice(0, debugInterceptor);
it.getSpouse();
// Won't affect existing reference
assertTrue(debugInterceptor.getCount() == 0);
it = (ITestBean) factory.getBean("test2");
it.getSpouse();
assertEquals(1, debugInterceptor.getCount());
config.removeAdvice(debugInterceptor);
it.getSpouse();
// Still invoked wiht old reference
assertEquals(2, debugInterceptor.getCount());
// not invoked with new object
it = (ITestBean) factory.getBean("test2");
it.getSpouse();
assertEquals(2, debugInterceptor.getCount());
// Our own timestamped reference should still work
assertEquals(time, ts.getTimeStamp());
}
/**
* Note that we can't add or remove interfaces without reconfiguring the
* singleton.
*/
@Test
public void testCanAddAndRemoveAdvicesOnSingleton() {
ITestBean it = (ITestBean) factory.getBean("test1");
Advised pc = (Advised) it;
it.getAge();
NopInterceptor di = new NopInterceptor();
pc.addAdvice(0, di);
assertEquals(0, di.getCount());
it.setAge(25);
assertEquals(25, it.getAge());
assertEquals(2, di.getCount());
}
@Test
public void testMethodPointcuts() {
ITestBean tb = (ITestBean) factory.getBean("pointcuts");
PointcutForVoid.reset();
assertTrue("No methods intercepted", PointcutForVoid.methodNames.isEmpty());
tb.getAge();
assertTrue("Not void: shouldn't have intercepted", PointcutForVoid.methodNames.isEmpty());
tb.setAge(1);
tb.getAge();
tb.setName("Tristan");
tb.toString();
assertEquals("Recorded wrong number of invocations", 2, PointcutForVoid.methodNames.size());
assertTrue(PointcutForVoid.methodNames.get(0).equals("setAge"));
assertTrue(PointcutForVoid.methodNames.get(1).equals("setName"));
}
@Test
public void testCanAddThrowsAdviceWithoutAdvisor() throws Throwable {
BeanFactory f = new XmlBeanFactory(new ClassPathResource(THROWS_ADVICE_CONTEXT, CLASS));
MyThrowsHandler th = (MyThrowsHandler) f.getBean("throwsAdvice");
CountingBeforeAdvice cba = (CountingBeforeAdvice) f.getBean("countingBeforeAdvice");
assertEquals(0, cba.getCalls());
assertEquals(0, th.getCalls());
IEcho echo = (IEcho) f.getBean("throwsAdvised");
int i = 12;
echo.setA(i);
assertEquals(i, echo.getA());
assertEquals(2, cba.getCalls());
assertEquals(0, th.getCalls());
Exception expected = new Exception();
try {
echo.echoException(1, expected);
fail();
}
catch (Exception ex) {
assertEquals(expected, ex);
}
// No throws handler method: count should still be 0
assertEquals(0, th.getCalls());
// Handler knows how to handle this exception
expected = new FileNotFoundException();
try {
echo.echoException(1, expected);
fail();
}
catch (IOException ex) {
assertEquals(expected, ex);
}
// One match
assertEquals(1, th.getCalls("ioException"));
}
// These two fail the whole bean factory
// TODO put in sep file to check quality of error message
/*
@Test
public void testNoInterceptorNamesWithoutTarget() {
try {
ITestBean tb = (ITestBean) factory.getBean("noInterceptorNamesWithoutTarget");
fail("Should require interceptor names");
}
catch (AopConfigException ex) {
// Ok
}
}
@Test
public void testNoInterceptorNamesWithTarget() {
ITestBean tb = (ITestBean) factory.getBean("noInterceptorNamesWithoutTarget");
}
*/
@Test
public void testEmptyInterceptorNames() {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(INVALID_CONTEXT, CLASS));
try {
factory.getBean("emptyInterceptorNames");
fail("Interceptor names cannot be empty");
}
catch (BeanCreationException ex) {
// Ok
}
}
/**
* Globals must be followed by a target.
*/
@Test
public void testGlobalsWithoutTarget() {
XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource(INVALID_CONTEXT, CLASS));
try {
factory.getBean("globalsWithoutTarget");
fail("Should require target name");
}
catch (BeanCreationException ex) {
assertTrue(ex.getCause() instanceof AopConfigException);
}
}
/**
* Checks that globals get invoked,
* and that they can add aspect interfaces unavailable
* to other beans. These interfaces don't need
* to be included in proxiedInterface [].
*/
@Test
public void testGlobalsCanAddAspectInterfaces() {
AddedGlobalInterface agi = (AddedGlobalInterface) factory.getBean("autoInvoker");
assertTrue(agi.globalsAdded() == -1);
ProxyFactoryBean pfb = (ProxyFactoryBean) factory.getBean("&validGlobals");
// Trigger lazy initialization.
pfb.getObject();
// 2 globals + 2 explicit
assertEquals("Have 2 globals and 2 explicit advisors", 3, pfb.getAdvisors().length);
ApplicationListener l = (ApplicationListener) factory.getBean("validGlobals");
agi = (AddedGlobalInterface) l;
assertTrue(agi.globalsAdded() == -1);
try {
agi = (AddedGlobalInterface) factory.getBean("test1");
fail("Aspect interface should't be implemeneted without globals");
}
catch (ClassCastException ex) {
}
}
@Test
public void testSerializableSingletonProxy() throws Exception {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(SERIALIZATION_CONTEXT, CLASS));
Person p = (Person) bf.getBean("serializableSingleton");
assertSame("Should be a Singleton", p, bf.getBean("serializableSingleton"));
Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertEquals(p, p2);
assertNotSame(p, p2);
assertEquals("serializableSingleton", p2.getName());
// Add unserializable advice
Advice nop = new NopInterceptor();
((Advised) p).addAdvice(nop);
// Check it still works
assertEquals(p2.getName(), p2.getName());
assertFalse("Not serializable because an interceptor isn't serializable", SerializationTestUtils.isSerializable(p));
// Remove offending interceptor...
assertTrue(((Advised) p).removeAdvice(nop));
assertTrue("Serializable again because offending interceptor was removed", SerializationTestUtils.isSerializable(p));
}
@Test
public void testSerializablePrototypeProxy() throws Exception {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(SERIALIZATION_CONTEXT, CLASS));
Person p = (Person) bf.getBean("serializablePrototype");
assertNotSame("Should not be a Singleton", p, bf.getBean("serializablePrototype"));
Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertEquals(p, p2);
assertNotSame(p, p2);
assertEquals("serializablePrototype", p2.getName());
}
@Test
public void testSerializableSingletonProxyFactoryBean() throws Exception {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(SERIALIZATION_CONTEXT, CLASS));
Person p = (Person) bf.getBean("serializableSingleton");
ProxyFactoryBean pfb = (ProxyFactoryBean) bf.getBean("&serializableSingleton");
ProxyFactoryBean pfb2 = (ProxyFactoryBean) SerializationTestUtils.serializeAndDeserialize(pfb);
Person p2 = (Person) pfb2.getObject();
assertEquals(p, p2);
assertNotSame(p, p2);
assertEquals("serializableSingleton", p2.getName());
}
@Test
public void testProxyNotSerializableBecauseOfAdvice() throws Exception {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(SERIALIZATION_CONTEXT, CLASS));
Person p = (Person) bf.getBean("interceptorNotSerializableSingleton");
assertFalse("Not serializable because an interceptor isn't serializable", SerializationTestUtils.isSerializable(p));
}
@Test
public void testPrototypeAdvisor() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(CONTEXT, CLASS));
ITestBean bean1 = (ITestBean) bf.getBean("prototypeTestBeanProxy");
ITestBean bean2 = (ITestBean) bf.getBean("prototypeTestBeanProxy");
bean1.setAge(3);
bean2.setAge(4);
assertEquals(3, bean1.getAge());
assertEquals(4, bean2.getAge());
((Lockable) bean1).lock();
try {
bean1.setAge(5);
fail("expected LockedException");
}
catch (LockedException ex) {
// expected
}
try {
bean2.setAge(6);
}
catch (LockedException ex) {
fail("did not expect LockedException");
}
}
@Test
public void testPrototypeInterceptorSingletonTarget() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(CONTEXT, CLASS));
ITestBean bean1 = (ITestBean) bf.getBean("prototypeTestBeanProxySingletonTarget");
ITestBean bean2 = (ITestBean) bf.getBean("prototypeTestBeanProxySingletonTarget");
bean1.setAge(1);
bean2.setAge(2);
assertEquals(2, bean1.getAge());
((Lockable) bean1).lock();
try {
bean1.setAge(5);
fail("expected LockedException");
}
catch (LockedException ex) {
// expected
}
try {
bean2.setAge(6);
}
catch (LockedException ex) {
fail("did not expect LockedException");
}
}
/**
* Simple test of a ProxyFactoryBean that has an inner bean as target that specifies autowiring.
* Checks for correct use of getType() by bean factory.
*/
@Test
public void testInnerBeanTargetUsingAutowiring() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(AUTOWIRING_CONTEXT, CLASS));
bf.getBean("testBean");
}
@Test
public void testFrozenFactoryBean() {
BeanFactory bf = new XmlBeanFactory(new ClassPathResource(FROZEN_CONTEXT, CLASS));
Advised advised = (Advised)bf.getBean("frozen");
assertTrue("The proxy should be frozen", advised.isFrozen());
}
@Test
public void testDetectsInterfaces() throws Exception {
ProxyFactoryBean fb = new ProxyFactoryBean();
fb.setTarget(new TestBean());
fb.addAdvice(new DebugInterceptor());
fb.setBeanFactory(new DefaultListableBeanFactory());
ITestBean proxy = (ITestBean) fb.getObject();
assertTrue(AopUtils.isJdkDynamicProxy(proxy));
}
/**
* Fires only on void methods. Saves list of methods intercepted.
*/
@SuppressWarnings("serial")
public static class PointcutForVoid extends DefaultPointcutAdvisor {
public static List<String> methodNames = new LinkedList<String>();
public static void reset() {
methodNames.clear();
}
public PointcutForVoid() {
setAdvice(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
methodNames.add(invocation.getMethod().getName());
return invocation.proceed();
}
});
setPointcut(new DynamicMethodMatcherPointcut() {
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return m.getReturnType() == Void.TYPE;
}
});
}
}
/**
* Aspect interface
*/
public interface AddedGlobalInterface {
int globalsAdded();
}
/**
* Use as a global interceptor. Checks that
* global interceptors can add aspect interfaces.
* NB: Add only via global interceptors in XML file.
*/
public static class GlobalAspectInterfaceInterceptor implements IntroductionInterceptor {
public boolean implementsInterface(Class<?> intf) {
return intf.equals(AddedGlobalInterface.class);
}
public Object invoke(MethodInvocation mi) throws Throwable {
if (mi.getMethod().getDeclaringClass().equals(AddedGlobalInterface.class)) {
return new Integer(-1);
}
return mi.proceed();
}
}
public static class GlobalIntroductionAdvice implements IntroductionAdvisor {
private IntroductionInterceptor gi = new GlobalAspectInterfaceInterceptor();
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
public Advice getAdvice() {
return this.gi;
}
public Class<?>[] getInterfaces() {
return new Class[] { AddedGlobalInterface.class };
}
public boolean isPerInstance() {
return false;
}
public void validateInterfaces() {
}
}
}

View File

@@ -0,0 +1,41 @@
package org.springframework.aop.framework;
/**
* Definitions of testing types for use in within this package.
* Wherever possible, test types should be defined local to the java
* file that makes use of them. In some cases however, a test type may
* need to be shared across tests. Such types reside here, with the
* intention of reducing the surface area of java files within this
* package. This allows developers to think about tests first, and deal
* with these second class testing artifacts on an as-needed basis.
*
* Types here should be defined as package-private top level classes in
* order to avoid needing to fully qualify, e.g.: _TestTypes$Foo.
*
* @author Chris Beams
*/
final class _TestTypes { }
interface IEcho {
int echoException(int i, Throwable t) throws Throwable;
int getA();
void setA(int a);
}
class Echo implements IEcho {
private int a;
public int echoException(int i, Throwable t) throws Throwable {
if (t != null)
throw t;
return i;
}
public void setA(int a) {
this.a = a;
}
public int getA() {
return a;
}
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="testBeanTarget" class="org.springframework.beans.TestBean"/>
<bean id="simpleBeforeAdvice" class="org.springframework.aop.framework.adapter.SimpleBeforeAdviceImpl"/>
<bean id="simpleBeforeAdviceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<constructor-arg><ref local="simpleBeforeAdvice"/></constructor-arg>
</bean>
<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>simpleBeforeAdviceAdvisor,testBeanTarget</value></property>
</bean>
<bean id="testAdvisorAdapter" class="org.springframework.aop.framework.adapter.SimpleBeforeAdviceAdapter"/>
<bean id="adapterRegistrationManager" class="org.springframework.aop.framework.adapter.AdvisorAdapterRegistrationManager"/>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="testBeanTarget" class="org.springframework.beans.TestBean"/>
<bean id="simpleBeforeAdvice" class="org.springframework.aop.framework.adapter.SimpleBeforeAdviceImpl"/>
<bean id="simpleBeforeAdviceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<constructor-arg><ref local="simpleBeforeAdvice"/></constructor-arg>
</bean>
<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>simpleBeforeAdviceAdvisor,testBeanTarget</value></property>
</bean>
<bean id="testAdvisorAdapter" class="org.springframework.aop.framework.adapter.SimpleBeforeAdviceAdapter"/>
</beans>

View File

@@ -0,0 +1,131 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework.adapter;
import static org.junit.Assert.*;
import java.io.Serializable;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.ITestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* TestCase for AdvisorAdapterRegistrationManager mechanism.
*
* @author Dmitriy Kopylenko
* @author Chris Beams
*/
public final class AdvisorAdapterRegistrationTests {
@Test
public void testAdvisorAdapterRegistrationManagerNotPresentInContext() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-without-bpp.xml", getClass());
ITestBean tb = (ITestBean) ctx.getBean("testBean");
// just invoke any method to see if advice fired
try {
tb.getName();
fail("Should throw UnknownAdviceTypeException");
}
catch (UnknownAdviceTypeException ex) {
// expected
assertEquals(0, getAdviceImpl(tb).getInvocationCounter());
}
}
@Test
public void testAdvisorAdapterRegistrationManagerPresentInContext() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-with-bpp.xml", getClass());
ITestBean tb = (ITestBean) ctx.getBean("testBean");
// just invoke any method to see if advice fired
try {
tb.getName();
assertEquals(1, getAdviceImpl(tb).getInvocationCounter());
}
catch (UnknownAdviceTypeException ex) {
fail("Should not throw UnknownAdviceTypeException");
}
}
private SimpleBeforeAdviceImpl getAdviceImpl(ITestBean tb) {
Advised advised = (Advised) tb;
Advisor advisor = advised.getAdvisors()[0];
return (SimpleBeforeAdviceImpl) advisor.getAdvice();
}
}
interface SimpleBeforeAdvice extends BeforeAdvice {
void before() throws Throwable;
}
@SuppressWarnings("serial")
class SimpleBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
public boolean supportsAdvice(Advice advice) {
return (advice instanceof SimpleBeforeAdvice);
}
public MethodInterceptor getInterceptor(Advisor advisor) {
SimpleBeforeAdvice advice = (SimpleBeforeAdvice) advisor.getAdvice();
return new SimpleBeforeAdviceInterceptor(advice) ;
}
}
class SimpleBeforeAdviceImpl implements SimpleBeforeAdvice {
private int invocationCounter;
public void before() throws Throwable {
++invocationCounter;
}
public int getInvocationCounter() {
return invocationCounter;
}
}
final class SimpleBeforeAdviceInterceptor implements MethodInterceptor {
private SimpleBeforeAdvice advice;
public SimpleBeforeAdviceInterceptor(SimpleBeforeAdvice advice) {
this.advice = advice;
}
public Object invoke(MethodInvocation mi) throws Throwable {
advice.before();
return mi.proceed();
}
}

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Shows common interceptor along with advisor.
-->
<beans>
<description>
Matches all Advisors in the factory: we don't use a prefix
</description>
<bean id="aapc"
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<!-- This common interceptor will be applied always,
before custom lockable advisor -->
<property name="interceptorNames">
<value>nopInterceptor</value>
</property>
</bean>
<bean id="nopInterceptor" class="test.interceptor.NopInterceptor" />
<!--
Stateful mixin. Will apply to all objects
Note that singleton property is false.
-->
<bean id="lockableAdvisor"
class="test.mixin.LockMixinAdvisor"
scope="prototype"
/>
<bean id="test1"
class="org.springframework.beans.TestBean">
<property name="age"><value>4</value></property>
</bean>
<bean id="test2"
class="org.springframework.beans.TestBean">
<property name="age"><value>4</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="autoproxy" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="customTargetSourceCreators">
<list>
<bean class="org.springframework.aop.framework.autoproxy.SelectivePrototypeTargetSourceCreator"/>
<bean class="org.springframework.aop.framework.autoproxy.target.LazyInitTargetSourceCreator"/>
</list>
</property>
</bean>
<bean id="test" scope="prototype" class="org.springframework.beans.TestBean">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<bean id="prototypeTest" class="org.springframework.aop.framework.autoproxy.CountingTestBean">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<bean id="lazyInitTest" class="org.springframework.aop.framework.autoproxy.CountingTestBean" lazy-init="true">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<bean id="wife" class="org.springframework.beans.TestBean">
<property name="name"><value>Kerry</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="optimizedTestBean" class="org.springframework.beans.TestBean">
<property name="name" value="Optimized"/>
</bean>
<bean id="countingAdvice" class="test.advice.CountingBeforeAdvice"/>
<bean id="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="countingAdvice"/>
<property name="patterns">
<list>
<value>.*beans.I?TestBean.*</value>
</list>
</property>
</bean>
<bean id="proxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="optimize" value="true"/>
</bean>
</beans>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="aapc" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="customTargetSourceCreators">
<list>
<ref local="aapc.quickTargetSourceCreator"/>
</list>
</property>
</bean>
<bean id="aapc.quickTargetSourceCreator"
class="org.springframework.aop.framework.autoproxy.target.QuickTargetSourceCreator"/>
<bean id="test" scope="prototype" class="org.springframework.beans.TestBean">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<bean id="wife" class="org.springframework.beans.TestBean">
<property name="name"><value>Kerry</value></property>
</bean>
<!-- Prefix means it will be pooled -->
<bean id=":test" class="org.springframework.beans.TestBean">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<!-- Prefix means it will be thread local -->
<bean name="%test" scope="prototype" class="org.springframework.beans.TestBean">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<!-- Prefix means it will be a prototype target source -->
<bean name="!test" scope="prototype" class="org.springframework.beans.TestBean">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
</beans>

View File

@@ -0,0 +1,230 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework.autoproxy;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.autoproxy.target.AbstractBeanFactoryBasedTargetSourceCreator;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource;
import org.springframework.aop.target.CommonsPoolTargetSource;
import org.springframework.aop.target.LazyInitTargetSource;
import org.springframework.aop.target.PrototypeTargetSource;
import org.springframework.aop.target.ThreadLocalTargetSource;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.advice.CountingBeforeAdvice;
import test.interceptor.NopInterceptor;
import test.mixin.Lockable;
/**
* Tests for auto proxy creation by advisor recognition.
*
* @see org.springframework.aop.framework.autoproxy.AdvisorAutoProxyCreatorIntegrationTests;
*
* @author Rod Johnson
* @author Dave Syer
* @author Chris Beams
*/
public final class AdvisorAutoProxyCreatorTests {
private static final Class<?> CLASS = AdvisorAutoProxyCreatorTests.class;
private static final String CLASSNAME = CLASS.getSimpleName();
private static final String DEFAULT_CONTEXT = CLASSNAME + "-context.xml";
private static final String COMMON_INTERCEPTORS_CONTEXT = CLASSNAME + "-common-interceptors.xml";
private static final String CUSTOM_TARGETSOURCE_CONTEXT = CLASSNAME + "-custom-targetsource.xml";
private static final String QUICK_TARGETSOURCE_CONTEXT = CLASSNAME + "-quick-targetsource.xml";
private static final String OPTIMIZED_CONTEXT = CLASSNAME + "-optimized.xml";
private static final String ADVISOR_APC_BEAN_NAME = "aapc";
private static final String TXMANAGER_BEAN_NAME = "txManager";
/**
* Return a bean factory with attributes and EnterpriseServices configured.
*/
protected BeanFactory getBeanFactory() throws IOException {
return new ClassPathXmlApplicationContext(DEFAULT_CONTEXT, CLASS);
}
/**
* Check that we can provide a common interceptor that will
* appear in the chain before "specific" interceptors,
* which are sourced from matching advisors
*/
@Test
public void testCommonInterceptorAndAdvisor() throws Exception {
BeanFactory bf = new ClassPathXmlApplicationContext(COMMON_INTERCEPTORS_CONTEXT, CLASS);
ITestBean test1 = (ITestBean) bf.getBean("test1");
assertTrue(AopUtils.isAopProxy(test1));
Lockable lockable1 = (Lockable) test1;
NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor");
assertEquals(0, nop.getCount());
ITestBean test2 = (ITestBean) bf.getBean("test2");
Lockable lockable2 = (Lockable) test2;
// Locking should be independent; nop is shared
assertFalse(lockable1.locked());
assertFalse(lockable2.locked());
// equals 2 calls on shared nop, because it's first
// and sees calls against the Lockable interface introduced
// by the specific advisor
assertEquals(2, nop.getCount());
lockable1.lock();
assertTrue(lockable1.locked());
assertFalse(lockable2.locked());
assertEquals(5, nop.getCount());
}
/**
* We have custom TargetSourceCreators but there's no match, and
* hence no proxying, for this bean
*/
@Test
public void testCustomTargetSourceNoMatch() throws Exception {
BeanFactory bf = new ClassPathXmlApplicationContext(CUSTOM_TARGETSOURCE_CONTEXT, CLASS);
ITestBean test = (ITestBean) bf.getBean("test");
assertFalse(AopUtils.isAopProxy(test));
assertEquals("Rod", test.getName());
assertEquals("Kerry", test.getSpouse().getName());
}
@Test
public void testCustomPrototypeTargetSource() throws Exception {
CountingTestBean.count = 0;
BeanFactory bf = new ClassPathXmlApplicationContext(CUSTOM_TARGETSOURCE_CONTEXT, CLASS);
ITestBean test = (ITestBean) bf.getBean("prototypeTest");
assertTrue(AopUtils.isAopProxy(test));
Advised advised = (Advised) test;
assertTrue(advised.getTargetSource() instanceof PrototypeTargetSource);
assertEquals("Rod", test.getName());
// Check that references survived prototype creation
assertEquals("Kerry", test.getSpouse().getName());
assertEquals("Only 2 CountingTestBeans instantiated", 2, CountingTestBean.count);
CountingTestBean.count = 0;
}
@Test
public void testLazyInitTargetSource() throws Exception {
CountingTestBean.count = 0;
BeanFactory bf = new ClassPathXmlApplicationContext(CUSTOM_TARGETSOURCE_CONTEXT, CLASS);
ITestBean test = (ITestBean) bf.getBean("lazyInitTest");
assertTrue(AopUtils.isAopProxy(test));
Advised advised = (Advised) test;
assertTrue(advised.getTargetSource() instanceof LazyInitTargetSource);
assertEquals("No CountingTestBean instantiated yet", 0, CountingTestBean.count);
assertEquals("Rod", test.getName());
assertEquals("Kerry", test.getSpouse().getName());
assertEquals("Only 1 CountingTestBean instantiated", 1, CountingTestBean.count);
CountingTestBean.count = 0;
}
@Test
public void testQuickTargetSourceCreator() throws Exception {
ClassPathXmlApplicationContext bf =
new ClassPathXmlApplicationContext(QUICK_TARGETSOURCE_CONTEXT, CLASS);
ITestBean test = (ITestBean) bf.getBean("test");
assertFalse(AopUtils.isAopProxy(test));
assertEquals("Rod", test.getName());
// Check that references survived pooling
assertEquals("Kerry", test.getSpouse().getName());
// Now test the pooled one
test = (ITestBean) bf.getBean(":test");
assertTrue(AopUtils.isAopProxy(test));
Advised advised = (Advised) test;
assertTrue(advised.getTargetSource() instanceof CommonsPoolTargetSource);
assertEquals("Rod", test.getName());
// Check that references survived pooling
assertEquals("Kerry", test.getSpouse().getName());
// Now test the ThreadLocal one
test = (ITestBean) bf.getBean("%test");
assertTrue(AopUtils.isAopProxy(test));
advised = (Advised) test;
assertTrue(advised.getTargetSource() instanceof ThreadLocalTargetSource);
assertEquals("Rod", test.getName());
// Check that references survived pooling
assertEquals("Kerry", test.getSpouse().getName());
// Now test the Prototype TargetSource
test = (ITestBean) bf.getBean("!test");
assertTrue(AopUtils.isAopProxy(test));
advised = (Advised) test;
assertTrue(advised.getTargetSource() instanceof PrototypeTargetSource);
assertEquals("Rod", test.getName());
// Check that references survived pooling
assertEquals("Kerry", test.getSpouse().getName());
ITestBean test2 = (ITestBean) bf.getBean("!test");
assertFalse("Prototypes cannot be the same object", test == test2);
assertEquals("Rod", test2.getName());
assertEquals("Kerry", test2.getSpouse().getName());
bf.close();
}
@Test
public void testWithOptimizedProxy() throws Exception {
BeanFactory beanFactory = new ClassPathXmlApplicationContext(OPTIMIZED_CONTEXT, CLASS);
ITestBean testBean = (ITestBean) beanFactory.getBean("optimizedTestBean");
assertTrue(AopUtils.isAopProxy(testBean));
CountingBeforeAdvice beforeAdvice = (CountingBeforeAdvice) beanFactory.getBean("countingAdvice");
testBean.setAge(23);
testBean.getAge();
assertEquals("Incorrect number of calls to proxy", 2, beforeAdvice.getCalls());
}
}
class CountingTestBean extends TestBean {
public static int count = 0;
public CountingTestBean() {
count++;
}
}
class SelectivePrototypeTargetSourceCreator extends AbstractBeanFactoryBasedTargetSourceCreator {
protected AbstractBeanFactoryBasedTargetSource createBeanFactoryBasedTargetSource(
Class<?> beanClass, String beanName) {
if (!beanName.startsWith("prototype")) {
return null;
}
return new PrototypeTargetSource();
}
}

View File

@@ -0,0 +1,319 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework.autoproxy;
import static org.junit.Assert.*;
import java.lang.reflect.Proxy;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.IndexedTestBean;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.DummyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.MessageSource;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.context.support.StaticMessageSource;
/**
* @since 09.12.2003
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AutoProxyCreatorTests {
@Test
public void testBeanNameAutoProxyCreator() {
StaticApplicationContext sac = new StaticApplicationContext();
sac.registerSingleton("testInterceptor", TestInterceptor.class);
RootBeanDefinition proxyCreator = new RootBeanDefinition(BeanNameAutoProxyCreator.class);
proxyCreator.getPropertyValues().addPropertyValue("interceptorNames", "testInterceptor");
proxyCreator.getPropertyValues().addPropertyValue("beanNames", "singletonToBeProxied,innerBean,singletonFactoryToBeProxied");
sac.getDefaultListableBeanFactory().registerBeanDefinition("beanNameAutoProxyCreator", proxyCreator);
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class, RootBeanDefinition.AUTOWIRE_BY_TYPE);
RootBeanDefinition innerBean = new RootBeanDefinition(TestBean.class);
bd.getPropertyValues().addPropertyValue("spouse", new BeanDefinitionHolder(innerBean, "innerBean"));
sac.getDefaultListableBeanFactory().registerBeanDefinition("singletonToBeProxied", bd);
sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class);
sac.registerSingleton("autowiredIndexedTestBean", IndexedTestBean.class);
sac.refresh();
MessageSource messageSource = (MessageSource) sac.getBean("messageSource");
ITestBean singletonToBeProxied = (ITestBean) sac.getBean("singletonToBeProxied");
assertFalse(Proxy.isProxyClass(messageSource.getClass()));
assertTrue(Proxy.isProxyClass(singletonToBeProxied.getClass()));
assertTrue(Proxy.isProxyClass(singletonToBeProxied.getSpouse().getClass()));
// test whether autowiring succeeded with auto proxy creation
assertEquals(sac.getBean("autowiredIndexedTestBean"), singletonToBeProxied.getNestedIndexedBean());
TestInterceptor ti = (TestInterceptor) sac.getBean("testInterceptor");
// already 2: getSpouse + getNestedIndexedBean calls above
assertEquals(2, ti.nrOfInvocations);
singletonToBeProxied.getName();
singletonToBeProxied.getSpouse().getName();
assertEquals(5, ti.nrOfInvocations);
ITestBean tb = (ITestBean) sac.getBean("singletonFactoryToBeProxied");
assertTrue(AopUtils.isJdkDynamicProxy(tb));
assertEquals(5, ti.nrOfInvocations);
tb.getAge();
assertEquals(6, ti.nrOfInvocations);
ITestBean tb2 = (ITestBean) sac.getBean("singletonFactoryToBeProxied");
assertSame(tb, tb2);
assertEquals(6, ti.nrOfInvocations);
tb2.getAge();
assertEquals(7, ti.nrOfInvocations);
}
@Test
public void testBeanNameAutoProxyCreatorWithFactoryBeanProxy() {
StaticApplicationContext sac = new StaticApplicationContext();
sac.registerSingleton("testInterceptor", TestInterceptor.class);
RootBeanDefinition proxyCreator = new RootBeanDefinition(BeanNameAutoProxyCreator.class);
proxyCreator.getPropertyValues().addPropertyValue("interceptorNames", "testInterceptor");
proxyCreator.getPropertyValues().addPropertyValue("beanNames", "singletonToBeProxied,&singletonFactoryToBeProxied");
sac.getDefaultListableBeanFactory().registerBeanDefinition("beanNameAutoProxyCreator", proxyCreator);
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
sac.getDefaultListableBeanFactory().registerBeanDefinition("singletonToBeProxied", bd);
sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class);
sac.refresh();
ITestBean singletonToBeProxied = (ITestBean) sac.getBean("singletonToBeProxied");
assertTrue(Proxy.isProxyClass(singletonToBeProxied.getClass()));
TestInterceptor ti = (TestInterceptor) sac.getBean("testInterceptor");
assertEquals(0, ti.nrOfInvocations);
singletonToBeProxied.getName();
assertEquals(1, ti.nrOfInvocations);
FactoryBean<?> factory = (FactoryBean<?>) sac.getBean("&singletonFactoryToBeProxied");
assertTrue(Proxy.isProxyClass(factory.getClass()));
TestBean tb = (TestBean) sac.getBean("singletonFactoryToBeProxied");
assertFalse(AopUtils.isAopProxy(tb));
assertEquals(3, ti.nrOfInvocations);
tb.getAge();
assertEquals(3, ti.nrOfInvocations);
}
@Test
public void testCustomAutoProxyCreator() {
StaticApplicationContext sac = new StaticApplicationContext();
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class);
sac.registerSingleton("singletonNoInterceptor", TestBean.class);
sac.registerSingleton("singletonToBeProxied", TestBean.class);
sac.registerPrototype("prototypeToBeProxied", TestBean.class);
sac.refresh();
MessageSource messageSource = (MessageSource) sac.getBean("messageSource");
ITestBean singletonNoInterceptor = (ITestBean) sac.getBean("singletonNoInterceptor");
ITestBean singletonToBeProxied = (ITestBean) sac.getBean("singletonToBeProxied");
ITestBean prototypeToBeProxied = (ITestBean) sac.getBean("prototypeToBeProxied");
assertFalse(AopUtils.isCglibProxy(messageSource));
assertTrue(AopUtils.isCglibProxy(singletonNoInterceptor));
assertTrue(AopUtils.isCglibProxy(singletonToBeProxied));
assertTrue(AopUtils.isCglibProxy(prototypeToBeProxied));
TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator");
assertEquals(0, tapc.testInterceptor.nrOfInvocations);
singletonNoInterceptor.getName();
assertEquals(0, tapc.testInterceptor.nrOfInvocations);
singletonToBeProxied.getAge();
assertEquals(1, tapc.testInterceptor.nrOfInvocations);
prototypeToBeProxied.getSpouse();
assertEquals(2, tapc.testInterceptor.nrOfInvocations);
}
@Test
public void testAutoProxyCreatorWithFactoryBean() {
StaticApplicationContext sac = new StaticApplicationContext();
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class);
sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class);
sac.refresh();
TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator");
tapc.testInterceptor.nrOfInvocations = 0;
FactoryBean<?> factory = (FactoryBean<?>) sac.getBean("&singletonFactoryToBeProxied");
assertTrue(AopUtils.isCglibProxy(factory));
TestBean tb = (TestBean) sac.getBean("singletonFactoryToBeProxied");
assertTrue(AopUtils.isCglibProxy(tb));
assertEquals(2, tapc.testInterceptor.nrOfInvocations);
tb.getAge();
assertEquals(3, tapc.testInterceptor.nrOfInvocations);
}
@Test
public void testAutoProxyCreatorWithFactoryBeanAndPrototype() {
StaticApplicationContext sac = new StaticApplicationContext();
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue("singleton", "false");
sac.registerSingleton("prototypeFactoryToBeProxied", DummyFactory.class, pvs);
sac.refresh();
TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator");
tapc.testInterceptor.nrOfInvocations = 0;
FactoryBean<?> prototypeFactory = (FactoryBean<?>) sac.getBean("&prototypeFactoryToBeProxied");
assertTrue(AopUtils.isCglibProxy(prototypeFactory));
TestBean tb = (TestBean) sac.getBean("prototypeFactoryToBeProxied");
assertTrue(AopUtils.isCglibProxy(tb));
assertEquals(2, tapc.testInterceptor.nrOfInvocations);
tb.getAge();
assertEquals(3, tapc.testInterceptor.nrOfInvocations);
}
@Test
public void testAutoProxyCreatorWithFactoryBeanAndProxyObjectOnly() {
StaticApplicationContext sac = new StaticApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue("proxyFactoryBean", "false");
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs);
sac.registerSingleton("singletonFactoryToBeProxied", DummyFactory.class);
sac.refresh();
TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator");
tapc.testInterceptor.nrOfInvocations = 0;
FactoryBean<?> factory = (FactoryBean<?>) sac.getBean("&singletonFactoryToBeProxied");
assertFalse(AopUtils.isAopProxy(factory));
TestBean tb = (TestBean) sac.getBean("singletonFactoryToBeProxied");
assertTrue(AopUtils.isCglibProxy(tb));
assertEquals(0, tapc.testInterceptor.nrOfInvocations);
tb.getAge();
assertEquals(1, tapc.testInterceptor.nrOfInvocations);
TestBean tb2 = (TestBean) sac.getBean("singletonFactoryToBeProxied");
assertSame(tb, tb2);
assertEquals(1, tapc.testInterceptor.nrOfInvocations);
tb2.getAge();
assertEquals(2, tapc.testInterceptor.nrOfInvocations);
}
@Test
public void testAutoProxyCreatorWithFactoryBeanAndProxyFactoryBeanOnly() {
StaticApplicationContext sac = new StaticApplicationContext();
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.addPropertyValue("proxyObject", "false");
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs);
pvs = new MutablePropertyValues();
pvs.addPropertyValue("singleton", "false");
sac.registerSingleton("prototypeFactoryToBeProxied", DummyFactory.class, pvs);
sac.refresh();
TestAutoProxyCreator tapc = (TestAutoProxyCreator) sac.getBean("testAutoProxyCreator");
tapc.testInterceptor.nrOfInvocations = 0;
FactoryBean<?> prototypeFactory = (FactoryBean<?>) sac.getBean("&prototypeFactoryToBeProxied");
assertTrue(AopUtils.isCglibProxy(prototypeFactory));
TestBean tb = (TestBean) sac.getBean("prototypeFactoryToBeProxied");
assertFalse(AopUtils.isCglibProxy(tb));
assertEquals(2, tapc.testInterceptor.nrOfInvocations);
tb.getAge();
assertEquals(2, tapc.testInterceptor.nrOfInvocations);
}
@SuppressWarnings("serial")
public static class TestAutoProxyCreator extends AbstractAutoProxyCreator {
private boolean proxyFactoryBean = true;
private boolean proxyObject = true;
public TestInterceptor testInterceptor = new TestInterceptor();
public TestAutoProxyCreator() {
setProxyTargetClass(true);
setOrder(0);
}
public void setProxyFactoryBean(boolean proxyFactoryBean) {
this.proxyFactoryBean = proxyFactoryBean;
}
public void setProxyObject(boolean proxyObject) {
this.proxyObject = proxyObject;
}
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String name, TargetSource customTargetSource) {
if (StaticMessageSource.class.equals(beanClass)) {
return DO_NOT_PROXY;
}
else if (name.endsWith("ToBeProxied")) {
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) {
return new Object[] {this.testInterceptor};
}
else {
return DO_NOT_PROXY;
}
}
else {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
}
}
/**
* Interceptor that counts the number of non-finalize method calls.
*/
public static class TestInterceptor implements MethodInterceptor {
public int nrOfInvocations = 0;
public Object invoke(MethodInvocation invocation) throws Throwable {
if (!invocation.getMethod().getName().equals("finalize")) {
this.nrOfInvocations++;
}
return invocation.proceed();
}
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*"/>
<property name="proxyTargetClass" value="true"/>
<property name="interceptorNames" value="checker"/>
</bean>
<bean id="checker" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<bean class="org.springframework.aop.framework.autoproxy.NullChecker"/>
</property>
<property name="patterns">
<bean class="org.springframework.beans.factory.config.ListFactoryBean">
<property name="sourceList">
<list>
<value>.*\.set[a-zA-Z]*(.*)</value>
</list>
</property>
</bean>
</property>
</bean>
<bean id="bean" class="org.springframework.beans.TestBean"/>
</beans>

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2002-2006 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework.autoproxy;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Juergen Hoeller
* @author Dave Syer
* @author Chris Beams
*/
public final class BeanNameAutoProxyCreatorInitTests {
@Test(expected=IllegalArgumentException.class)
public void testIgnoreAdvisorThatIsCurrentlyCreation() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
TestBean bean = (TestBean) ctx.getBean("bean");
bean.setName("foo");
assertEquals("foo", bean.getName());
bean.setName(null); // should throw
}
}
class NullChecker implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
check(args);
}
private void check(Object[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
throw new IllegalArgumentException("Null argument at position " + i);
}
}
}
}

View File

@@ -0,0 +1,115 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="frozenProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="frozenBean"/>
<property name="frozen" value="true"/>
<property name="interceptorNames" value="nopInterceptor"/>
</bean>
<bean id="_jdkBeanNameProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<description>
Automatically proxies using JDK dynamic proxies
</description>
<property name="beanNames"><value>jdk*,onlyJdk,doubleJdk</value></property>
<property name="interceptorNames">
<list>
<value>nopInterceptor</value>
</list>
</property>
</bean>
<bean id="doubleJdkBeanNameProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="doubleJdk"/>
<property name="interceptorNames" value="nopInterceptor"/>
</bean>
<bean id="_cglibBeanNameProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<value>
cglib*
</value>
</property>
<property name="proxyTargetClass">
<description>Use the inherited ProxyConfig property to force CGLIB proxying</description>
<value>true</value>
</property>
<property name="interceptorNames">
<description>Interceptors and Advisors to apply automatically</description>
<list>
<value>nopInterceptor</value>
<value>countingBeforeAdvice</value>
</list>
</property>
</bean>
<bean id="introductionBeanNameProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<description>
Illustrates a JDK introduction
</description>
<property name="beanNames"><value>*introductionUsingJdk</value></property>
<property name="interceptorNames">
<list>
<value>introductionNopInterceptor</value>
<value>timestampIntroduction</value>
<value>lockableAdvisor</value>
</list>
</property>
</bean>
<bean id="timestampIntroduction" class="test.advice.TimestampIntroductionAdvisor"/>
<!--
Stateful mixin. Note that singleton property is false.
-->
<bean id="lockableAdvisor" class="test.mixin.LockMixinAdvisor"
scope="prototype"/>
<bean id="countingBeforeAdvice" class="test.advice.CountingBeforeAdvice"/>
<bean id="nopInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="introductionNopInterceptor" class="test.interceptor.NopInterceptor"/>
<bean id="introductionUsingJdk" class="org.springframework.beans.TestBean">
<property name="name"><value>introductionUsingJdk</value></property>
</bean>
<bean id="second-introductionUsingJdk" class="org.springframework.beans.TestBean">
<property name="name"><value>second-introductionUsingJdk</value></property>
</bean>
<!--
Lazy only because it breaks other tests until this test is fixed
-->
<bean id="factory-introductionUsingJdk" class="org.springframework.aop.framework.autoproxy.CreatesTestBean"
lazy-init="true">
</bean>
<bean id="jdk1" class="org.springframework.beans.TestBean">
<property name="name"><value>jdk1</value></property>
</bean>
<bean id="frozenBean" class="org.springframework.beans.TestBean">
<property name="name" value="frozenBean"/>
</bean>
<bean id="cglib1" class="org.springframework.beans.TestBean">
<property name="name"><value>cglib1</value></property>
</bean>
<bean id="onlyJdk" class="org.springframework.beans.TestBean">
<property name="name"><value>onlyJdk</value></property>
</bean>
<bean id="doubleJdk" class="org.springframework.beans.TestBean">
<property name="name"><value>doubleJdk</value></property>
</bean>
<bean id="noproxy" class="org.springframework.beans.TestBean">
<property name="name"><value>noproxy</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,226 @@
/*
* Copyright 2002-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework.autoproxy;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.advice.CountingBeforeAdvice;
import test.interceptor.NopInterceptor;
import test.mixin.Lockable;
import test.mixin.LockedException;
import test.util.TimeStamped;
/**
* @author Rod Johnson
* @author Rob Harrop
* @author Chris Beams
*/
public class BeanNameAutoProxyCreatorTests {
private BeanFactory beanFactory;
@Before
public void setUp() throws IOException {
// Note that we need an ApplicationContext, not just a BeanFactory,
// for post-processing and hence auto-proxying to work.
beanFactory =
new ClassPathXmlApplicationContext(getClass().getSimpleName() + "-context.xml", getClass());
}
@Test
public void testNoProxy() {
TestBean tb = (TestBean) beanFactory.getBean("noproxy");
assertFalse(AopUtils.isAopProxy(tb));
assertEquals("noproxy", tb.getName());
}
@Test
public void testJdkProxyWithExactNameMatch() {
ITestBean tb = (ITestBean) beanFactory.getBean("onlyJdk");
jdkAssertions(tb, 1);
assertEquals("onlyJdk", tb.getName());
}
@Test
public void testJdkProxyWithDoubleProxying() {
ITestBean tb = (ITestBean) beanFactory.getBean("doubleJdk");
jdkAssertions(tb, 2);
assertEquals("doubleJdk", tb.getName());
}
@Test
public void testJdkIntroduction() {
ITestBean tb = (ITestBean) beanFactory.getBean("introductionUsingJdk");
NopInterceptor nop = (NopInterceptor) beanFactory.getBean("introductionNopInterceptor");
assertEquals(0, nop.getCount());
assertTrue(AopUtils.isJdkDynamicProxy(tb));
int age = 5;
tb.setAge(age);
assertEquals(age, tb.getAge());
assertTrue("Introduction was made", tb instanceof TimeStamped);
assertEquals(0, ((TimeStamped) tb).getTimeStamp());
assertEquals(3, nop.getCount());
assertEquals("introductionUsingJdk", tb.getName());
ITestBean tb2 = (ITestBean) beanFactory.getBean("second-introductionUsingJdk");
// Check two per-instance mixins were distinct
Lockable lockable1 = (Lockable) tb;
Lockable lockable2 = (Lockable) tb2;
assertFalse(lockable1.locked());
assertFalse(lockable2.locked());
tb.setAge(65);
assertEquals(65, tb.getAge());
lockable1.lock();
assertTrue(lockable1.locked());
// Shouldn't affect second
assertFalse(lockable2.locked());
// Can still mod second object
tb2.setAge(12);
// But can't mod first
try {
tb.setAge(6);
fail("Mixin should have locked this object");
}
catch (LockedException ex) {
// Ok
}
}
@Test
public void testJdkIntroductionAppliesToCreatedObjectsNotFactoryBean() {
ITestBean tb = (ITestBean) beanFactory.getBean("factory-introductionUsingJdk");
NopInterceptor nop = (NopInterceptor) beanFactory.getBean("introductionNopInterceptor");
assertEquals("NOP should not have done any work yet", 0, nop.getCount());
assertTrue(AopUtils.isJdkDynamicProxy(tb));
int age = 5;
tb.setAge(age);
assertEquals(age, tb.getAge());
assertTrue("Introduction was made", tb instanceof TimeStamped);
assertEquals(0, ((TimeStamped) tb).getTimeStamp());
assertEquals(3, nop.getCount());
ITestBean tb2 = (ITestBean) beanFactory.getBean("second-introductionUsingJdk");
// Check two per-instance mixins were distinct
Lockable lockable1 = (Lockable) tb;
Lockable lockable2 = (Lockable) tb2;
assertFalse(lockable1.locked());
assertFalse(lockable2.locked());
tb.setAge(65);
assertEquals(65, tb.getAge());
lockable1.lock();
assertTrue(lockable1.locked());
// Shouldn't affect second
assertFalse(lockable2.locked());
// Can still mod second object
tb2.setAge(12);
// But can't mod first
try {
tb.setAge(6);
fail("Mixin should have locked this object");
}
catch (LockedException ex) {
// Ok
}
}
@Test
public void testJdkProxyWithWildcardMatch() {
ITestBean tb = (ITestBean) beanFactory.getBean("jdk1");
jdkAssertions(tb, 1);
assertEquals("jdk1", tb.getName());
}
@Test
public void testCglibProxyWithWildcardMatch() {
TestBean tb = (TestBean) beanFactory.getBean("cglib1");
cglibAssertions(tb);
assertEquals("cglib1", tb.getName());
}
@Test
public void testWithFrozenProxy() {
ITestBean testBean = (ITestBean) beanFactory.getBean("frozenBean");
assertTrue(((Advised)testBean).isFrozen());
}
private void jdkAssertions(ITestBean tb, int nopInterceptorCount) {
NopInterceptor nop = (NopInterceptor) beanFactory.getBean("nopInterceptor");
assertEquals(0, nop.getCount());
assertTrue(AopUtils.isJdkDynamicProxy(tb));
int age = 5;
tb.setAge(age);
assertEquals(age, tb.getAge());
assertEquals(2 * nopInterceptorCount, nop.getCount());
}
/**
* Also has counting before advice.
*/
private void cglibAssertions(TestBean tb) {
CountingBeforeAdvice cba = (CountingBeforeAdvice) beanFactory.getBean("countingBeforeAdvice");
NopInterceptor nop = (NopInterceptor) beanFactory.getBean("nopInterceptor");
assertEquals(0, cba.getCalls());
assertEquals(0, nop.getCount());
assertTrue(AopUtils.isCglibProxy(tb));
int age = 5;
tb.setAge(age);
assertEquals(age, tb.getAge());
assertEquals(2, nop.getCount());
assertEquals(2, cba.getCalls());
}
}
class CreatesTestBean implements FactoryBean<Object> {
/**
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
public Object getObject() throws Exception {
return new TestBean();
}
/**
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<?> getObjectType() {
return TestBean.class;
}
/**
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {
return true;
}
}

View File

@@ -0,0 +1,16 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="scopedList" class="java.util.ArrayList" scope="request">
<aop:scoped-proxy/>
</bean>
<bean id="testBean" class="org.springframework.beans.TestBean">
<property name="friends" ref="scopedList"/>
</bean>
</beans>

View File

@@ -0,0 +1,22 @@
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean id="singletonMap" class="java.util.Collections" factory-method="singletonMap" scope="prototype">
<aop:scoped-proxy/>
<constructor-arg value="test"/>
<constructor-arg value="1234"/>
</bean>
<bean id="synchronizedMap" class="java.util.Collections" factory-method="synchronizedMap" scope="singleton">
<constructor-arg ref="singletonParams"/>
</bean>
<bean id="simpleMap" class="java.util.HashMap" scope="prototype">
<aop:scoped-proxy/>
</bean>
</beans>

View File

@@ -0,0 +1,21 @@
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id="testBean" class="org.springframework.beans.TestBean" scope="request">
<aop:scoped-proxy proxy-target-class="false"/>
<property name="age" value="99"/>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
<property name="properties">
<map>
<entry key="testBean.sex" value="male"/>
</map>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="testBeanTarget" class="org.springframework.beans.TestBean" scope="request"/>
<bean id="testBean" class="org.springframework.aop.scope.ScopedProxyFactoryBean">
<property name="targetBeanName" value="testBeanTarget"/>
<property name="proxyTargetClass" value="false"/>
</bean>
</beans>

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.scope;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.config.SimpleMapScope;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Chris Beams
*/
public class ScopedProxyTests {
private static final Class<?> CLASS = ScopedProxyTests.class;
private static final String CLASSNAME = CLASS.getSimpleName();
private static final ClassPathResource LIST_CONTEXT = new ClassPathResource(CLASSNAME + "-list.xml", CLASS);
private static final ClassPathResource MAP_CONTEXT = new ClassPathResource(CLASSNAME + "-map.xml", CLASS);
private static final ClassPathResource OVERRIDE_CONTEXT = new ClassPathResource(CLASSNAME + "-override.xml", CLASS);
private static final ClassPathResource TESTBEAN_CONTEXT = new ClassPathResource(CLASSNAME + "-testbean.xml", CLASS);
/* SPR-2108 */
@Test
public void testProxyAssignable() throws Exception {
XmlBeanFactory bf = new XmlBeanFactory(MAP_CONTEXT);
Object baseMap = bf.getBean("singletonMap");
assertTrue(baseMap instanceof Map);
}
@Test
public void testSimpleProxy() throws Exception {
XmlBeanFactory bf = new XmlBeanFactory(MAP_CONTEXT);
Object simpleMap = bf.getBean("simpleMap");
assertTrue(simpleMap instanceof Map);
assertTrue(simpleMap instanceof HashMap);
}
@Test
public void testScopedOverride() throws Exception {
GenericApplicationContext ctx = new GenericApplicationContext();
new XmlBeanDefinitionReader(ctx).loadBeanDefinitions(OVERRIDE_CONTEXT);
SimpleMapScope scope = new SimpleMapScope();
ctx.getBeanFactory().registerScope("request", scope);
ctx.refresh();
ITestBean bean = (ITestBean) ctx.getBean("testBean");
assertEquals("male", bean.getName());
assertEquals(99, bean.getAge());
assertTrue(scope.getMap().containsKey("scopedTarget.testBean"));
assertEquals(TestBean.class, scope.getMap().get("scopedTarget.testBean").getClass());
}
@Test
public void testJdkScopedProxy() throws Exception {
XmlBeanFactory bf = new XmlBeanFactory(TESTBEAN_CONTEXT);
SimpleMapScope scope = new SimpleMapScope();
bf.registerScope("request", scope);
ITestBean bean = (ITestBean) bf.getBean("testBean");
assertNotNull(bean);
assertTrue(AopUtils.isJdkDynamicProxy(bean));
assertTrue(bean instanceof ScopedObject);
ScopedObject scoped = (ScopedObject) bean;
assertEquals(TestBean.class, scoped.getTargetObject().getClass());
assertTrue(scope.getMap().containsKey("testBeanTarget"));
assertEquals(TestBean.class, scope.getMap().get("testBeanTarget").getClass());
}
@Test
public void testCglibScopedProxy() {
XmlBeanFactory bf = new XmlBeanFactory(LIST_CONTEXT);
SimpleMapScope scope = new SimpleMapScope();
bf.registerScope("request", scope);
TestBean tb = (TestBean) bf.getBean("testBean");
assertTrue(AopUtils.isCglibProxy(tb.getFriends()));
assertTrue(tb.getFriends() instanceof ScopedObject);
ScopedObject scoped = (ScopedObject) tb.getFriends();
assertEquals(ArrayList.class, scoped.getTargetObject().getClass());
assertTrue(scope.getMap().containsKey("scopedTarget.scopedList"));
assertEquals(ArrayList.class, scope.getMap().get("scopedTarget.scopedList").getClass());
}
}

View File

@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="prototypeTest" class="test.beans.SideEffectBean" scope="prototype">
<property name="count"><value>10</value></property>
</bean>
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName"><value>prototypeTest</value></property>
<property name="maxSize"><value>25</value></property>
</bean>
<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="poolTargetSource" /></property>
<property name="targetMethod"><value>getPoolingConfigMixin</value></property>
</bean>
<bean id="nop" class="test.interceptor.NopInterceptor"/>
<!--
This will create a bean for each thread ("apartment")
-->
<bean id="pooled" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="poolTargetSource"/></property>
<property name="interceptorNames"><value>nop</value></property>
</bean>
<bean id="pooledNoInterceptors" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="poolTargetSource"/></property>
</bean>
<bean id="pooledWithMixin" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="poolTargetSource"/></property>
<property name="interceptorNames"><value>poolConfigAdvisor</value></property>
<!-- Necessary as have a mixin and want to avoid losing the class,
because there's no target interface -->
<property name="proxyTargetClass"><value>true</value></property>
</bean>
<!-- Serialization tests using serializable target and advice -->
<bean id="serializableNop" class="test.interceptor.SerializableNopInterceptor" />
<bean id="prototypePerson" class="org.springframework.beans.SerializablePerson" scope="prototype"/>
<bean id="personPoolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName"><value>prototypePerson</value></property>
<property name="maxSize"><value>10</value></property>
</bean>
<bean id="pooledPerson" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="personPoolTargetSource"/></property>
<property name="interceptorNames"><value>serializableNop</value></property>
</bean>
<bean id="maxSizePooledPerson" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="prototypePerson"/>
<property name="maxSize" value="10"/>
<property name="maxWait" value="1"/>
</bean>
</property>
<property name="interceptorNames"><value>serializableNop</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,216 @@
/*
* Copyright 2002-2005 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.target;
import static org.junit.Assert.*;
import java.util.NoSuchElementException;
import org.apache.commons.pool.impl.GenericObjectPool;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.Person;
import org.springframework.beans.SerializablePerson;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.SerializationTestUtils;
import test.beans.SideEffectBean;
/**
* Tests for pooling invoker interceptor.
* TODO: need to make these tests stronger: it's hard to
* make too many assumptions about a pool.
*
* @author Rod Johnson
* @author Rob Harrop
* @author Chris Beams
*/
public class CommonsPoolTargetSourceTests {
/**
* Initial count value set in bean factory XML
*/
private static final int INITIAL_COUNT = 10;
private XmlBeanFactory beanFactory;
@Before
public void setUp() throws Exception {
this.beanFactory = new XmlBeanFactory(new ClassPathResource(getClass().getSimpleName() + "-context.xml", getClass()));
}
/**
* We must simulate container shutdown, which should clear threads.
*/
@After
public void tearDown() {
// Will call pool.close()
this.beanFactory.destroySingletons();
}
private void testFunctionality(String name) {
SideEffectBean pooled = (SideEffectBean) beanFactory.getBean(name);
assertEquals(INITIAL_COUNT, pooled.getCount());
pooled.doWork();
assertEquals(INITIAL_COUNT + 1, pooled.getCount());
pooled = (SideEffectBean) beanFactory.getBean(name);
// Just check that it works--we can't make assumptions
// about the count
pooled.doWork();
//assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
}
@Test
public void testFunctionality() {
testFunctionality("pooled");
}
@Test
public void testFunctionalityWithNoInterceptors() {
testFunctionality("pooledNoInterceptors");
}
@Test
public void testConfigMixin() {
SideEffectBean pooled = (SideEffectBean) beanFactory.getBean("pooledWithMixin");
assertEquals(INITIAL_COUNT, pooled.getCount());
PoolingConfig conf = (PoolingConfig) beanFactory.getBean("pooledWithMixin");
// TODO one invocation from setup
//assertEquals(1, conf.getInvocations());
pooled.doWork();
// assertEquals("No objects active", 0, conf.getActive());
assertEquals("Correct target source", 25, conf.getMaxSize());
// assertTrue("Some free", conf.getFree() > 0);
//assertEquals(2, conf.getInvocations());
assertEquals(25, conf.getMaxSize());
}
@Test
public void testTargetSourceSerializableWithoutConfigMixin() throws Exception {
CommonsPoolTargetSource cpts = (CommonsPoolTargetSource) beanFactory.getBean("personPoolTargetSource");
SingletonTargetSource serialized = (SingletonTargetSource) SerializationTestUtils.serializeAndDeserialize(cpts);
assertTrue(serialized.getTarget() instanceof Person);
}
@Test
public void testProxySerializableWithoutConfigMixin() throws Exception {
Person pooled = (Person) beanFactory.getBean("pooledPerson");
//System.out.println(((Advised) pooled).toProxyConfigString());
assertTrue(((Advised) pooled).getTargetSource() instanceof CommonsPoolTargetSource);
//((Advised) pooled).setTargetSource(new SingletonTargetSource(new SerializablePerson()));
Person serialized = (Person) SerializationTestUtils.serializeAndDeserialize(pooled);
assertTrue(((Advised) serialized).getTargetSource() instanceof SingletonTargetSource);
serialized.setAge(25);
assertEquals(25, serialized.getAge());
}
@Test
public void testHitMaxSize() throws Exception {
int maxSize = 10;
CommonsPoolTargetSource targetSource = new CommonsPoolTargetSource();
targetSource.setMaxSize(maxSize);
targetSource.setMaxWait(1);
prepareTargetSource(targetSource);
Object[] pooledInstances = new Object[maxSize];
for (int x = 0; x < maxSize; x++) {
Object instance = targetSource.getTarget();
assertNotNull(instance);
pooledInstances[x] = instance;
}
// should be at maximum now
try {
targetSource.getTarget();
fail("Should throw NoSuchElementException");
}
catch (NoSuchElementException ex) {
// desired
}
// lets now release an object and try to accquire a new one
targetSource.releaseTarget(pooledInstances[9]);
pooledInstances[9] = targetSource.getTarget();
// release all objects
for (int i = 0; i < pooledInstances.length; i++) {
targetSource.releaseTarget(pooledInstances[i]);
}
}
@Test
public void testHitMaxSizeLoadedFromContext() throws Exception {
Advised person = (Advised) beanFactory.getBean("maxSizePooledPerson");
CommonsPoolTargetSource targetSource = (CommonsPoolTargetSource) person.getTargetSource();
int maxSize = targetSource.getMaxSize();
Object[] pooledInstances = new Object[maxSize];
for (int x = 0; x < maxSize; x++) {
Object instance = targetSource.getTarget();
assertNotNull(instance);
pooledInstances[x] = instance;
}
// should be at maximum now
try {
targetSource.getTarget();
fail("Should throw NoSuchElementException");
}
catch (NoSuchElementException ex) {
// desired
}
// lets now release an object and try to accquire a new one
targetSource.releaseTarget(pooledInstances[9]);
pooledInstances[9] = targetSource.getTarget();
// release all objects
for (int i = 0; i < pooledInstances.length; i++) {
targetSource.releaseTarget(pooledInstances[i]);
}
}
@Test
public void testSetWhenExhaustedAction() {
CommonsPoolTargetSource targetSource = new CommonsPoolTargetSource();
targetSource.setWhenExhaustedActionName("WHEN_EXHAUSTED_BLOCK");
assertEquals(GenericObjectPool.WHEN_EXHAUSTED_BLOCK, targetSource.getWhenExhaustedAction());
}
private void prepareTargetSource(CommonsPoolTargetSource targetSource) {
String beanName = "target";
StaticApplicationContext applicationContext = new StaticApplicationContext();
applicationContext.registerPrototype(beanName, SerializablePerson.class);
targetSource.setTargetBeanName(beanName);
targetSource.setBeanFactory(applicationContext);
}
}

View File

@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.Attribute;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
@@ -34,7 +35,6 @@ import javax.management.modelmbean.ModelMBeanInfo;
import org.junit.Ignore;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.NopInterceptor;
import org.springframework.beans.TestBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
@@ -49,15 +49,18 @@ import org.springframework.jmx.export.assembler.SimpleReflectiveMBeanInfoAssembl
import org.springframework.jmx.export.naming.SelfNaming;
import org.springframework.jmx.support.ObjectNameManager;
import test.interceptor.NopInterceptor;
/**
* Integration tests for the MBeanExporter class.
* Integration tests for the {@link MBeanExporter} class.
*
* @author Rob Harrop
* @author Juergen Hoeller
* @author Rick Evans
* @author Mark Fisher
* @author Chris Beams
*/
public class MBeanExporterTests extends AbstractMBeanServerTests {
public final class MBeanExporterTests extends AbstractMBeanServerTests {
private static final String OBJECT_NAME = "spring:test=jmxMBeanAdaptor";

View File

@@ -27,15 +27,17 @@ import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.NopInterceptor;
import org.springframework.jmx.IJmxTestBean;
import org.springframework.jmx.JmxTestBean;
import org.springframework.jmx.export.MBeanExporter;
import org.springframework.jmx.export.metadata.JmxAttributeSource;
import org.springframework.jmx.support.ObjectNameManager;
import test.interceptor.NopInterceptor;
/**
* @author Rob Harrop
* @author Chris Beams
*/
public abstract class AbstractMetadataAssemblerTests extends AbstractJmxAssemblerTests {

View File

@@ -16,6 +16,6 @@
<property name="message" value="Hello World!"/>
</bean>
<bean id="advice" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
<bean id="advice" class="test.advice.CountingBeforeAdvice"/>
</beans>

View File

@@ -16,6 +16,6 @@
<property name="interceptorNames" value="advice"/>
</bean>
<bean id="advice" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
<bean id="advice" class="test.advice.CountingBeforeAdvice"/>
</beans>

View File

@@ -16,43 +16,53 @@
package org.springframework.scripting.jruby;
import junit.framework.TestCase;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.CountingBeforeAdvice;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
import test.advice.CountingBeforeAdvice;
/**
* @author Rob Harrop
* @author Chris Beams
*/
public class AdvisedJRubyScriptFactoryTests extends TestCase {
public final class AdvisedJRubyScriptFactoryTests {
private static final Class<?> CLASS = AdvisedJRubyScriptFactoryTests.class;
private static final String CLASSNAME = CLASS.getSimpleName();
private static final String FACTORYBEAN_CONTEXT = CLASSNAME + "-factoryBean.xml";
private static final String APC_CONTEXT = CLASSNAME + "-beanNameAutoProxyCreator.xml";
public void testAdviseWithProxyFactoryBean() throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("advisedByProxyFactoryBean.xml", getClass());
@Test
public void testAdviseWithProxyFactoryBean() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(FACTORYBEAN_CONTEXT, CLASS);
Messenger bean = (Messenger) context.getBean("messenger");
Messenger bean = (Messenger) ctx.getBean("messenger");
assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean));
assertTrue("Bean is not an Advised object", bean instanceof Advised);
CountingBeforeAdvice advice = (CountingBeforeAdvice) context.getBean("advice");
CountingBeforeAdvice advice = (CountingBeforeAdvice) ctx.getBean("advice");
assertEquals(0, advice.getCalls());
bean.getMessage();
assertEquals(1, advice.getCalls());
}
public void testAdviseWithBeanNameAutoProxyCreator() throws Exception {
ApplicationContext context =
new ClassPathXmlApplicationContext("advisedByBeanNameAutoProxyCreator.xml", getClass());
@Test
public void testAdviseWithBeanNameAutoProxyCreator() {
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(APC_CONTEXT, CLASS);
Messenger bean = (Messenger) context.getBean("messenger");
Messenger bean = (Messenger) ctx.getBean("messenger");
assertTrue("Bean is not a proxy", AopUtils.isAopProxy(bean));
assertTrue("Bean is not an Advised object", bean instanceof Advised);
CountingBeforeAdvice advice = (CountingBeforeAdvice) context.getBean("advice");
CountingBeforeAdvice advice = (CountingBeforeAdvice) ctx.getBean("advice");
assertEquals(0, advice.getCalls());
bean.getMessage();
assertEquals(1, advice.getCalls());

Some files were not shown because too many files have changed in this diff Show More