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:
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
Reference in New Issue
Block a user