Rename modules {org.springframework.*=>spring-*}

This renaming more intuitively expresses the relationship between
subprojects and the JAR artifacts they produce.

Tracking history across these renames is possible, but it requires
use of the --follow flag to `git log`, for example

    $ git log spring-aop/src/main/java/org/springframework/aop/Advisor.java

will show history up until the renaming event, where

    $ git log --follow spring-aop/src/main/java/org/springframework/aop/Advisor.java

will show history for all changes to the file, before and after the
renaming.

See http://chrisbeams.com/git-diff-across-renamed-directories
This commit is contained in:
Chris Beams
2012-01-20 22:51:02 +01:00
parent b6cb514d38
commit 02a4473c62
5671 changed files with 20 additions and 32 deletions

View File

@@ -0,0 +1,49 @@
/*
* 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;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Test;
/**
* Additional parameter name discover tests that need Java 5.
* Yes this will re-run the tests from the superclass, but that
* doesn't matter in the grand scheme of things...
*
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AspectJAdviceParameterNameDiscoverAnnotationTests
extends AspectJAdviceParameterNameDiscovererTests {
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {}
public void pjpAndAnAnnotation(ProceedingJoinPoint pjp, MyAnnotation ann) {}
@Test
public void testAnnotationBinding() {
assertParameterNames(getMethod("pjpAndAnAnnotation"),
"execution(* *(..)) && @annotation(ann)",
new String[] {"thisJoinPoint","ann"});
}
}

View File

@@ -0,0 +1,330 @@
/*
* 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;
import static org.junit.Assert.*;
import org.aspectj.lang.JoinPoint;
import org.junit.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException;
import java.lang.reflect.Method;
/**
* Unit tests for the {@link AspectJAdviceParameterNameDiscoverer} class.
*
* <p>See also {@link TigerAspectJAdviceParameterNameDiscovererTests} in
* the 'tiger' tree for tests relating to annotations.
*
* @author Adrian Colyer
* @author Chris Beams
*/
public class AspectJAdviceParameterNameDiscovererTests {
// methods to discover parameter names for
public void noArgs() {
}
public void tjp(JoinPoint jp) {
}
public void tjpsp(JoinPoint.StaticPart tjpsp) {
}
public void twoJoinPoints(JoinPoint jp1, JoinPoint jp2) {
}
public void oneThrowable(Exception ex) {
}
public void jpAndOneThrowable(JoinPoint jp, Exception ex) {
}
public void jpAndTwoThrowables(JoinPoint jp, Exception ex, Error err) {
}
public void oneObject(Object x) {
}
public void twoObjects(Object x, Object y) {
}
public void onePrimitive(int x) {
}
public void oneObjectOnePrimitive(Object x, int y) {
}
public void oneThrowableOnePrimitive(Throwable x, int y) {
}
public void theBigOne(JoinPoint jp, Throwable x, int y, Object foo) {
}
@Test
public void testNoArgs() {
assertParameterNames(getMethod("noArgs"), "execution(* *(..))", new String[0]);
}
@Test
public void testJoinPointOnly() {
assertParameterNames(getMethod("tjp"), "execution(* *(..))", new String[]{"thisJoinPoint"});
}
@Test
public void testJoinPointStaticPartOnly() {
assertParameterNames(getMethod("tjpsp"), "execution(* *(..))", new String[]{"thisJoinPointStaticPart"});
}
@Test
public void testTwoJoinPoints() {
assertException(getMethod("twoJoinPoints"), "foo()", IllegalStateException.class, "Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testOneThrowable() {
assertParameterNames(getMethod("oneThrowable"), "foo()", null, "ex", new String[]{"ex"});
}
@Test
public void testOneJPAndOneThrowable() {
assertParameterNames(getMethod("jpAndOneThrowable"), "foo()", null, "ex", new String[]{"thisJoinPoint", "ex"});
}
@Test
public void testOneJPAndTwoThrowables() {
assertException(getMethod("jpAndTwoThrowables"), "foo()", null, "ex", AmbiguousBindingException.class,
"Binding of throwing parameter 'ex' is ambiguous: could be bound to argument 1 or argument 2");
}
@Test
public void testThrowableNoCandidates() {
assertException(getMethod("noArgs"), "foo()", null, "ex", IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
public void testReturning() {
assertParameterNames(getMethod("oneObject"), "foo()", "obj", null, new String[]{"obj"});
}
@Test
public void testAmbiguousReturning() {
assertException(getMethod("twoObjects"), "foo()", "obj", null, AmbiguousBindingException.class,
"Binding of returning parameter 'obj' is ambiguous, there are 2 candidates.");
}
@Test
public void testReturningNoCandidates() {
assertException(getMethod("noArgs"), "foo()", "obj", null, IllegalStateException.class,
"Not enough arguments in method to satisfy binding of returning and throwing variables");
}
@Test
public void testThisBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "this(x)", new String[]{"x"});
}
@Test
public void testThisBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "this( x )", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "this( x)", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "this (x )", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "this(x )", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "foo() && this(x)", new String[]{"x"});
}
@Test
public void testThisBindingTwoCandidates() {
assertException(getMethod("oneObject"), "this(x) || this(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testThisBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "this(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "this(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testTargetBindingOneCandidate() {
assertParameterNames(getMethod("oneObject"), "target(x)", new String[]{"x"});
}
@Test
public void testTargetBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("oneObject"), "target( x )", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "target( x)", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "target (x )", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "target(x )", new String[]{"x"});
assertParameterNames(getMethod("oneObject"), "foo() && target(x)", new String[]{"x"});
}
@Test
public void testTargetBindingTwoCandidates() {
assertException(getMethod("oneObject"), "target(x) || target(y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testTargetBindingWithBadPointcutExpressions() {
assertException(getMethod("oneObject"), "target(", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
assertException(getMethod("oneObject"), "target(x && foo()", IllegalStateException.class,
"Failed to bind all argument names: 1 argument(s) could not be bound");
}
@Test
public void testArgsBindingOneObject() {
assertParameterNames(getMethod("oneObject"), "args(x)", new String[]{"x"});
}
@Test
public void testArgsBindingOneObjectTwoCandidates() {
assertException(getMethod("oneObject"), "args(x,y)", AmbiguousBindingException.class,
"Found 2 candidate this(), target() or args() variables but only one unbound argument slot");
}
@Test
public void testAmbiguousArgsBinding() {
assertException(getMethod("twoObjects"), "args(x,y)", AmbiguousBindingException.class,
"Still 2 unbound args at this(),target(),args() binding stage, with no way to determine between them");
}
@Test
public void testArgsOnePrimitive() {
assertParameterNames(getMethod("onePrimitive"), "args(count)", new String[]{"count"});
}
@Test
public void testArgsOnePrimitiveOneObject() {
assertException(getMethod("oneObjectOnePrimitive"), "args(count,obj)", AmbiguousBindingException.class,
"Found 2 candidate variable names but only one candidate binding slot when matching primitive args");
}
@Test
public void testThisAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && this(obj)", new String[]{"obj", "count"});
}
@Test
public void testTargetAndPrimitive() {
assertParameterNames(getMethod("oneObjectOnePrimitive"), "args(count) && target(obj)", new String[]{"obj", "count"});
}
@Test
public void testThrowingAndPrimitive() {
assertParameterNames(getMethod("oneThrowableOnePrimitive"), "args(count)", null, "ex", new String[]{"ex", "count"});
}
@Test
public void testAllTogetherNow() {
assertParameterNames(getMethod("theBigOne"), "this(foo) && args(x)", null, "ex", new String[]{"thisJoinPoint", "ex", "x", "foo"});
}
@Test
public void testReferenceBinding() {
assertParameterNames(getMethod("onePrimitive"),"somepc(foo)",new String[] {"foo"});
}
@Test
public void testReferenceBindingWithAlternateTokenizations() {
assertParameterNames(getMethod("onePrimitive"),"call(bar *) && somepc(foo)",new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc ( foo )",new String[] {"foo"});
assertParameterNames(getMethod("onePrimitive"),"somepc( foo)",new String[] {"foo"});
}
protected Method getMethod(String name) {
// assumes no overloading of test methods...
Method[] candidates = this.getClass().getMethods();
for (int i = 0; i < candidates.length; i++) {
if (candidates[i].getName().equals(name)) {
return candidates[i];
}
}
fail("Bad test specification, no method '" + name + "' found in test class");
return null;
}
protected void assertParameterNames(Method m, String pointcut, String[] parameterNames) {
assertParameterNames(m, pointcut, null, null, parameterNames);
}
protected void assertParameterNames(Method m, String pointcut, String returning, String throwing, String[] parameterNames) {
assertEquals("bad test specification, must have same number of parameter names as method arguments",
m.getParameterTypes().length, parameterNames.length);
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true);
discoverer.setReturningName(returning);
discoverer.setThrowingName(throwing);
String[] discoveredNames = discoverer.getParameterNames(m);
String formattedExpectedNames = format(parameterNames);
String formattedActualNames = format(discoveredNames);
assertEquals("Expecting " + parameterNames.length + " parameter names in return set '" +
formattedExpectedNames + "', but found " + discoveredNames.length +
" '" + formattedActualNames + "'",
parameterNames.length, discoveredNames.length);
for (int i = 0; i < discoveredNames.length; i++) {
assertNotNull("Parameter names must never be null", discoveredNames[i]);
assertEquals("Expecting parameter " + i + " to be named '" +
parameterNames[i] + "' but was '" + discoveredNames[i] + "'",
parameterNames[i], discoveredNames[i]);
}
}
protected void assertException(Method m, String pointcut, Class<?> exceptionType, String message) {
assertException(m, pointcut, null, null, exceptionType, message);
}
protected void assertException(Method m, String pointcut, String returning, String throwing, Class<?> exceptionType, String message) {
AspectJAdviceParameterNameDiscoverer discoverer = new AspectJAdviceParameterNameDiscoverer(pointcut);
discoverer.setRaiseExceptions(true);
discoverer.setReturningName(returning);
discoverer.setThrowingName(throwing);
try {
discoverer.getParameterNames(m);
fail("Expecting " + exceptionType.getName() + " with message '" + message + "'");
} catch (RuntimeException expected) {
assertEquals("Expecting exception of type " + exceptionType.getName(),
exceptionType, expected.getClass());
assertEquals("Exception message does not match expected", message, expected.getMessage());
}
}
private static String format(String[] names) {
StringBuffer sb = new StringBuffer();
sb.append("(");
for (int i = 0; i < names.length; i++) {
sb.append(names[i]);
if ((i + 1) < names.length) {
sb.append(",");
}
}
sb.append(")");
return sb.toString();
}
}

View File

@@ -0,0 +1,370 @@
/*
* 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;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import test.beans.IOther;
import test.beans.ITestBean;
import test.beans.TestBean;
import test.beans.subpkg.DeepBean;
/**
* @author Rob Harrop
* @author Rod Johnson
* @author Chris Beams
*/
public final class AspectJExpressionPointcutTests {
public static final String MATCH_ALL_METHODS = "execution(* *(..))";
private Method getAge;
private Method setAge;
private Method setSomeNumber;
private Method isPostProcessed;
@Before
public void setUp() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge", (Class<?>[])null);
setAge = TestBean.class.getMethod("setAge", new Class[]{int.class});
setSomeNumber = TestBean.class.getMethod("setSomeNumber", new Class[]{Number.class});
isPostProcessed = TestBean.class.getMethod("isPostProcessed", (Class[]) null);
}
@Test
public void testMatchExplicit() {
String expression = "execution(int test.beans.TestBean.getAge())";
Pointcut pointcut = getPointcut(expression);
ClassFilter classFilter = pointcut.getClassFilter();
MethodMatcher methodMatcher = pointcut.getMethodMatcher();
assertMatchesTestBeanClass(classFilter);
// not currently testable in a reliable fashion
//assertDoesNotMatchStringClass(classFilter);
assertFalse("Should not be a runtime match", methodMatcher.isRuntime());
assertMatchesGetAge(methodMatcher);
assertFalse("Expression should match setAge() method", methodMatcher.matches(setAge, TestBean.class));
}
@Test
public void testMatchWithTypePattern() throws Exception {
String expression = "execution(* *..TestBean.*Age(..))";
Pointcut pointcut = getPointcut(expression);
ClassFilter classFilter = pointcut.getClassFilter();
MethodMatcher methodMatcher = pointcut.getMethodMatcher();
assertMatchesTestBeanClass(classFilter);
// not currently testable in a reliable fashion
//assertDoesNotMatchStringClass(classFilter);
assertFalse("Should not be a runtime match", methodMatcher.isRuntime());
assertMatchesGetAge(methodMatcher);
assertTrue("Expression should match setAge(int) method", methodMatcher.matches(setAge, TestBean.class));
}
@Test
public void testThis() throws SecurityException, NoSuchMethodException{
testThisOrTarget("this");
}
@Test
public void testTarget() throws SecurityException, NoSuchMethodException {
testThisOrTarget("target");
}
public static class OtherIOther implements IOther {
public void absquatulate() {
// Empty
}
}
/**
* This and target are equivalent. Really instanceof pointcuts.
* @throws Exception
* @param which this or target
* @throws NoSuchMethodException
* @throws SecurityException
*/
private void testThisOrTarget(String which) throws SecurityException, NoSuchMethodException {
String matchesTestBean = which + "(test.beans.TestBean)";
String matchesIOther = which + "(test.beans.IOther)";
AspectJExpressionPointcut testBeanPc = new AspectJExpressionPointcut();
testBeanPc.setExpression(matchesTestBean);
AspectJExpressionPointcut iOtherPc = new AspectJExpressionPointcut();
iOtherPc.setExpression(matchesIOther);
assertTrue(testBeanPc.matches(TestBean.class));
assertTrue(testBeanPc.matches(getAge, TestBean.class));
assertTrue(iOtherPc.matches(OtherIOther.class.getMethod("absquatulate", (Class<?>[])null),
OtherIOther.class));
assertFalse(testBeanPc.matches(OtherIOther.class.getMethod("absquatulate", (Class<?>[])null),
OtherIOther.class));
}
@Test
public void testWithinRootPackage() throws SecurityException, NoSuchMethodException {
testWithinPackage(false);
}
@Test
public void testWithinRootAndSubpackages() throws SecurityException, NoSuchMethodException {
testWithinPackage(true);
}
private void testWithinPackage(boolean matchSubpackages) throws SecurityException, NoSuchMethodException {
String withinBeansPackage = "within(test.beans.";
// Subpackages are matched by **
if (matchSubpackages) {
withinBeansPackage += ".";
}
withinBeansPackage = withinBeansPackage + "*)";
AspectJExpressionPointcut withinBeansPc = new AspectJExpressionPointcut();
withinBeansPc.setExpression(withinBeansPackage);
assertTrue(withinBeansPc.matches(TestBean.class));
assertTrue(withinBeansPc.matches(getAge, TestBean.class));
assertEquals(matchSubpackages, withinBeansPc.matches(DeepBean.class));
assertEquals(matchSubpackages, withinBeansPc.matches(
DeepBean.class.getMethod("aMethod", String.class), DeepBean.class));
assertFalse(withinBeansPc.matches(String.class));
assertFalse(withinBeansPc.matches(OtherIOther.class.getMethod("absquatulate", (Class<?>[])null),
OtherIOther.class));
}
@Test
public void testFriendlyErrorOnNoLocationClassMatching() {
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
try {
pc.matches(ITestBean.class);
fail();
}
catch (IllegalStateException ex) {
assertTrue(ex.getMessage().indexOf("expression") != -1);
}
}
@Test
public void testFriendlyErrorOnNoLocation2ArgMatching() {
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
try {
pc.matches(getAge, ITestBean.class);
fail();
}
catch (IllegalStateException ex) {
assertTrue(ex.getMessage().indexOf("expression") != -1);
}
}
@Test
public void testFriendlyErrorOnNoLocation3ArgMatching() {
AspectJExpressionPointcut pc = new AspectJExpressionPointcut();
try {
pc.matches(getAge, ITestBean.class, (Object[]) null);
fail();
}
catch (IllegalStateException ex) {
assertTrue(ex.getMessage().indexOf("expression") != -1);
}
}
@Test
public void testMatchWithArgs() throws Exception {
String expression = "execution(void test.beans.TestBean.setSomeNumber(Number)) && args(Double)";
Pointcut pointcut = getPointcut(expression);
ClassFilter classFilter = pointcut.getClassFilter();
MethodMatcher methodMatcher = pointcut.getMethodMatcher();
assertMatchesTestBeanClass(classFilter);
// not currently testable in a reliable fashion
//assertDoesNotMatchStringClass(classFilter);
assertTrue("Should match with setSomeNumber with Double input",
methodMatcher.matches(setSomeNumber, TestBean.class, new Object[]{new Double(12)}));
assertFalse("Should not match setSomeNumber with Integer input",
methodMatcher.matches(setSomeNumber, TestBean.class, new Object[]{new Integer(11)}));
assertFalse("Should not match getAge", methodMatcher.matches(getAge, TestBean.class, null));
assertTrue("Should be a runtime match", methodMatcher.isRuntime());
}
@Test
public void testSimpleAdvice() {
String expression = "execution(int test.beans.TestBean.getAge())";
CallCountingInterceptor interceptor = new CallCountingInterceptor();
TestBean testBean = getAdvisedProxy(expression, interceptor);
assertEquals("Calls should be 0", 0, interceptor.getCount());
testBean.getAge();
assertEquals("Calls should be 1", 1, interceptor.getCount());
testBean.setAge(90);
assertEquals("Calls should still be 1", 1, interceptor.getCount());
}
@Test
public void testDynamicMatchingProxy() {
String expression = "execution(void test.beans.TestBean.setSomeNumber(Number)) && args(Double)";
CallCountingInterceptor interceptor = new CallCountingInterceptor();
TestBean testBean = getAdvisedProxy(expression, interceptor);
assertEquals("Calls should be 0", 0, interceptor.getCount());
testBean.setSomeNumber(new Double(30));
assertEquals("Calls should be 1", 1, interceptor.getCount());
testBean.setSomeNumber(new Integer(90));
assertEquals("Calls should be 1", 1, interceptor.getCount());
}
@Test
public void testInvalidExpression() {
String expression = "execution(void test.beans.TestBean.setSomeNumber(Number) && args(Double)";
try {
getPointcut(expression).getClassFilter(); // call to getClassFilter forces resolution
fail("Invalid expression should throw IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
assertTrue(true);
System.out.println(ex.getMessage());
}
}
private TestBean getAdvisedProxy(String pointcutExpression, CallCountingInterceptor interceptor) {
TestBean target = new TestBean();
Pointcut pointcut = getPointcut(pointcutExpression);
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setAdvice(interceptor);
advisor.setPointcut(pointcut);
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvisor(advisor);
return (TestBean) pf.getProxy();
}
private void assertMatchesGetAge(MethodMatcher methodMatcher) {
assertTrue("Expression should match getAge() method", methodMatcher.matches(getAge, TestBean.class));
}
private void assertMatchesTestBeanClass(ClassFilter classFilter) {
assertTrue("Expression should match TestBean class", classFilter.matches(TestBean.class));
}
private void assertDoesNotMatchStringClass(ClassFilter classFilter) {
assertFalse("Expression should not match String class", classFilter.matches(String.class));
}
@Test
public void testWithUnsupportedPointcutPrimitive() throws Exception {
String expression = "call(int test.beans.TestBean.getAge())";
try {
getPointcut(expression).getClassFilter(); // call to getClassFilter forces resolution...
fail("Should not support call pointcuts");
}
catch (UnsupportedPointcutPrimitiveException ex) {
assertEquals("Should not support call pointcut", PointcutPrimitive.CALL, ex.getUnsupportedPrimitive());
}
}
@Test
public void testAndSubstitution() {
Pointcut pc = getPointcut("execution(* *(..)) and args(String)");
PointcutExpression expr =
((AspectJExpressionPointcut) pc).getPointcutExpression();
assertEquals("execution(* *(..)) && args(String)",expr.getPointcutExpression());
}
@Test
public void testMultipleAndSubstitutions() {
Pointcut pc = getPointcut("execution(* *(..)) and args(String) and this(Object)");
PointcutExpression expr =
((AspectJExpressionPointcut) pc).getPointcutExpression();
assertEquals("execution(* *(..)) && args(String) && this(Object)",expr.getPointcutExpression());
}
private Pointcut getPointcut(String expression) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expression);
return pointcut;
}
}
class CallCountingInterceptor implements MethodInterceptor {
private int count;
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
count++;
return methodInvocation.proceed();
}
public int getCount() {
return count;
}
public void reset() {
this.count = 0;
}
}

View File

@@ -0,0 +1,100 @@
/*
* 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;
import static org.junit.Assert.*;
import org.junit.Test;
import test.beans.TestBean;
/**
* Tests for matching of bean() pointcut designator.
*
* @author Ramnivas Laddad
* @author Chris Beams
*/
public final class BeanNamePointcutMatchingTests {
@Test
public void testMatchingPointcuts() {
assertMatch("someName", "bean(someName)");
// Spring bean names are less restrictive compared to AspectJ names (methods, types etc.)
// MVC Controller-kind
assertMatch("someName/someOtherName", "bean(someName/someOtherName)");
assertMatch("someName/foo/someOtherName", "bean(someName/*/someOtherName)");
assertMatch("someName/foo/bar/someOtherName", "bean(someName/*/someOtherName)");
assertMatch("someName/*/**", "bean(someName/*)");
// JMX-kind
assertMatch("service:name=traceService", "bean(service:name=traceService)");
assertMatch("service:name=traceService", "bean(service:name=*)");
assertMatch("service:name=traceService", "bean(*:name=traceService)");
// Wildcards
assertMatch("someName", "bean(*someName)");
assertMatch("someName", "bean(*Name)");
assertMatch("someName", "bean(*)");
assertMatch("someName", "bean(someName*)");
assertMatch("someName", "bean(some*)");
assertMatch("someName", "bean(some*Name)");
assertMatch("someName", "bean(*some*Name*)");
assertMatch("someName", "bean(*s*N*)");
// Or, and, not expressions
assertMatch("someName", "bean(someName) || bean(someOtherName)");
assertMatch("someOtherName", "bean(someName) || bean(someOtherName)");
assertMatch("someName", "!bean(someOtherName)");
assertMatch("someName", "bean(someName) || !bean(someOtherName)");
assertMatch("someName", "bean(someName) && !bean(someOtherName)");
}
@Test
public void testNonMatchingPointcuts() {
assertMisMatch("someName", "bean(someNamex)");
assertMisMatch("someName", "bean(someX*Name)");
// And, not expressions
assertMisMatch("someName", "bean(someName) && bean(someOtherName)");
assertMisMatch("someName", "!bean(someName)");
assertMisMatch("someName", "!bean(someName) && bean(someOtherName)");
assertMisMatch("someName", "!bean(someName) || bean(someOtherName)");
}
private void assertMatch(String beanName, String pcExpression) {
assertTrue("Unexpected mismatch for bean \"" + beanName + "\" for pcExpression \"" + pcExpression + "\"",
matches(beanName, pcExpression));
}
private void assertMisMatch(String beanName, String pcExpression) {
assertFalse("Unexpected match for bean \"" + beanName + "\" for pcExpression \"" + pcExpression + "\"",
matches(beanName, pcExpression));
}
private static boolean matches(final String beanName, String pcExpression) {
@SuppressWarnings("serial")
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut() {
protected String getCurrentProxiedBeanName() {
return beanName;
}
};
pointcut.setExpression(pcExpression);
return pointcut.matches(TestBean.class);
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright 2002-2009 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;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.JoinPoint.StaticPart;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.aspectj.lang.reflect.SourceLocation;
import org.aspectj.runtime.reflect.Factory;
import static org.junit.Assert.*;
import org.junit.Test;
import test.beans.ITestBean;
import test.beans.TestBean;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.AopContext;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.support.AopUtils;
/**
* @author Rod Johnson
* @author Chris Beams
* @author Ramnivas Laddad
* @since 2.0
*/
public final class MethodInvocationProceedingJoinPointTests {
@Test
public void testingBindingWithJoinPoint() {
try {
AbstractAspectJAdvice.currentJoinPoint();
fail("Needs to be bound by interceptor action");
}
catch (IllegalStateException ex) {
// expected
}
}
@Test
public void testingBindingWithProceedingJoinPoint() {
try {
AbstractAspectJAdvice.currentJoinPoint();
fail("Needs to be bound by interceptor action");
}
catch (IllegalStateException ex) {
// expected
}
}
@Test
public void testCanGetMethodSignatureFromJoinPoint() {
final Object raw = new TestBean();
// Will be set by advice during a method call
final int newAge = 23;
ProxyFactory pf = new ProxyFactory(raw);
pf.setExposeProxy(true);
pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
pf.addAdvice(new MethodBeforeAdvice() {
private int depth;
public void before(Method method, Object[] args, Object target) throws Throwable {
JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint();
assertTrue("Method named in toString", jp.toString().contains(method.getName()));
// Ensure that these don't cause problems
jp.toShortString();
jp.toLongString();
assertSame(target, AbstractAspectJAdvice.currentJoinPoint().getTarget());
assertFalse(AopUtils.isAopProxy(AbstractAspectJAdvice.currentJoinPoint().getTarget()));
ITestBean thisProxy = (ITestBean) AbstractAspectJAdvice.currentJoinPoint().getThis();
assertTrue(AopUtils.isAopProxy(AbstractAspectJAdvice.currentJoinPoint().getThis()));
assertNotSame(target, thisProxy);
// Check getting again doesn't cause a problem
assertSame(thisProxy, AbstractAspectJAdvice.currentJoinPoint().getThis());
// Try reentrant call--will go through this advice.
// Be sure to increment depth to avoid infinite recursion
if (depth++ == 0) {
// Check that toString doesn't cause a problem
thisProxy.toString();
// Change age, so this will be returned by invocation
thisProxy.setAge(newAge);
assertEquals(newAge, thisProxy.getAge());
}
assertSame(AopContext.currentProxy(), thisProxy);
assertSame(target, raw);
assertSame(method.getName(), AbstractAspectJAdvice.currentJoinPoint().getSignature().getName());
assertEquals(method.getModifiers(), AbstractAspectJAdvice.currentJoinPoint().getSignature().getModifiers());
MethodSignature msig = (MethodSignature) AbstractAspectJAdvice.currentJoinPoint().getSignature();
assertSame("Return same MethodSignature repeatedly", msig, AbstractAspectJAdvice.currentJoinPoint().getSignature());
assertSame("Return same JoinPoint repeatedly", AbstractAspectJAdvice.currentJoinPoint(), AbstractAspectJAdvice.currentJoinPoint());
assertEquals(method.getDeclaringClass(), msig.getDeclaringType());
assertTrue(Arrays.equals(method.getParameterTypes(), msig.getParameterTypes()));
assertEquals(method.getReturnType(), msig.getReturnType());
assertTrue(Arrays.equals(method.getExceptionTypes(), msig.getExceptionTypes()));
msig.toLongString();
msig.toShortString();
}
});
ITestBean itb = (ITestBean) pf.getProxy();
// Any call will do
assertEquals("Advice reentrantly set age", newAge, itb.getAge());
}
@Test
public void testCanGetSourceLocationFromJoinPoint() {
final Object raw = new TestBean();
ProxyFactory pf = new ProxyFactory(raw);
pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
pf.addAdvice(new MethodBeforeAdvice() {
public void before(Method method, Object[] args, Object target) throws Throwable {
SourceLocation sloc = AbstractAspectJAdvice.currentJoinPoint().getSourceLocation();
assertEquals("Same source location must be returned on subsequent requests", sloc, AbstractAspectJAdvice.currentJoinPoint().getSourceLocation());
assertEquals(TestBean.class, sloc.getWithinType());
try {
sloc.getLine();
fail("Can't get line number");
}
catch (UnsupportedOperationException ex) {
// Expected
}
try {
sloc.getFileName();
fail("Can't get file name");
}
catch (UnsupportedOperationException ex) {
// Expected
}
}
});
ITestBean itb = (ITestBean) pf.getProxy();
// Any call will do
itb.getAge();
}
@Test
public void testCanGetStaticPartFromJoinPoint() {
final Object raw = new TestBean();
ProxyFactory pf = new ProxyFactory(raw);
pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
pf.addAdvice(new MethodBeforeAdvice() {
public void before(Method method, Object[] args, Object target) throws Throwable {
StaticPart staticPart = AbstractAspectJAdvice.currentJoinPoint().getStaticPart();
assertEquals("Same static part must be returned on subsequent requests", staticPart, AbstractAspectJAdvice.currentJoinPoint().getStaticPart());
assertEquals(ProceedingJoinPoint.METHOD_EXECUTION, staticPart.getKind());
assertSame(AbstractAspectJAdvice.currentJoinPoint().getSignature(), staticPart.getSignature());
assertEquals(AbstractAspectJAdvice.currentJoinPoint().getSourceLocation(), staticPart.getSourceLocation());
}
});
ITestBean itb = (ITestBean) pf.getProxy();
// Any call will do
itb.getAge();
}
@Test
public void toShortAndLongStringFormedCorrectly() throws Exception {
final Object raw = new TestBean();
ProxyFactory pf = new ProxyFactory(raw);
pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
pf.addAdvice(new MethodBeforeAdvice() {
public void before(Method method, Object[] args, Object target) throws Throwable {
// makeEncSJP, although meant for computing the enclosing join point,
// it serves our purpose here
JoinPoint.StaticPart aspectJVersionJp = Factory.makeEncSJP(method);
JoinPoint jp = AbstractAspectJAdvice.currentJoinPoint();
assertEquals(aspectJVersionJp.getSignature().toLongString(), jp.getSignature().toLongString());
assertEquals(aspectJVersionJp.getSignature().toShortString(), jp.getSignature().toShortString());
assertEquals(aspectJVersionJp.getSignature().toString(), jp.getSignature().toString());
assertEquals(aspectJVersionJp.toLongString(), jp.toLongString());
assertEquals(aspectJVersionJp.toShortString(), jp.toShortString());
assertEquals(aspectJVersionJp.toString(), jp.toString());
}
});
ITestBean itb = (ITestBean) pf.getProxy();
itb.getAge();
itb.setName("foo");
itb.getDoctor();
itb.getStringArray();
itb.getSpouses();
itb.setSpouse(new TestBean());
try {
itb.unreliableFileOperation();
} catch (IOException ex) {
// we don't realy care...
}
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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;
import org.junit.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer.AmbiguousBindingException;
/**
* Tests just the annotation binding part of {@link AspectJAdviceParameterNameDiscoverer};
* see supertype for remaining tests.
*
* @author Adrian Colyer
* @author Chris Beams
*/
public final class TigerAspectJAdviceParameterNameDiscovererTests
extends AspectJAdviceParameterNameDiscovererTests {
@Test
public void testAtThis() {
assertParameterNames(getMethod("oneAnnotation"),"@this(a)",new String[]{"a"});
}
@Test
public void testAtTarget() {
assertParameterNames(getMethod("oneAnnotation"),"@target(a)",new String[]{"a"});
}
@Test
public void testAtArgs() {
assertParameterNames(getMethod("oneAnnotation"),"@args(a)",new String[]{"a"});
}
@Test
public void testAtWithin() {
assertParameterNames(getMethod("oneAnnotation"),"@within(a)",new String[]{"a"});
}
@Test
public void testAtWithincode() {
assertParameterNames(getMethod("oneAnnotation"),"@withincode(a)",new String[]{"a"});
}
@Test
public void testAtAnnotation() {
assertParameterNames(getMethod("oneAnnotation"),"@annotation(a)",new String[]{"a"});
}
@Test
public void testAmbiguousAnnotationTwoVars() {
assertException(getMethod("twoAnnotations"),"@annotation(a) && @this(x)",AmbiguousBindingException.class,
"Found 2 potential annotation variable(s), and 2 potential argument slots");
}
@Test
public void testAmbiguousAnnotationOneVar() {
assertException(getMethod("oneAnnotation"),"@annotation(a) && @this(x)",IllegalArgumentException.class,
"Found 2 candidate annotation binding variables but only one potential argument binding slot");
}
@Test
public void testAnnotationMedley() {
assertParameterNames(getMethod("annotationMedley"),"@annotation(a) && args(count) && this(foo)",null,"ex",
new String[] {"ex","foo","count","a"});
}
public void oneAnnotation(MyAnnotation ann) {}
public void twoAnnotations(MyAnnotation ann, MyAnnotation anotherAnn) {}
public void annotationMedley(Throwable t, Object foo, int x, MyAnnotation ma) {}
@interface MyAnnotation {}
}

View File

@@ -0,0 +1,296 @@
/*
* 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.aspectj;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import test.annotation.EmptySpringAnnotation;
import test.annotation.transaction.Tx;
import test.beans.TestBean;
/**
* Java5-specific {@link AspectJExpressionPointcutTests}.
*
* @author Rod Johnson
* @author Chris Beams
*/
public final class TigerAspectJExpressionPointcutTests {
// TODO factor into static in AspectJExpressionPointcut
private Method getAge;
private Map<String,Method> methodsOnHasGeneric = new HashMap<String,Method>();
@Before
public void setUp() throws NoSuchMethodException {
getAge = TestBean.class.getMethod("getAge", (Class[]) null);
// Assumes no overloading
for (Method m : HasGeneric.class.getMethods()) {
methodsOnHasGeneric.put(m.getName(), m);
}
}
public static class HasGeneric {
public void setFriends(List<TestBean> friends) {
}
public void setEnemies(List<TestBean> enemies) {
}
public void setPartners(List<?> partners) {
}
public void setPhoneNumbers(List<String> numbers) {
}
}
@Test
public void testMatchGenericArgument() {
String expression = "execution(* set*(java.util.List<test.beans.TestBean>) )";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
// TODO this will currently map, would be nice for optimization
//assertTrue(ajexp.matches(HasGeneric.class));
//assertFalse(ajexp.matches(TestBean.class));
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertTrue(ajexp.matches(takesGenericList, HasGeneric.class));
assertTrue(ajexp.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class));
assertFalse(ajexp.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class));
assertFalse(ajexp.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class));
assertFalse(ajexp.matches(getAge, TestBean.class));
}
@Test
public void testMatchVarargs() throws SecurityException, NoSuchMethodException {
class MyTemplate {
public int queryForInt(String sql, Object... params) {
return 0;
}
}
String expression = "execution(int *.*(String, Object...))";
AspectJExpressionPointcut jdbcVarArgs = new AspectJExpressionPointcut();
jdbcVarArgs.setExpression(expression);
// TODO: the expression above no longer matches Object[]
// assertFalse(jdbcVarArgs.matches(
// JdbcTemplate.class.getMethod("queryForInt", String.class, Object[].class),
// JdbcTemplate.class));
assertTrue(jdbcVarArgs.matches(
MyTemplate.class.getMethod("queryForInt", String.class, Object[].class),
MyTemplate.class));
Method takesGenericList = methodsOnHasGeneric.get("setFriends");
assertFalse(jdbcVarArgs.matches(takesGenericList, HasGeneric.class));
assertFalse(jdbcVarArgs.matches(methodsOnHasGeneric.get("setEnemies"), HasGeneric.class));
assertFalse(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPartners"), HasGeneric.class));
assertFalse(jdbcVarArgs.matches(methodsOnHasGeneric.get("setPhoneNumbers"), HasGeneric.class));
assertFalse(jdbcVarArgs.matches(getAge, TestBean.class));
}
@Test
public void testMatchAnnotationOnClassWithAtWithin() throws SecurityException, NoSuchMethodException {
String expression = "@within(test.annotation.transaction.Tx)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithoutBinding() throws SecurityException, NoSuchMethodException {
String expression = "within(@test.annotation.transaction.Tx *)";
testMatchAnnotationOnClass(expression);
}
@Test
public void testMatchAnnotationOnClassWithSubpackageWildcard() throws SecurityException, NoSuchMethodException {
String expression = "within(@(test.annotation..*) *)";
AspectJExpressionPointcut springAnnotatedPc = testMatchAnnotationOnClass(expression);
assertFalse(springAnnotatedPc.matches(TestBean.class.getMethod("setName", String.class),
TestBean.class));
assertTrue(springAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo", (Class[]) null),
SpringAnnotated.class));
expression = "within(@(test.annotation.transaction..*) *)";
AspectJExpressionPointcut springTxAnnotatedPc = testMatchAnnotationOnClass(expression);
assertFalse(springTxAnnotatedPc.matches(SpringAnnotated.class.getMethod("foo", (Class[]) null),
SpringAnnotated.class));
}
@Test
public void testMatchAnnotationOnClassWithExactPackageWildcard() throws SecurityException, NoSuchMethodException {
String expression = "within(@(test.annotation.transaction.*) *)";
testMatchAnnotationOnClass(expression);
}
private AspectJExpressionPointcut testMatchAnnotationOnClass(String expression) throws SecurityException, NoSuchMethodException {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertFalse(ajexp.matches(getAge, TestBean.class));
assertTrue(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class));
assertTrue(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertTrue(ajexp.matches(BeanB.class.getMethod("setName", String.class), BeanB.class));
assertFalse(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
return ajexp;
}
@Test
public void testAnnotationOnMethodWithFQN() throws SecurityException, NoSuchMethodException {
String expression = "@annotation(test.annotation.transaction.Tx)";
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(expression);
assertFalse(ajexp.matches(getAge, TestBean.class));
assertFalse(ajexp.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class));
assertFalse(ajexp.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertTrue(ajexp.matches(BeanA.class.getMethod("getAge", (Class[]) null), BeanA.class));
assertFalse(ajexp.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
}
@Test
public void testAnnotationOnMethodWithWildcard() throws SecurityException, NoSuchMethodException {
String expression = "execution(@(test.annotation..*) * *(..))";
AspectJExpressionPointcut anySpringMethodAnnotation = new AspectJExpressionPointcut();
anySpringMethodAnnotation.setExpression(expression);
assertFalse(anySpringMethodAnnotation.matches(getAge, TestBean.class));
assertFalse(anySpringMethodAnnotation.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class));
assertFalse(anySpringMethodAnnotation.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertTrue(anySpringMethodAnnotation.matches(BeanA.class.getMethod("getAge", (Class[]) null), BeanA.class));
assertFalse(anySpringMethodAnnotation.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
}
@Test
public void testAnnotationOnMethodArgumentsWithFQN() throws SecurityException, NoSuchMethodException {
String expression = "@args(*, test.annotation.EmptySpringAnnotation))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertFalse(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge", (Class[]) null), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertTrue(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class));
// True because it maybeMatches with potential argument subtypes
assertTrue(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class));
assertFalse(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class,
new Object[] { new TestBean(), new BeanA()})
);
}
@Test
public void testAnnotationOnMethodArgumentsWithWildcards() throws SecurityException, NoSuchMethodException {
String expression = "execution(* *(*, @(test..*) *))";
AspectJExpressionPointcut takesSpringAnnotatedArgument2 = new AspectJExpressionPointcut();
takesSpringAnnotatedArgument2.setExpression(expression);
assertFalse(takesSpringAnnotatedArgument2.matches(getAge, TestBean.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("foo", (Class[]) null), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(HasTransactionalAnnotation.class.getMethod("bar", String.class), HasTransactionalAnnotation.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("getAge", (Class[]) null), BeanA.class));
assertFalse(takesSpringAnnotatedArgument2.matches(BeanA.class.getMethod("setName", String.class), BeanA.class));
assertTrue(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesAnnotatedParameters", TestBean.class, SpringAnnotated.class),
ProcessesSpringAnnotatedParameters.class));
assertFalse(takesSpringAnnotatedArgument2.matches(
ProcessesSpringAnnotatedParameters.class.getMethod("takesNoAnnotatedParameters", TestBean.class, BeanA.class),
ProcessesSpringAnnotatedParameters.class));
}
public static class ProcessesSpringAnnotatedParameters {
public void takesAnnotatedParameters(TestBean tb, SpringAnnotated sa) {
}
public void takesNoAnnotatedParameters(TestBean tb, BeanA tb3) {
}
}
@Tx
public static class HasTransactionalAnnotation {
public void foo() {
}
public Object bar(String foo) {
throw new UnsupportedOperationException();
}
}
@EmptySpringAnnotation
public static class SpringAnnotated {
public void foo() {
}
}
static class BeanA {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
@Tx
public int getAge() {
return age;
}
}
@Tx
static class BeanB {
private String name;
public void setName(String name) {
this.name = name;
}
}
}

View File

@@ -0,0 +1,174 @@
package org.springframework.aop.aspectj;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.core.OverridingClassLoader;
/**
* @author Dave Syer
*/
public class TrickyAspectJPointcutExpressionTests {
@Test
public void testManualProxyJavaWithUnconditionalPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
testAdvice(new DefaultPointcutAdvisor(logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithStaticPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithDynamicPointcut() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl");
}
@Test
public void testManualProxyJavaWithDynamicPointcutAndProxyTargetClass() throws Exception {
TestService target = new TestServiceImpl();
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("@within(%s.Log)", getClass().getName()));
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, target, "TestServiceImpl", true);
}
@Test
public void testManualProxyJavaWithStaticPointcutAndTwoClassLoaders() throws Exception {
LogUserAdvice logAdvice = new LogUserAdvice();
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(String.format("execution(* %s.TestService.*(..))", getClass().getName()));
// Test with default class loader first...
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, new TestServiceImpl(), "TestServiceImpl");
// Then try again with a different class loader on the target...
SimpleThrowawayClassLoader loader = new SimpleThrowawayClassLoader(new TestServiceImpl().getClass().getClassLoader());
// Make sure the interface is loaded from the parent class loader
loader.excludeClass(TestService.class.getName());
loader.excludeClass(TestException.class.getName());
TestService other = (TestService) loader.loadClass(TestServiceImpl.class.getName()).newInstance();
testAdvice(new DefaultPointcutAdvisor(pointcut, logAdvice), logAdvice, other, "TestServiceImpl");
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message)
throws Exception {
testAdvice(advisor, logAdvice, target, message, false);
}
private void testAdvice(Advisor advisor, LogUserAdvice logAdvice, TestService target, String message,
boolean proxyTargetClass) throws Exception {
logAdvice.reset();
ProxyFactory factory = new ProxyFactory(target);
factory.setProxyTargetClass(proxyTargetClass);
factory.addAdvisor(advisor);
TestService bean = (TestService) factory.getProxy();
assertEquals(0, logAdvice.getCountThrows());
try {
bean.sayHello();
fail("Expected exception");
} catch (TestException e) {
assertEquals(message, e.getMessage());
}
assertEquals(1, logAdvice.getCountThrows());
}
public static class SimpleThrowawayClassLoader extends OverridingClassLoader {
/**
* Create a new SimpleThrowawayClassLoader for the given class loader.
* @param parent the ClassLoader to build a throwaway ClassLoader for
*/
public SimpleThrowawayClassLoader(ClassLoader parent) {
super(parent);
}
}
public static class TestException extends RuntimeException {
public TestException(String string) {
super(string);
}
}
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public static @interface Log {
}
public static interface TestService {
public String sayHello();
}
@Log
public static class TestServiceImpl implements TestService{
public String sayHello() {
throw new TestException("TestServiceImpl");
}
}
public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice {
private int countBefore = 0;
private int countThrows = 0;
public void before(Method method, Object[] objects, Object o) throws Throwable {
countBefore++;
}
public void afterThrowing(Exception e) throws Throwable {
countThrows++;
throw e;
}
public int getCountBefore() {
return countBefore;
}
public int getCountThrows() {
return countThrows;
}
public void reset() {
countThrows = 0;
countBefore = 0;
}
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import test.beans.CountingTestBean;
import test.beans.IOther;
import test.beans.ITestBean;
import test.beans.TestBean;
import test.beans.subpkg.DeepBean;
/**
* Unit tests for the {@link TypePatternClassFilter} class.
*
* @author Rod Johnson
* @author Rick Evans
* @author Chris Beams
*/
public final class TypePatternClassFilterTests {
@Test(expected=IllegalArgumentException.class)
public void testInvalidPattern() {
// should throw - pattern must be recognized as invalid
new TypePatternClassFilter("-");
}
@Test
public void testValidPatternMatching() {
TypePatternClassFilter tpcf = new TypePatternClassFilter("test.beans.*");
assertTrue("Must match: in package", tpcf.matches(TestBean.class));
assertTrue("Must match: in package", tpcf.matches(ITestBean.class));
assertTrue("Must match: in package", tpcf.matches(IOther.class));
assertFalse("Must be excluded: in wrong package", tpcf.matches(DeepBean.class));
assertFalse("Must be excluded: in wrong package", tpcf.matches(BeanFactory.class));
assertFalse("Must be excluded: in wrong package", tpcf.matches(DefaultListableBeanFactory.class));
}
@Test
public void testSubclassMatching() {
TypePatternClassFilter tpcf = new TypePatternClassFilter("test.beans.ITestBean+");
assertTrue("Must match: in package", tpcf.matches(TestBean.class));
assertTrue("Must match: in package", tpcf.matches(ITestBean.class));
assertTrue("Must match: in package", tpcf.matches(CountingTestBean.class));
assertFalse("Must be excluded: not subclass", tpcf.matches(IOther.class));
assertFalse("Must be excluded: not subclass", tpcf.matches(DefaultListableBeanFactory.class));
}
@Test
public void testAndOrNotReplacement() {
TypePatternClassFilter tpcf = new TypePatternClassFilter("java.lang.Object or java.lang.String");
assertFalse("matches Number",tpcf.matches(Number.class));
assertTrue("matches Object",tpcf.matches(Object.class));
assertTrue("matchesString",tpcf.matches(String.class));
tpcf = new TypePatternClassFilter("java.lang.Number+ and java.lang.Float");
assertTrue("matches Float",tpcf.matches(Float.class));
assertFalse("matches Double",tpcf.matches(Double.class));
tpcf = new TypePatternClassFilter("java.lang.Number+ and not java.lang.Float");
assertFalse("matches Float",tpcf.matches(Float.class));
assertTrue("matches Double",tpcf.matches(Double.class));
}
@Test(expected=IllegalArgumentException.class)
public void testSetTypePatternWithNullArgument() throws Exception {
new TypePatternClassFilter(null);
}
@Test(expected=IllegalStateException.class)
public void testInvocationOfMatchesMethodBlowsUpWhenNoTypePatternHasBeenSet() throws Exception {
new TypePatternClassFilter().matches(String.class);
}
}

View File

@@ -0,0 +1,132 @@
/*
* 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.annotation;
import static org.junit.Assert.*;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.junit.Test;
import org.springframework.aop.aspectj.AspectJAdviceParameterNameDiscoverer;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* @author Adrian Colyer
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class ArgumentBindingTests {
@Test(expected=IllegalArgumentException.class)
public void testBindingInPointcutUsedByAdvice() {
TestBean tb = new TestBean();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
proxyFactory.addAspect(NamedPointcutWithArgs.class);
ITestBean proxiedTestBean = (ITestBean) proxyFactory.getProxy();
proxiedTestBean.setName("Supercalifragalisticexpialidocious"); // should throw
}
@Test(expected=IllegalStateException.class)
public void testAnnotationArgumentNameBinding() {
TransactionalBean tb = new TransactionalBean();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(tb);
proxyFactory.addAspect(PointcutWithAnnotationArgument.class);
ITransactionalBean proxiedTestBean = (ITransactionalBean) proxyFactory.getProxy();
proxiedTestBean.doInTransaction(); // should throw
}
@Test
public void testParameterNameDiscoverWithReferencePointcut() throws Exception {
AspectJAdviceParameterNameDiscoverer discoverer =
new AspectJAdviceParameterNameDiscoverer("somepc(formal) && set(* *)");
discoverer.setRaiseExceptions(true);
Method methodUsedForParameterTypeDiscovery =
getClass().getMethod("methodWithOneParam", String.class);
String[] pnames = discoverer.getParameterNames(methodUsedForParameterTypeDiscovery);
assertEquals("one parameter name", 1, pnames.length);
assertEquals("formal", pnames[0]);
}
public void methodWithOneParam(String aParam) {
}
public interface ITransactionalBean {
@Transactional
void doInTransaction();
}
public static class TransactionalBean implements ITransactionalBean {
@Transactional
public void doInTransaction() {
}
}
}
/**
* Represents Spring's Transactional annotation without actually introducing the dependency
*/
@Retention(RetentionPolicy.RUNTIME)
@interface Transactional {
}
/**
* @author Juergen Hoeller
*/
@Aspect
class PointcutWithAnnotationArgument {
@Around(value = "execution(* org.springframework..*.*(..)) && @annotation(transaction)")
public Object around(ProceedingJoinPoint pjp, Transactional transaction) throws Throwable {
System.out.println("Invoked with transaction " + transaction);
throw new IllegalStateException();
}
}
/**
* @author Adrian Colyer
*/
@Aspect
class NamedPointcutWithArgs {
@Pointcut("execution(* *(..)) && args(s,..)")
public void pointcutWithArgs(String s) {}
@Around("pointcutWithArgs(aString)")
public Object doAround(ProceedingJoinPoint pjp, String aString) throws Throwable {
System.out.println("got '" + aString + "' at '" + pjp + "'");
throw new IllegalArgumentException(aString);
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.annotation;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcutTests;
import org.springframework.aop.framework.AopConfigException;
import test.aop.PerTargetAspect;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class AspectJPointcutAdvisorTests {
private AspectJAdvisorFactory af = new ReflectiveAspectJAdvisorFactory();
@Test
public void testSingleton() throws SecurityException, NoSuchMethodException {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(AspectJExpressionPointcutTests.MATCH_ALL_METHODS);
InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(af, ajexp,
new SingletonMetadataAwareAspectInstanceFactory(new AbstractAspectJAdvisorFactoryTests.ExceptionAspect(null),"someBean"),
TestBean.class.getMethod("getAge", (Class[]) null),1,"someBean");
assertSame(Pointcut.TRUE, ajpa.getAspectMetadata().getPerClausePointcut());
assertFalse(ajpa.isPerInstance());
}
@Test
public void testPerTarget() throws SecurityException, NoSuchMethodException {
AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();
ajexp.setExpression(AspectJExpressionPointcutTests.MATCH_ALL_METHODS);
InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(af, ajexp,
new SingletonMetadataAwareAspectInstanceFactory(new PerTargetAspect(),"someBean"), null, 1, "someBean");
assertNotSame(Pointcut.TRUE, ajpa.getAspectMetadata().getPerClausePointcut());
assertTrue(ajpa.getAspectMetadata().getPerClausePointcut() instanceof AspectJExpressionPointcut);
assertTrue(ajpa.isPerInstance());
assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getClassFilter().matches(TestBean.class));
assertFalse(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(
TestBean.class.getMethod("getAge", (Class[]) null),
TestBean.class));
assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(
TestBean.class.getMethod("getSpouse", (Class[]) null),
TestBean.class));
}
@Test(expected=AopConfigException.class)
public void testPerCflowTarget() {
testIllegalInstantiationModel(AbstractAspectJAdvisorFactoryTests.PerCflowAspect.class);
}
@Test(expected=AopConfigException.class)
public void testPerCflowBelowTarget() {
testIllegalInstantiationModel(AbstractAspectJAdvisorFactoryTests.PerCflowBelowAspect.class);
}
private void testIllegalInstantiationModel(Class<?> c) throws AopConfigException {
new AspectMetadata(c,"someBean");
}
}

View File

@@ -0,0 +1,64 @@
/*
* 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.annotation;
import static org.junit.Assert.*;
import org.aspectj.lang.reflect.PerClauseKind;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.annotation.AbstractAspectJAdvisorFactoryTests.ExceptionAspect;
import test.aop.PerTargetAspect;
/**
* @since 2.0
* @author Rod Johnson
* @author Chris Beams
*/
public final class AspectMetadataTests {
@Test(expected=IllegalArgumentException.class)
public void testNotAnAspect() {
new AspectMetadata(String.class,"someBean");
}
@Test
public void testSingletonAspect() {
AspectMetadata am = new AspectMetadata(ExceptionAspect.class,"someBean");
assertFalse(am.isPerThisOrPerTarget());
assertSame(Pointcut.TRUE, am.getPerClausePointcut());
assertEquals(PerClauseKind.SINGLETON, am.getAjType().getPerClause().getKind());
}
@Test
public void testPerTargetAspect() {
AspectMetadata am = new AspectMetadata(PerTargetAspect.class,"someBean");
assertTrue(am.isPerThisOrPerTarget());
assertNotSame(Pointcut.TRUE, am.getPerClausePointcut());
assertEquals(PerClauseKind.PERTARGET, am.getAjType().getPerClause().getKind());
}
@Test
public void testPerThisAspect() {
AspectMetadata am = new AspectMetadata(PerThisAspect.class,"someBean");
assertTrue(am.isPerThisOrPerTarget());
assertNotSame(Pointcut.TRUE, am.getPerClausePointcut());
assertEquals(PerClauseKind.PERTHIS, am.getAjType().getPerClause().getKind());
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright 2002-2010 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.annotation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import static org.junit.Assert.*;
import org.junit.Ignore;
import org.junit.Test;
import test.aop.PerThisAspect;
import test.util.SerializationTestUtils;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AspectProxyFactoryTests {
@Test(expected=IllegalArgumentException.class)
public void testWithNonAspect() {
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean());
proxyFactory.addAspect(TestBean.class);
}
@Test
public void testWithSimpleAspect() throws Exception {
TestBean bean = new TestBean();
bean.setAge(2);
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(bean);
proxyFactory.addAspect(MultiplyReturnValue.class);
ITestBean proxy = proxyFactory.getProxy();
assertEquals("Multiplication did not occur", bean.getAge() * 2, proxy.getAge());
}
@Test
public void testWithPerThisAspect() throws Exception {
TestBean bean1 = new TestBean();
TestBean bean2 = new TestBean();
AspectJProxyFactory pf1 = new AspectJProxyFactory(bean1);
pf1.addAspect(PerThisAspect.class);
AspectJProxyFactory pf2 = new AspectJProxyFactory(bean2);
pf2.addAspect(PerThisAspect.class);
ITestBean proxy1 = pf1.getProxy();
ITestBean proxy2 = pf2.getProxy();
assertEquals(0, proxy1.getAge());
assertEquals(1, proxy1.getAge());
assertEquals(0, proxy2.getAge());
assertEquals(2, proxy1.getAge());
}
@Test(expected=IllegalArgumentException.class)
public void testWithInstanceWithNonAspect() throws Exception {
AspectJProxyFactory pf = new AspectJProxyFactory();
pf.addAspect(new TestBean());
}
@Test
@Ignore // InstantiationModelAwarePointcutAdvisorImpl not serializable yet
public void testWithInstance() throws Exception {
MultiplyReturnValue aspect = new MultiplyReturnValue();
int multiple = 3;
aspect.setMultiple(multiple);
TestBean target = new TestBean();
target.setAge(24);
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(target);
proxyFactory.addAspect(aspect);
ITestBean proxy = proxyFactory.getProxy();
assertEquals(target.getAge() * multiple, proxy.getAge());
ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
assertEquals(target.getAge() * multiple, serializedProxy.getAge());
}
@Test(expected=IllegalArgumentException.class)
public void testWithNonSingletonAspectInstance() throws Exception {
AspectJProxyFactory pf = new AspectJProxyFactory();
pf.addAspect(new PerThisAspect());
}
public static interface ITestBean {
int getAge();
}
public static class TestBean implements ITestBean {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
/**
* @author Rod Johnson
*/
@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;
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.annotation;
/**
* Tests for ReflectiveAtAspectJAdvisorFactory.
* Tests are inherited: we only set the test fixture here.
*
* @author Rod Johnson
* @since 2.0
*/
public final class ReflectiveAspectJAdvisorFactoryTests extends AbstractAspectJAdvisorFactoryTests {
@Override
protected AspectJAdvisorFactory getFixture() {
return new ReflectiveAspectJAdvisorFactory();
}
}

View File

@@ -0,0 +1,106 @@
/*
* 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 org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.aop.config.AopNamespaceUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.PassThroughSourceExtractor;
import org.springframework.beans.factory.parsing.SourceExtractor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.factory.xml.XmlReaderContext;
import test.parsing.CollectingReaderEventListener;
/**
* @author Rob Harrop
* @author Chris Beams
*/
public final class AspectJNamespaceHandlerTests {
private ParserContext parserContext;
private CollectingReaderEventListener readerEventListener = new CollectingReaderEventListener();
private BeanDefinitionRegistry registry = new DefaultListableBeanFactory();
@Before
public void setUp() throws Exception {
SourceExtractor sourceExtractor = new PassThroughSourceExtractor();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.registry);
XmlReaderContext readerContext =
new XmlReaderContext(null, null, this.readerEventListener, sourceExtractor, reader, null);
this.parserContext = new ParserContext(readerContext, null);
}
@Test
public void testRegisterAutoProxyCreator() throws Exception {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount());
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount());
}
@Test
public void testRegisterAspectJAutoProxyCreator() throws Exception {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount());
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals("Incorrect number of definitions registered", 1, registry.getBeanDefinitionCount());
BeanDefinition definition = registry.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
assertEquals("Incorrect APC class",
AspectJAwareAdvisorAutoProxyCreator.class.getName(), definition.getBeanClassName());
}
@Test
public void testRegisterAspectJAutoProxyCreatorWithExistingAutoProxyCreator() throws Exception {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals(1, registry.getBeanDefinitionCount());
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals("Incorrect definition count", 1, registry.getBeanDefinitionCount());
BeanDefinition definition = registry.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
assertEquals("APC class not switched",
AspectJAwareAdvisorAutoProxyCreator.class.getName(), definition.getBeanClassName());
}
@Test
public void testRegisterAutoProxyCreatorWhenAspectJAutoProxyCreatorAlreadyExists() throws Exception {
AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals(1, registry.getBeanDefinitionCount());
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(this.parserContext, null);
assertEquals("Incorrect definition count", 1, registry.getBeanDefinitionCount());
BeanDefinition definition = registry.getBeanDefinition(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME);
assertEquals("Incorrect APC class",
AspectJAwareAdvisorAutoProxyCreator.class.getName(), definition.getBeanClassName());
}
}

View File

@@ -0,0 +1,236 @@
/*
* 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 org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.Advisor;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.aspectj.AbstractAspectJAdvice;
import org.springframework.aop.aspectj.AspectJAfterAdvice;
import org.springframework.aop.aspectj.AspectJAfterReturningAdvice;
import org.springframework.aop.aspectj.AspectJAfterThrowingAdvice;
import org.springframework.aop.aspectj.AspectJAroundAdvice;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
import org.springframework.aop.aspectj.AspectJPointcutAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
/**
* @author Adrian Colyer
* @author Chris Beams
*/
public final class AspectJPrecedenceComparatorTests {
/*
* Specification for the comparator (as defined in the
* AspectJPrecedenceComparator class)
*
* <p>
* Orders AspectJ advice/advisors by invocation order.
* </p>
* <p>
* Given two pieces of advice, <code>a</code> and <code>b</code>:
* </p>
* <ul>
* <li>if <code>a</code> and <code>b</code> are defined in different
* aspects, then the advice in the aspect with the lowest order
* value has the highest precedence</li>
* <li>if <code>a</code> and <code>b</code> are defined in the same
* aspect, then if one of <code>a</code> or <code>b</code> is a form of
* after advice, then the advice declared last in the aspect has the
* highest precedence. If neither <code>a</code> nor <code>b</code> is a
* form of after advice, then the advice declared first in the aspect has
* the highest precedence.</li>
* </ul>
*/
private static final int HIGH_PRECEDENCE_ADVISOR_ORDER = 100;
private static final int LOW_PRECEDENCE_ADVISOR_ORDER = 200;
private static final int EARLY_ADVICE_DECLARATION_ORDER = 5;
private static final int LATE_ADVICE_DECLARATION_ORDER = 10;
private AspectJPrecedenceComparator comparator;
private Method anyOldMethod;
private AspectJExpressionPointcut anyOldPointcut;
@Before
public void setUp() throws Exception {
this.comparator = new AspectJPrecedenceComparator();
this.anyOldMethod = getClass().getMethods()[0];
this.anyOldPointcut = new AspectJExpressionPointcut();
this.anyOldPointcut.setExpression("execution(* *(..))");
}
@Test
public void testSameAspectNoAfterAdvice() {
Advisor advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
assertEquals("advisor2 sorted before advisor1", 1, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testSameAspectAfterAdvice() {
Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
assertEquals("advisor2 sorted before advisor1", 1, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJAfterReturningAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAfterThrowingAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testSameAspectOneOfEach() {
Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
assertEquals("advisor1 and advisor2 not comparable", 0, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testSameAdvisorPrecedenceDifferentAspectNoAfterAdvice() {
Advisor advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testSameAdvisorPrecedenceDifferentAspectAfterAdvice() {
Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJAfterReturningAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAfterThrowingAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("nothing to say about order here", 0, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testHigherAdvisorPrecedenceNoAfterAdvice() {
Advisor advisor1 = createSpringAOPBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER);
Advisor advisor2 = createAspectJBeforeAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAroundAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testHigherAdvisorPrecedenceAfterAdvice() {
Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJAroundAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted before advisor2", -1, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJAfterReturningAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAfterThrowingAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor2 sorted after advisor1", -1, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testLowerAdvisorPrecedenceNoAfterAdvice() {
Advisor advisor1 = createAspectJBeforeAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2));
advisor1 = createAspectJBeforeAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2));
}
@Test
public void testLowerAdvisorPrecedenceAfterAdvice() {
Advisor advisor1 = createAspectJAfterAdvice(LOW_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
Advisor advisor2 = createAspectJAroundAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2));
advisor1 = createSpringAOPAfterAdvice(LOW_PRECEDENCE_ADVISOR_ORDER);
advisor2 = createAspectJAfterThrowingAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someOtherAspect");
assertEquals("advisor1 sorted after advisor2", 1, this.comparator.compare(advisor1, advisor2));
}
private Advisor createAspectJBeforeAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) {
AspectJMethodBeforeAdvice advice = new AspectJMethodBeforeAdvice(this.anyOldMethod, this.anyOldPointcut, null);
return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice);
}
private Advisor createAspectJAroundAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) {
AspectJAroundAdvice advice = new AspectJAroundAdvice(this.anyOldMethod, this.anyOldPointcut, null);
return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice);
}
private Advisor createAspectJAfterAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) {
AspectJAfterAdvice advice = new AspectJAfterAdvice(this.anyOldMethod, this.anyOldPointcut, null);
return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice);
}
private Advisor createAspectJAfterReturningAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) {
AspectJAfterReturningAdvice advice = new AspectJAfterReturningAdvice(this.anyOldMethod, this.anyOldPointcut, null);
return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice);
}
private Advisor createAspectJAfterThrowingAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName) {
AspectJAfterThrowingAdvice advice = new AspectJAfterThrowingAdvice(this.anyOldMethod, this.anyOldPointcut, null);
return createAspectJAdvice(advisorOrder, adviceDeclarationOrder, aspectName, advice);
}
private Advisor createAspectJAdvice(int advisorOrder, int adviceDeclarationOrder, String aspectName, AbstractAspectJAdvice advice) {
advice.setDeclarationOrder(adviceDeclarationOrder);
advice.setAspectName(aspectName);
AspectJPointcutAdvisor advisor = new AspectJPointcutAdvisor(advice);
advisor.setOrder(advisorOrder);
return advisor;
}
private Advisor createSpringAOPAfterAdvice(int order) {
AfterReturningAdvice advice = new AfterReturningAdvice() {
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
}
};
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(this.anyOldPointcut, advice);
advisor.setOrder(order);
return advisor;
}
private Advisor createSpringAOPBeforeAdvice(int order) {
BeforeAdvice advice = new BeforeAdvice() {
};
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(this.anyOldPointcut, advice);
advisor.setOrder(order);
return advisor;
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:aspect id="countAgeCalls" ref="countingAdvice">
<aop:pointcut id="pc" expression="execution(* getAge())"/>
<aop:before pointcut-ref="pc" method="myBeforeAdvice" />
<aop:after pointcut-ref="pc" method="myAfterAdvice" />
<aop:after-returning pointcut-ref="pc" method="myAfterReturningAdvice" returning="age"/>
<aop:after-throwing pointcut-ref="pc" method="myAfterThrowingAdvice" throwing="ex"/>
<aop:around pointcut-ref="pc" method="myAroundAdvice"/>
</aop:aspect>
</aop:config>
<bean id="getNameCounter" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
<bean id="getAgeCounter" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
<bean id="testBean" class="test.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:config>
<aop:advisor advice-ref="countingAdvice" pointcut="within(org.springframework..*)"/>
</aop:config>
<bean id="countingAdvice" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
</beans>

View File

@@ -0,0 +1,12 @@
<?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="myPointcut" expression="within(org.springframework..*)"/>
</aop:config>
</beans>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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="pc" expression="within(org.springframework..*)"/>
<aop:advisor advice-ref="countingAdvice" pointcut-ref="pc"/>
</aop:config>
<bean id="countingAdvice" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
</beans>

View File

@@ -0,0 +1,195 @@
/*
* 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.config;
import static org.junit.Assert.*;
import static test.util.TestResourceUtils.qualifiedResource;
import java.util.HashSet;
import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.ComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import test.parsing.CollectingReaderEventListener;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class AopNamespaceHandlerEventTests {
private static final Class<?> CLASS = AopNamespaceHandlerEventTests.class;
private static final Resource CONTEXT = qualifiedResource(CLASS, "context.xml");
private static final Resource POINTCUT_EVENTS_CONTEXT = qualifiedResource(CLASS, "pointcutEvents.xml");
private static final Resource POINTCUT_REF_CONTEXT = qualifiedResource(CLASS, "pointcutRefEvents.xml");
private static final Resource DIRECT_POINTCUT_EVENTS_CONTEXT = qualifiedResource(CLASS, "directPointcutEvents.xml");
private CollectingReaderEventListener eventListener = new CollectingReaderEventListener();
private XmlBeanDefinitionReader reader;
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@Before
public void setUp() throws Exception {
this.reader = new XmlBeanDefinitionReader(this.beanFactory);
this.reader.setEventListener(this.eventListener);
}
@Test
public void testPointcutEvents() throws Exception {
this.reader.loadBeanDefinitions(POINTCUT_EVENTS_CONTEXT);
ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions();
assertEquals("Incorrect number of events fired", 1, componentDefinitions.length);
assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition);
CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0];
assertEquals("aop:config", compositeDef.getName());
ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents();
assertEquals("Incorrect number of inner components", 2, nestedComponentDefs.length);
PointcutComponentDefinition pcd = null;
for (int i = 0; i < nestedComponentDefs.length; i++) {
ComponentDefinition componentDefinition = nestedComponentDefs[i];
if (componentDefinition instanceof PointcutComponentDefinition) {
pcd = (PointcutComponentDefinition) componentDefinition;
break;
}
}
assertNotNull("PointcutComponentDefinition not found", pcd);
assertEquals("Incorrect number of BeanDefinitions", 1, pcd.getBeanDefinitions().length);
}
@Test
public void testAdvisorEventsWithPointcutRef() throws Exception {
this.reader.loadBeanDefinitions(POINTCUT_REF_CONTEXT);
ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions();
assertEquals("Incorrect number of events fired", 2, componentDefinitions.length);
assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition);
CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0];
assertEquals("aop:config", compositeDef.getName());
ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents();
assertEquals("Incorrect number of inner components", 3, nestedComponentDefs.length);
AdvisorComponentDefinition acd = null;
for (int i = 0; i < nestedComponentDefs.length; i++) {
ComponentDefinition componentDefinition = nestedComponentDefs[i];
if (componentDefinition instanceof AdvisorComponentDefinition) {
acd = (AdvisorComponentDefinition) componentDefinition;
break;
}
}
assertNotNull("AdvisorComponentDefinition not found", acd);
assertEquals(1, acd.getBeanDefinitions().length);
assertEquals(2, acd.getBeanReferences().length);
assertTrue("No advice bean found", componentDefinitions[1] instanceof BeanComponentDefinition);
BeanComponentDefinition adviceDef = (BeanComponentDefinition) componentDefinitions[1];
assertEquals("countingAdvice", adviceDef.getBeanName());
}
@Test
public void testAdvisorEventsWithDirectPointcut() throws Exception {
this.reader.loadBeanDefinitions(DIRECT_POINTCUT_EVENTS_CONTEXT);
ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions();
assertEquals("Incorrect number of events fired", 2, componentDefinitions.length);
assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition);
CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0];
assertEquals("aop:config", compositeDef.getName());
ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents();
assertEquals("Incorrect number of inner components", 2, nestedComponentDefs.length);
AdvisorComponentDefinition acd = null;
for (int i = 0; i < nestedComponentDefs.length; i++) {
ComponentDefinition componentDefinition = nestedComponentDefs[i];
if (componentDefinition instanceof AdvisorComponentDefinition) {
acd = (AdvisorComponentDefinition) componentDefinition;
break;
}
}
assertNotNull("AdvisorComponentDefinition not found", acd);
assertEquals(2, acd.getBeanDefinitions().length);
assertEquals(1, acd.getBeanReferences().length);
assertTrue("No advice bean found", componentDefinitions[1] instanceof BeanComponentDefinition);
BeanComponentDefinition adviceDef = (BeanComponentDefinition) componentDefinitions[1];
assertEquals("countingAdvice", adviceDef.getBeanName());
}
@Test
public void testAspectEvent() throws Exception {
this.reader.loadBeanDefinitions(CONTEXT);
ComponentDefinition[] componentDefinitions = this.eventListener.getComponentDefinitions();
assertEquals("Incorrect number of events fired", 5, componentDefinitions.length);
assertTrue("No holder with nested components", componentDefinitions[0] instanceof CompositeComponentDefinition);
CompositeComponentDefinition compositeDef = (CompositeComponentDefinition) componentDefinitions[0];
assertEquals("aop:config", compositeDef.getName());
ComponentDefinition[] nestedComponentDefs = compositeDef.getNestedComponents();
assertEquals("Incorrect number of inner components", 2, nestedComponentDefs.length);
AspectComponentDefinition acd = null;
for (int i = 0; i < nestedComponentDefs.length; i++) {
ComponentDefinition componentDefinition = nestedComponentDefs[i];
if (componentDefinition instanceof AspectComponentDefinition) {
acd = (AspectComponentDefinition) componentDefinition;
break;
}
}
assertNotNull("AspectComponentDefinition not found", acd);
BeanDefinition[] beanDefinitions = acd.getBeanDefinitions();
assertEquals(5, beanDefinitions.length);
BeanReference[] beanReferences = acd.getBeanReferences();
assertEquals(6, beanReferences.length);
Set<String> expectedReferences = new HashSet<String>();
expectedReferences.add("pc");
expectedReferences.add("countingAdvice");
for (int i = 0; i < beanReferences.length; i++) {
BeanReference beanReference = beanReferences[i];
expectedReferences.remove(beanReference.getBeanName());
}
assertEquals("Incorrect references found", 0, expectedReferences.size());
for (int i = 1; i < componentDefinitions.length; i++) {
assertTrue(componentDefinitions[i] instanceof BeanComponentDefinition);
}
ComponentDefinition[] nestedComponentDefs2 = acd.getNestedComponents();
assertEquals("Inner PointcutComponentDefinition not found", 1, nestedComponentDefs2.length);
assertTrue(nestedComponentDefs2[0] instanceof PointcutComponentDefinition);
PointcutComponentDefinition pcd = (PointcutComponentDefinition) nestedComponentDefs2[0];
assertEquals("Incorrect number of BeanDefinitions", 1, pcd.getBeanDefinitions().length);
}
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.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" pointcut="execution(* getAge())" method="myBeforeAdvice"/>
</aop:aspect>
</aop:config>
<bean id="getAgeCounter" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
<bean id="testBean" class="test.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.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 method="myBeforeAdvice" />
</aop:aspect>
</aop:config>
<bean id="getAgeCounter" class="org.springframework.aop.framework.CountingBeforeAdvice"/>
<bean id="testBean" class="test.beans.TestBean"/>
<bean id="countingAdvice" class="org.springframework.aop.config.CountingAspectJAdvice"/>
</beans>

View File

@@ -0,0 +1,55 @@
/*
* 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.config;
import static org.junit.Assert.*;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Test;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.beans.factory.xml.XmlBeanFactory;
/**
* @author Mark Fisher
* @author Chris Beams
*/
public final class AopNamespaceHandlerPointcutErrorTests {
@Test
public void testDuplicatePointcutConfig() {
try {
new XmlBeanFactory(qualifiedResource(getClass(), "pointcutDuplication.xml"));
fail("parsing should have caused a BeanDefinitionStoreException");
}
catch (BeanDefinitionStoreException ex) {
assertTrue(ex.contains(BeanDefinitionParsingException.class));
}
}
@Test
public void testMissingPointcutConfig() {
try {
new XmlBeanFactory(qualifiedResource(getClass(), "pointcutMissing.xml"));
fail("parsing should have caused a BeanDefinitionStoreException");
}
catch (BeanDefinitionStoreException ex) {
assertTrue(ex.contains(BeanDefinitionParsingException.class));
}
}
}

View File

@@ -0,0 +1,12 @@
<config xmlns="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<pointcut id="testPointcut" expression="execution(* foo(..)) and within(springbank.dao.AccountDao+)"/>
<pointcut id="testPointcut1" expression="execution(* springbank.dao.AccountDao.foo(..))"/>
<aspect ref="myAspect">
<after method="foo" pointcut-ref="testPointcut"/>
</aspect>
</config>

View File

@@ -0,0 +1,46 @@
/*
* 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.config;
import static org.junit.Assert.assertTrue;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Test;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
/**
* Tests that the &lt;aop:config/&gt; element can be used as a top level element.
*
* @author Rob Harrop
* @author Chris Beams
*/
public final class TopLevelAopTagTests {
private static final Resource CONTEXT = qualifiedResource(TopLevelAopTagTests.class, "context.xml");
@Test
public void testParse() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(CONTEXT);
assertTrue(beanFactory.containsBeanDefinition("testPointcut"));
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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.framework;
import static org.junit.Assert.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.springframework.aop.SpringProxy;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class AopProxyUtilsTests {
@Test
public void testCompleteProxiedInterfacesWorksWithNull() {
AdvisedSupport as = new AdvisedSupport();
Class<?>[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as);
assertEquals(2, completedInterfaces.length);
List<?> ifaces = Arrays.asList(completedInterfaces);
assertTrue(ifaces.contains(Advised.class));
assertTrue(ifaces.contains(SpringProxy.class));
}
@Test
public void testCompleteProxiedInterfacesWorksWithNullOpaque() {
AdvisedSupport as = new AdvisedSupport();
as.setOpaque(true);
Class<?>[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as);
assertEquals(1, completedInterfaces.length);
}
@Test
public void testCompleteProxiedInterfacesAdvisedNotIncluded() {
AdvisedSupport as = new AdvisedSupport();
as.addInterface(ITestBean.class);
as.addInterface(Comparable.class);
Class<?>[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as);
assertEquals(4, completedInterfaces.length);
// Can't assume ordering for others, so use a list
List<?> l = Arrays.asList(completedInterfaces);
assertTrue(l.contains(Advised.class));
assertTrue(l.contains(ITestBean.class));
assertTrue(l.contains(Comparable.class));
}
@Test
public void testCompleteProxiedInterfacesAdvisedIncluded() {
AdvisedSupport as = new AdvisedSupport();
as.addInterface(ITestBean.class);
as.addInterface(Comparable.class);
as.addInterface(Advised.class);
Class<?>[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as);
assertEquals(4, completedInterfaces.length);
// Can't assume ordering for others, so use a list
List<?> l = Arrays.asList(completedInterfaces);
assertTrue(l.contains(Advised.class));
assertTrue(l.contains(ITestBean.class));
assertTrue(l.contains(Comparable.class));
}
@Test
public void testCompleteProxiedInterfacesAdvisedNotIncludedOpaque() {
AdvisedSupport as = new AdvisedSupport();
as.setOpaque(true);
as.addInterface(ITestBean.class);
as.addInterface(Comparable.class);
Class<?>[] completedInterfaces = AopProxyUtils.completeProxiedInterfaces(as);
assertEquals(3, completedInterfaces.length);
// Can't assume ordering for others, so use a list
List<?> l = Arrays.asList(completedInterfaces);
assertFalse(l.contains(Advised.class));
assertTrue(l.contains(ITestBean.class));
assertTrue(l.contains(Comparable.class));
}
@Test
public void testProxiedUserInterfacesWithSingleInterface() {
ProxyFactory pf = new ProxyFactory();
pf.setTarget(new TestBean());
pf.addInterface(ITestBean.class);
Object proxy = pf.getProxy();
Class<?>[] userInterfaces = AopProxyUtils.proxiedUserInterfaces(proxy);
assertEquals(1, userInterfaces.length);
assertEquals(ITestBean.class, userInterfaces[0]);
}
@Test
public void testProxiedUserInterfacesWithMultipleInterfaces() {
ProxyFactory pf = new ProxyFactory();
pf.setTarget(new TestBean());
pf.addInterface(ITestBean.class);
pf.addInterface(Comparable.class);
Object proxy = pf.getProxy();
Class<?>[] userInterfaces = AopProxyUtils.proxiedUserInterfaces(proxy);
assertEquals(2, userInterfaces.length);
assertEquals(ITestBean.class, userInterfaces[0]);
assertEquals(Comparable.class, userInterfaces[1]);
}
@Test(expected=IllegalArgumentException.class)
public void testProxiedUserInterfacesWithNoInterface() {
Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[0],
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});
AopProxyUtils.proxiedUserInterfaces(proxy);
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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.framework;
import org.junit.Test;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.util.StopWatch;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* Benchmarks for introductions.
*
* NOTE: No assertions!
*
* @author Rod Johnson
* @author Chris Beams
* @since 2.0
*/
public final class IntroductionBenchmarkTests {
private static final int EXPECTED_COMPARE = 13;
/** Increase this if you want meaningful results! */
private static final int INVOCATIONS = 100000;
@SuppressWarnings("serial")
public static class SimpleCounterIntroduction extends DelegatingIntroductionInterceptor implements Counter {
public int getCount() {
return EXPECTED_COMPARE;
}
}
public static interface Counter {
int getCount();
}
@Test
public void timeManyInvocations() {
StopWatch sw = new StopWatch();
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
pf.setProxyTargetClass(false);
pf.addAdvice(new SimpleCounterIntroduction());
ITestBean proxy = (ITestBean) pf.getProxy();
Counter counter = (Counter) proxy;
sw.start(INVOCATIONS + " invocations on proxy, not hitting introduction");
for (int i = 0; i < INVOCATIONS; i++) {
proxy.getAge();
}
sw.stop();
sw.start(INVOCATIONS + " invocations on proxy, hitting introduction");
for (int i = 0; i < INVOCATIONS; i++) {
counter.getCount();
}
sw.stop();
sw.start(INVOCATIONS + " invocations on target");
for (int i = 0; i < INVOCATIONS; i++) {
target.getAge();
}
sw.stop();
System.out.println(sw.prettyPrint());
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.framework;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
* @since 14.03.2003
*/
public final class MethodInvocationTests {
@Test
public void testValidInvocation() throws Throwable {
Method m = Object.class.getMethod("hashCode", (Class[]) null);
Object proxy = new Object();
final Object returnValue = new Object();
List<Object> is = new LinkedList<Object>();
is.add(new MethodInterceptor() {
public Object invoke(MethodInvocation invocation) throws Throwable {
return returnValue;
}
});
ReflectiveMethodInvocation invocation = new ReflectiveMethodInvocation(proxy, null, //?
m, null, null, is // list
);
Object rv = invocation.proceed();
assertTrue("correct response", rv == returnValue);
}
/**
* toString on target can cause failure.
*/
@Test
public void testToStringDoesntHitTarget() throws Throwable {
Object target = new TestBean() {
public String toString() {
throw new UnsupportedOperationException("toString");
}
};
List<Object> is = new LinkedList<Object>();
Method m = Object.class.getMethod("hashCode", (Class[]) null);
Object proxy = new Object();
ReflectiveMethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, m, null, null, is);
// If it hits target, the test will fail with the UnsupportedOpException
// in the inner class above.
invocation.toString();
}
}

View File

@@ -0,0 +1,42 @@
<?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.aop.framework.PrototypeTargetTests$TestBeanImpl"
scope="prototype"/>
<bean id="testInterceptor" class="org.springframework.aop.framework.PrototypeTargetTests$TestInterceptor"
scope="singleton"/>
<bean id="testBeanPrototype" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.springframework.aop.framework.PrototypeTargetTests$TestBean</value>
</property>
<property name="singleton">
<value>false</value>
</property>
<property name="interceptorNames">
<list>
<value>testInterceptor</value>
<value>testBeanTarget</value>
</list>
</property>
</bean>
<bean id="testBeanSingleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.springframework.aop.framework.PrototypeTargetTests$TestBean</value>
</property>
<property name="singleton">
<value>true</value>
</property>
<property name="interceptorNames">
<list>
<value>testInterceptor</value>
<value>testBeanTarget</value>
</list>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,90 @@
/*
* 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.framework;
import static org.junit.Assert.assertEquals;
import static test.util.TestResourceUtils.qualifiedResource;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
/**
* @author Juergen Hoeller
* @author Chris Beams
* @since 03.09.2004
*/
public final class PrototypeTargetTests {
private static final Resource CONTEXT = qualifiedResource(PrototypeTargetTests.class, "context.xml");
@Test
public void testPrototypeProxyWithPrototypeTarget() {
TestBeanImpl.constructionCount = 0;
XmlBeanFactory xbf = new XmlBeanFactory(CONTEXT);
for (int i = 0; i < 10; i++) {
TestBean tb = (TestBean) xbf.getBean("testBeanPrototype");
tb.doSomething();
}
TestInterceptor interceptor = (TestInterceptor) xbf.getBean("testInterceptor");
assertEquals(10, TestBeanImpl.constructionCount);
assertEquals(10, interceptor.invocationCount);
}
@Test
public void testSingletonProxyWithPrototypeTarget() {
TestBeanImpl.constructionCount = 0;
XmlBeanFactory xbf = new XmlBeanFactory(CONTEXT);
for (int i = 0; i < 10; i++) {
TestBean tb = (TestBean) xbf.getBean("testBeanSingleton");
tb.doSomething();
}
TestInterceptor interceptor = (TestInterceptor) xbf.getBean("testInterceptor");
assertEquals(1, TestBeanImpl.constructionCount);
assertEquals(10, interceptor.invocationCount);
}
public static interface TestBean {
public void doSomething();
}
public static class TestBeanImpl implements TestBean {
private static int constructionCount = 0;
public TestBeanImpl() {
constructionCount++;
}
public void doSomething() {
}
}
public static class TestInterceptor implements MethodInterceptor {
private int invocationCount = 0;
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
invocationCount++;
return methodInvocation.proceed();
}
}
}

View File

@@ -0,0 +1,358 @@
/*
* Copyright 2002-2010 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 javax.accessibility.Accessible;
import javax.swing.*;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.Ignore;
import org.junit.Test;
import test.aop.CountingBeforeAdvice;
import test.aop.NopInterceptor;
import test.beans.IOther;
import test.beans.ITestBean;
import test.beans.TestBean;
import test.util.TimeStamped;
import org.springframework.aop.Advisor;
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.DelegatingIntroductionInterceptor;
/**
* Also tests AdvisedSupport and ProxyCreatorSupport superclasses.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 14.05.2003
*/
public final class ProxyFactoryTests {
@Test
public void testIndexOfMethods() {
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
NopInterceptor nop = new NopInterceptor();
Advisor advisor = new DefaultPointcutAdvisor(new CountingBeforeAdvice());
Advised advised = (Advised) pf.getProxy();
// Can use advised and ProxyFactory interchangeably
advised.addAdvice(nop);
pf.addAdvisor(advisor);
assertEquals(-1, pf.indexOf(new NopInterceptor()));
assertEquals(0, pf.indexOf(nop));
assertEquals(1, pf.indexOf(advisor));
assertEquals(-1, advised.indexOf(new DefaultPointcutAdvisor(null)));
}
@Test
public void testRemoveAdvisorByReference() {
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
NopInterceptor nop = new NopInterceptor();
CountingBeforeAdvice cba = new CountingBeforeAdvice();
Advisor advisor = new DefaultPointcutAdvisor(cba);
pf.addAdvice(nop);
pf.addAdvisor(advisor);
ITestBean proxied = (ITestBean) pf.getProxy();
proxied.setAge(5);
assertEquals(1, cba.getCalls());
assertEquals(1, nop.getCount());
assertTrue(pf.removeAdvisor(advisor));
assertEquals(5, proxied.getAge());
assertEquals(1, cba.getCalls());
assertEquals(2, nop.getCount());
assertFalse(pf.removeAdvisor(new DefaultPointcutAdvisor(null)));
}
@Test
public void testRemoveAdvisorByIndex() {
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
NopInterceptor nop = new NopInterceptor();
CountingBeforeAdvice cba = new CountingBeforeAdvice();
Advisor advisor = new DefaultPointcutAdvisor(cba);
pf.addAdvice(nop);
pf.addAdvisor(advisor);
NopInterceptor nop2 = new NopInterceptor();
pf.addAdvice(nop2);
ITestBean proxied = (ITestBean) pf.getProxy();
proxied.setAge(5);
assertEquals(1, cba.getCalls());
assertEquals(1, nop.getCount());
assertEquals(1, nop2.getCount());
// Removes counting before advisor
pf.removeAdvisor(1);
assertEquals(5, proxied.getAge());
assertEquals(1, cba.getCalls());
assertEquals(2, nop.getCount());
assertEquals(2, nop2.getCount());
// Removes Nop1
pf.removeAdvisor(0);
assertEquals(5, proxied.getAge());
assertEquals(1, cba.getCalls());
assertEquals(2, nop.getCount());
assertEquals(3, nop2.getCount());
// Check out of bounds
try {
pf.removeAdvisor(-1);
}
catch (AopConfigException ex) {
// Ok
}
try {
pf.removeAdvisor(2);
}
catch (AopConfigException ex) {
// Ok
}
assertEquals(5, proxied.getAge());
assertEquals(4, nop2.getCount());
}
@Test
public void testReplaceAdvisor() {
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
NopInterceptor nop = new NopInterceptor();
CountingBeforeAdvice cba1 = new CountingBeforeAdvice();
CountingBeforeAdvice cba2 = new CountingBeforeAdvice();
Advisor advisor1 = new DefaultPointcutAdvisor(cba1);
Advisor advisor2 = new DefaultPointcutAdvisor(cba2);
pf.addAdvisor(advisor1);
pf.addAdvice(nop);
ITestBean proxied = (ITestBean) pf.getProxy();
// Use the type cast feature
// Replace etc methods on advised should be same as on ProxyFactory
Advised advised = (Advised) proxied;
proxied.setAge(5);
assertEquals(1, cba1.getCalls());
assertEquals(0, cba2.getCalls());
assertEquals(1, nop.getCount());
assertFalse(advised.replaceAdvisor(new DefaultPointcutAdvisor(new NopInterceptor()), advisor2));
assertTrue(advised.replaceAdvisor(advisor1, advisor2));
assertEquals(advisor2, pf.getAdvisors()[0]);
assertEquals(5, proxied.getAge());
assertEquals(1, cba1.getCalls());
assertEquals(2, nop.getCount());
assertEquals(1, cba2.getCalls());
assertFalse(pf.replaceAdvisor(new DefaultPointcutAdvisor(null), advisor1));
}
@Test
public void testAddRepeatedInterface() {
TimeStamped tst = new TimeStamped() {
public long getTimeStamp() {
throw new UnsupportedOperationException("getTimeStamp");
}
};
ProxyFactory pf = new ProxyFactory(tst);
// We've already implicitly added this interface.
// This call should be ignored without error
pf.addInterface(TimeStamped.class);
// All cool
assertThat(pf.getProxy(), instanceOf(TimeStamped.class));
}
@Test
public void testGetsAllInterfaces() throws Exception {
// Extend to get new interface
class TestBeanSubclass extends TestBean implements Comparable<Object> {
public int compareTo(Object arg0) {
throw new UnsupportedOperationException("compareTo");
}
}
TestBeanSubclass raw = new TestBeanSubclass();
ProxyFactory factory = new ProxyFactory(raw);
//System.out.println("Proxied interfaces are " + StringUtils.arrayToDelimitedString(factory.getProxiedInterfaces(), ","));
assertEquals("Found correct number of interfaces", 3, factory.getProxiedInterfaces().length);
ITestBean tb = (ITestBean) factory.getProxy();
assertThat("Picked up secondary interface", tb, instanceOf(IOther.class));
raw.setAge(25);
assertTrue(tb.getAge() == raw.getAge());
long t = 555555L;
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t);
Class<?>[] oldProxiedInterfaces = factory.getProxiedInterfaces();
factory.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
Class<?>[] newProxiedInterfaces = factory.getProxiedInterfaces();
assertEquals("Advisor proxies one more interface after introduction", oldProxiedInterfaces.length + 1, newProxiedInterfaces.length);
TimeStamped ts = (TimeStamped) factory.getProxy();
assertTrue(ts.getTimeStamp() == t);
// Shouldn't fail;
((IOther) ts).absquatulate();
}
@Test
public void testInterceptorInclusionMethods() {
class MyInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
throw new UnsupportedOperationException();
}
}
NopInterceptor di = new NopInterceptor();
NopInterceptor diUnused = new NopInterceptor();
ProxyFactory factory = new ProxyFactory(new TestBean());
factory.addAdvice(0, di);
assertThat(factory.getProxy(), instanceOf(ITestBean.class));
assertTrue(factory.adviceIncluded(di));
assertTrue(!factory.adviceIncluded(diUnused));
assertTrue(factory.countAdvicesOfType(NopInterceptor.class) == 1);
assertTrue(factory.countAdvicesOfType(MyInterceptor.class) == 0);
factory.addAdvice(0, diUnused);
assertTrue(factory.adviceIncluded(diUnused));
assertTrue(factory.countAdvicesOfType(NopInterceptor.class) == 2);
}
/**
* Should see effect immediately on behavior.
*/
@Test
public void testCanAddAndRemoveAspectInterfacesOnSingleton() {
ProxyFactory config = new ProxyFactory(new TestBean());
assertFalse("Shouldn't implement TimeStamped before manipulation",
config.getProxy() instanceof TimeStamped);
long time = 666L;
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor();
ti.setTime(time);
// Add to front 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) config.getProxy();
assertTrue(ts.getTimeStamp() == time);
// Can remove
config.removeAdvice(ti);
assertTrue(config.getAdvisors().length == oldCount);
try {
// Existing reference will fail
ts.getTimeStamp();
fail("Existing object won't implement this interface any more");
}
catch (RuntimeException ex) {
}
assertFalse("Should no longer implement TimeStamped",
config.getProxy() instanceof TimeStamped);
// 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();
assertEquals(1, debugInterceptor.getCount());
config.removeAdvice(debugInterceptor);
it.getSpouse();
// not invoked again
assertTrue(debugInterceptor.getCount() == 1);
}
@Test
public void testProxyTargetClassWithInterfaceAsTarget() {
ProxyFactory pf = new ProxyFactory();
pf.setTargetClass(ITestBean.class);
Object proxy = pf.getProxy();
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy));
assertTrue(proxy instanceof ITestBean);
assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
ProxyFactory pf2 = new ProxyFactory(proxy);
Object proxy2 = pf2.getProxy();
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy2));
assertTrue(proxy2 instanceof ITestBean);
assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
}
@Test
public void testProxyTargetClassWithConcreteClassAsTarget() {
ProxyFactory pf = new ProxyFactory();
pf.setTargetClass(TestBean.class);
Object proxy = pf.getProxy();
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy));
assertTrue(proxy instanceof TestBean);
assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
ProxyFactory pf2 = new ProxyFactory(proxy);
pf2.setProxyTargetClass(true);
Object proxy2 = pf2.getProxy();
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy2));
assertTrue(proxy2 instanceof TestBean);
assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
}
@Test
@Ignore("Not implemented yet, see http://jira.springframework.org/browse/SPR-5708")
public void testExclusionOfNonPublicInterfaces() {
JFrame frame = new JFrame();
ProxyFactory proxyFactory = new ProxyFactory(frame);
Object proxy = proxyFactory.getProxy();
assertTrue(proxy instanceof RootPaneContainer);
assertTrue(proxy instanceof Accessible);
}
@SuppressWarnings("serial")
private static class TimestampIntroductionInterceptor extends DelegatingIntroductionInterceptor
implements TimeStamped {
private long ts;
public TimestampIntroductionInterceptor() {
}
public TimestampIntroductionInterceptor(long ts) {
this.ts = ts;
}
public void setTime(long ts) {
this.ts = ts;
}
public long getTimeStamp() {
return ts;
}
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2002-2009 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 java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import javax.transaction.TransactionRolledbackException;
import org.aopalliance.intercept.MethodInvocation;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import org.junit.Test;
import test.aop.MethodCounter;
import org.springframework.aop.ThrowsAdvice;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class ThrowsAdviceInterceptorTests {
@Test(expected=IllegalArgumentException.class)
public void testNoHandlerMethods() {
// should require one handler method at least
new ThrowsAdviceInterceptor(new Object());
}
@Test
public void testNotInvoked() throws Throwable {
MyThrowsHandler th = new MyThrowsHandler();
ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th);
Object ret = new Object();
MethodInvocation mi = createMock(MethodInvocation.class);
expect(mi.proceed()).andReturn(ret);
replay(mi);
assertEquals(ret, ti.invoke(mi));
assertEquals(0, th.getCalls());
verify(mi);
}
@Test
public void testNoHandlerMethodForThrowable() throws Throwable {
MyThrowsHandler th = new MyThrowsHandler();
ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th);
assertEquals(2, ti.getHandlerMethodCount());
Exception ex = new Exception();
MethodInvocation mi = createMock(MethodInvocation.class);
expect(mi.proceed()).andThrow(ex);
replay(mi);
try {
ti.invoke(mi);
fail();
}
catch (Exception caught) {
assertEquals(ex, caught);
}
assertEquals(0, th.getCalls());
verify(mi);
}
@Test
public void testCorrectHandlerUsed() throws Throwable {
MyThrowsHandler th = new MyThrowsHandler();
ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th);
FileNotFoundException ex = new FileNotFoundException();
MethodInvocation mi = createMock(MethodInvocation.class);
expect(mi.getMethod()).andReturn(Object.class.getMethod("hashCode", (Class[]) null));
expect(mi.getArguments()).andReturn(null);
expect(mi.getThis()).andReturn(new Object());
expect(mi.proceed()).andThrow(ex);
replay(mi);
try {
ti.invoke(mi);
fail();
}
catch (Exception caught) {
assertEquals(ex, caught);
}
assertEquals(1, th.getCalls());
assertEquals(1, th.getCalls("ioException"));
verify(mi);
}
@Test
public void testCorrectHandlerUsedForSubclass() throws Throwable {
MyThrowsHandler th = new MyThrowsHandler();
ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th);
// Extends RemoteException
TransactionRolledbackException ex = new TransactionRolledbackException();
MethodInvocation mi = createMock(MethodInvocation.class);
expect(mi.proceed()).andThrow(ex);
replay(mi);
try {
ti.invoke(mi);
fail();
}
catch (Exception caught) {
assertEquals(ex, caught);
}
assertEquals(1, th.getCalls());
assertEquals(1, th.getCalls("remoteException"));
verify(mi);
}
@Test
public void testHandlerMethodThrowsException() throws Throwable {
final Throwable t = new Throwable();
@SuppressWarnings("serial")
MyThrowsHandler th = new MyThrowsHandler() {
public void afterThrowing(RemoteException ex) throws Throwable {
super.afterThrowing(ex);
throw t;
}
};
ThrowsAdviceInterceptor ti = new ThrowsAdviceInterceptor(th);
// Extends RemoteException
TransactionRolledbackException ex = new TransactionRolledbackException();
MethodInvocation mi = createMock(MethodInvocation.class);
expect(mi.proceed()).andThrow(ex);
replay(mi);
try {
ti.invoke(mi);
fail();
}
catch (Throwable caught) {
assertEquals(t, caught);
}
assertEquals(1, th.getCalls());
assertEquals(1, th.getCalls("remoteException"));
verify(mi);
}
@SuppressWarnings("serial")
private static class MyThrowsHandler extends MethodCounter implements ThrowsAdvice {
// Full method signature
public void afterThrowing(Method m, Object[] args, Object target, IOException ex) {
count("ioException");
}
public void afterThrowing(RemoteException ex) throws Throwable {
count("remoteException");
}
/** Not valid, wrong number of arguments */
public void afterThrowing(Method m, Exception ex) throws Throwable {
throw new UnsupportedOperationException("Shouldn't be called");
}
}
}

View File

@@ -0,0 +1,160 @@
/*
* 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.interceptor;
import static org.junit.Assert.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import test.beans.DerivedTestBean;
import test.beans.ITestBean;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
/**
* @author Juergen Hoeller
* @author Chris Beams
* @since 06.04.2004
*/
public final class ConcurrencyThrottleInterceptorTests {
protected static final Log logger = LogFactory.getLog(ConcurrencyThrottleInterceptorTests.class);
public static final int NR_OF_THREADS = 100;
public static final int NR_OF_ITERATIONS = 1000;
@Test
public void testSerializable() throws Exception {
DerivedTestBean tb = new DerivedTestBean();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor();
proxyFactory.addAdvice(cti);
proxyFactory.setTarget(tb);
ITestBean proxy = (ITestBean) proxyFactory.getProxy();
proxy.getAge();
ITestBean serializedProxy = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy);
Advised advised = (Advised) serializedProxy;
ConcurrencyThrottleInterceptor serializedCti =
(ConcurrencyThrottleInterceptor) advised.getAdvisors()[0].getAdvice();
assertEquals(cti.getConcurrencyLimit(), serializedCti.getConcurrencyLimit());
serializedProxy.getAge();
}
@Test
public void testMultipleThreadsWithLimit1() {
testMultipleThreads(1);
}
@Test
public void testMultipleThreadsWithLimit10() {
testMultipleThreads(10);
}
private void testMultipleThreads(int concurrencyLimit) {
TestBean tb = new TestBean();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setInterfaces(new Class[] {ITestBean.class});
ConcurrencyThrottleInterceptor cti = new ConcurrencyThrottleInterceptor();
cti.setConcurrencyLimit(concurrencyLimit);
proxyFactory.addAdvice(cti);
proxyFactory.setTarget(tb);
ITestBean proxy = (ITestBean) proxyFactory.getProxy();
Thread[] threads = new Thread[NR_OF_THREADS];
for (int i = 0; i < NR_OF_THREADS; i++) {
threads[i] = new ConcurrencyThread(proxy, null);
threads[i].start();
}
for (int i = 0; i < NR_OF_THREADS / 10; i++) {
try {
Thread.sleep(5);
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
threads[i] = new ConcurrencyThread(proxy,
i % 2 == 0 ? (Throwable) new OutOfMemoryError() : (Throwable) new IllegalStateException());
threads[i].start();
}
for (int i = 0; i < NR_OF_THREADS; i++) {
try {
threads[i].join();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
private static class ConcurrencyThread extends Thread {
private ITestBean proxy;
private Throwable ex;
public ConcurrencyThread(ITestBean proxy, Throwable ex) {
this.proxy = proxy;
this.ex = ex;
}
public void run() {
if (this.ex != null) {
try {
this.proxy.exceptional(this.ex);
}
catch (RuntimeException ex) {
if (ex == this.ex) {
logger.debug("Expected exception thrown", ex);
}
else {
// should never happen
ex.printStackTrace();
}
}
catch (Error err) {
if (err == this.ex) {
logger.debug("Expected exception thrown", err);
}
else {
// should never happen
ex.printStackTrace();
}
}
catch (Throwable ex) {
// should never happen
ex.printStackTrace();
}
}
else {
for (int i = 0; i < NR_OF_ITERATIONS; i++) {
this.proxy.getName();
}
}
logger.debug("finished");
}
}
}

View File

@@ -0,0 +1,197 @@
/*
* 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.interceptor;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.junit.Test;
/**
* @author Rob Harrop
* @author Rick Evans
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class CustomizableTraceInterceptorTests {
@Test(expected=IllegalArgumentException.class)
public void testSetEmptyEnterMessage() {
// Must not be able to set empty enter message
new CustomizableTraceInterceptor().setEnterMessage("");
}
@Test(expected=IllegalArgumentException.class)
public void testSetEnterMessageWithReturnValuePlaceholder() {
// Must not be able to set enter message with return value placeholder
new CustomizableTraceInterceptor().setEnterMessage(CustomizableTraceInterceptor.PLACEHOLDER_RETURN_VALUE);
}
@Test(expected=IllegalArgumentException.class)
public void testSetEnterMessageWithExceptionPlaceholder() {
// Must not be able to set enter message with exception placeholder
new CustomizableTraceInterceptor().setEnterMessage(CustomizableTraceInterceptor.PLACEHOLDER_EXCEPTION);
}
@Test(expected=IllegalArgumentException.class)
public void testSetEnterMessageWithInvocationTimePlaceholder() {
// Must not be able to set enter message with invocation time placeholder
new CustomizableTraceInterceptor().setEnterMessage(CustomizableTraceInterceptor.PLACEHOLDER_INVOCATION_TIME);
}
@Test(expected=IllegalArgumentException.class)
public void testSetEmptyExitMessage() {
// Must not be able to set empty exit message
new CustomizableTraceInterceptor().setExitMessage("");
}
@Test(expected=IllegalArgumentException.class)
public void testSetExitMessageWithExceptionPlaceholder() {
// Must not be able to set exit message with exception placeholder
new CustomizableTraceInterceptor().setExitMessage(CustomizableTraceInterceptor.PLACEHOLDER_EXCEPTION);
}
@Test(expected=IllegalArgumentException.class)
public void testSetEmptyExceptionMessage() {
// Must not be able to set empty exception message
new CustomizableTraceInterceptor().setExceptionMessage("");
}
@Test(expected=IllegalArgumentException.class)
public void testSetExceptionMethodWithReturnValuePlaceholder() {
// Must not be able to set exception message with return value placeholder
new CustomizableTraceInterceptor().setExceptionMessage(CustomizableTraceInterceptor.PLACEHOLDER_RETURN_VALUE);
}
@Test
public void testSunnyDayPathLogsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation methodInvocation = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[]{});
expect(log.isTraceEnabled()).andReturn(true);
expect(methodInvocation.getMethod()).andReturn(toString).times(4);
expect(methodInvocation.getThis()).andReturn(this).times(2);
log.trace(isA(String.class));
expect(methodInvocation.proceed()).andReturn(null);
log.trace(isA(String.class));
replay(methodInvocation);
replay(log);
CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log);
interceptor.invoke(methodInvocation);
verify(log);
verify(methodInvocation);
}
@Test
public void testExceptionPathLogsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation methodInvocation = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[]{});
expect(log.isTraceEnabled()).andReturn(true);
expect(methodInvocation.getMethod()).andReturn(toString).times(4);
expect(methodInvocation.getThis()).andReturn(this).times(2);
log.trace(isA(String.class));
IllegalArgumentException exception = new IllegalArgumentException();
expect(methodInvocation.proceed()).andThrow(exception);
log.trace(isA(String.class), eq(exception));
replay(log);
replay(methodInvocation);
CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log);
try {
interceptor.invoke(methodInvocation);
fail("Must have propagated the IllegalArgumentException.");
}
catch (IllegalArgumentException expected) {
}
verify(log);
verify(methodInvocation);
}
@Test
public void testSunnyDayPathLogsCorrectlyWithPrettyMuchAllPlaceholdersMatching() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation methodInvocation = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[0]);
Object[] arguments = new Object[]{"$ One \\$", new Long(2)};
expect(log.isTraceEnabled()).andReturn(true);
expect(methodInvocation.getMethod()).andReturn(toString).times(7);
expect(methodInvocation.getThis()).andReturn(this).times(2);
expect(methodInvocation.getArguments()).andReturn(arguments).times(2);
log.trace(isA(String.class));
expect(methodInvocation.proceed()).andReturn("Hello!");
log.trace(isA(String.class));
replay(methodInvocation);
replay(log);
CustomizableTraceInterceptor interceptor = new StubCustomizableTraceInterceptor(log);
interceptor.setEnterMessage(new StringBuffer()
.append("Entering the '").append(CustomizableTraceInterceptor.PLACEHOLDER_METHOD_NAME)
.append("' method of the [").append(CustomizableTraceInterceptor.PLACEHOLDER_TARGET_CLASS_NAME)
.append("] class with the following args (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENTS)
.append(") and arg types (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENT_TYPES)
.append(").").toString());
interceptor.setExitMessage(new StringBuffer()
.append("Exiting the '").append(CustomizableTraceInterceptor.PLACEHOLDER_METHOD_NAME)
.append("' method of the [").append(CustomizableTraceInterceptor.PLACEHOLDER_TARGET_CLASS_SHORT_NAME)
.append("] class with the following args (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENTS)
.append(") and arg types (").append(CustomizableTraceInterceptor.PLACEHOLDER_ARGUMENT_TYPES)
.append("), returning '").append(CustomizableTraceInterceptor.PLACEHOLDER_RETURN_VALUE)
.append("' and taking '").append(CustomizableTraceInterceptor.PLACEHOLDER_INVOCATION_TIME)
.append("' this long.").toString());
interceptor.invoke(methodInvocation);
verify(log);
verify(methodInvocation);
}
@SuppressWarnings("serial")
private static class StubCustomizableTraceInterceptor extends CustomizableTraceInterceptor {
private final Log log;
public StubCustomizableTraceInterceptor(Log log) {
super.setUseDynamicLogger(false);
this.log = log;
}
protected Log getLoggerForInvocation(MethodInvocation invocation) {
return this.log;
}
}
}

View File

@@ -0,0 +1,105 @@
/*
* 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.interceptor;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.junit.Test;
/**
* Unit tests for the {@link DebugInterceptor} class.
*
* @author Rick Evans
* @author Chris Beams
*/
public final class DebugInterceptorTests {
@Test
public void testSunnyDayPathLogsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation methodInvocation = createMock(MethodInvocation.class);
expect(log.isTraceEnabled()).andReturn(true);
log.trace(isA(String.class));
expect(methodInvocation.proceed()).andReturn(null);
log.trace(isA(String.class));
replay(methodInvocation);
replay(log);
DebugInterceptor interceptor = new StubDebugInterceptor(log);
interceptor.invoke(methodInvocation);
checkCallCountTotal(interceptor);
verify(methodInvocation);
verify(log);
}
@Test
public void testExceptionPathStillLogsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation methodInvocation = createMock(MethodInvocation.class);
expect(log.isTraceEnabled()).andReturn(true);
log.trace(isA(String.class));
IllegalArgumentException exception = new IllegalArgumentException();
expect(methodInvocation.proceed()).andThrow(exception);
log.trace(isA(String.class), eq(exception));
replay(methodInvocation);
replay(log);
DebugInterceptor interceptor = new StubDebugInterceptor(log);
try {
interceptor.invoke(methodInvocation);
fail("Must have propagated the IllegalArgumentException.");
} catch (IllegalArgumentException expected) {
}
checkCallCountTotal(interceptor);
verify(methodInvocation);
verify(log);
}
private void checkCallCountTotal(DebugInterceptor interceptor) {
assertEquals("Intercepted call count not being incremented correctly", 1, interceptor.getCount());
}
@SuppressWarnings("serial")
private static final class StubDebugInterceptor extends DebugInterceptor {
private final Log log;
public StubDebugInterceptor(Log log) {
super(true);
this.log = log;
}
protected Log getLoggerForInvocation(MethodInvocation invocation) {
return log;
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* 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.interceptor;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.NamedBean;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class ExposeBeanNameAdvisorsTests {
private class RequiresBeanNameBoundTestBean extends TestBean {
private final String beanName;
public RequiresBeanNameBoundTestBean(String beanName) {
this.beanName = beanName;
}
public int getAge() {
assertEquals(beanName, ExposeBeanNameAdvisors.getBeanName());
return super.getAge();
}
}
@Test
public void testNoIntroduction() {
String beanName = "foo";
TestBean target = new RequiresBeanNameBoundTestBean(beanName);
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
pf.addAdvisor(ExposeBeanNameAdvisors.createAdvisorWithoutIntroduction(beanName));
ITestBean proxy = (ITestBean) pf.getProxy();
assertFalse("No introduction", proxy instanceof NamedBean);
// Requires binding
proxy.getAge();
}
@Test
public void testWithIntroduction() {
String beanName = "foo";
TestBean target = new RequiresBeanNameBoundTestBean(beanName);
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(ExposeInvocationInterceptor.ADVISOR);
pf.addAdvisor(ExposeBeanNameAdvisors.createAdvisorIntroducingNamedBean(beanName));
ITestBean proxy = (ITestBean) pf.getProxy();
assertTrue("Introduction was made", proxy instanceof NamedBean);
// Requires binding
proxy.getAge();
NamedBean nb = (NamedBean) proxy;
assertEquals("Name returned correctly", beanName, nb.getBeanName());
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<!--
Tests for throws advice.
-->
<beans>
<bean id="nopInterceptor" class="test.aop.NopInterceptor"/>
<bean id="exposeInvocation" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
<property name="targetClass">
<value>org.springframework.aop.interceptor.ExposeInvocationInterceptor</value>
</property>
<property name="targetField"><value>INSTANCE</value></property>
</bean>
<bean id="countingBeforeAdvice" class="test.aop.CountingBeforeAdvice"/>
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="org.springframework.aop.interceptor.InvocationCheckExposedInvocationTestBean" />
</property>
<property name="interceptorNames">
<value>exposeInvocation,countingBeforeAdvice,nopInterceptor</value>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,78 @@
/*
* 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.interceptor;
import static org.junit.Assert.*;
import static test.util.TestResourceUtils.qualifiedResource;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* Non-XML tests are in AbstractAopProxyTests
*
* @author Rod Johnson
* @author Chris Beams
*/
public final class ExposeInvocationInterceptorTests {
private static final Resource CONTEXT =
qualifiedResource(ExposeInvocationInterceptorTests.class, "context.xml");
@Test
public void testXmlConfig() {
XmlBeanFactory bf = new XmlBeanFactory(CONTEXT);
ITestBean tb = (ITestBean) bf.getBean("proxy");
String name= "tony";
tb.setName(name);
// Fires context checks
assertEquals(name, tb.getName());
}
}
abstract class ExposedInvocationTestBean extends TestBean {
public String getName() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
assertions(invocation);
return super.getName();
}
public void absquatulate() {
MethodInvocation invocation = ExposeInvocationInterceptor.currentInvocation();
assertions(invocation);
super.absquatulate();
}
protected abstract void assertions(MethodInvocation invocation);
}
class InvocationCheckExposedInvocationTestBean extends ExposedInvocationTestBean {
protected void assertions(MethodInvocation invocation) {
assertTrue(invocation.getThis() == this);
assertTrue("Invocation should be on ITestBean: " + invocation.getMethod(),
ITestBean.class.isAssignableFrom(invocation.getMethod().getDeclaringClass()));
}
}

View File

@@ -0,0 +1,92 @@
/*
* 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.interceptor;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.junit.Test;
/**
* @author Rob Harrop
* @author Rick Evans
* @author Chris Beams
*/
public final class PerformanceMonitorInterceptorTests {
@Test
public void testSuffixAndPrefixAssignment() {
PerformanceMonitorInterceptor interceptor = new PerformanceMonitorInterceptor();
assertNotNull(interceptor.getPrefix());
assertNotNull(interceptor.getSuffix());
interceptor.setPrefix(null);
interceptor.setSuffix(null);
assertNotNull(interceptor.getPrefix());
assertNotNull(interceptor.getSuffix());
}
@Test
public void testSunnyDayPathLogsPerformanceMetricsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation mi = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[0]);
expect(mi.getMethod()).andReturn(toString);
expect(mi.proceed()).andReturn(null);
log.trace(isA(String.class));
replay(mi, log);
PerformanceMonitorInterceptor interceptor = new PerformanceMonitorInterceptor(true);
interceptor.invokeUnderTrace(mi, log);
verify(mi, log);
}
@Test
public void testExceptionPathStillLogsPerformanceMetricsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation mi = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[0]);
expect(mi.getMethod()).andReturn(toString);
expect(mi.proceed()).andThrow(new IllegalArgumentException());
log.trace(isA(String.class));
replay(mi, log);
PerformanceMonitorInterceptor interceptor = new PerformanceMonitorInterceptor(true);
try {
interceptor.invokeUnderTrace(mi, log);
fail("Must have propagated the IllegalArgumentException.");
}
catch (IllegalArgumentException expected) {
}
verify(mi, log);
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.interceptor;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.fail;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.junit.Test;
/**
* Unit tests for the {@link SimpleTraceInterceptor} class.
*
* @author Rick Evans
* @author Chris Beams
*/
public final class SimpleTraceInterceptorTests {
@Test
public void testSunnyDayPathLogsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation mi = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[]{});
expect(mi.getMethod()).andReturn(toString);
expect(mi.getThis()).andReturn(this);
log.trace(isA(String.class));
expect(mi.proceed()).andReturn(null);
log.trace(isA(String.class));
replay(mi, log);
SimpleTraceInterceptor interceptor = new SimpleTraceInterceptor(true);
interceptor.invokeUnderTrace(mi, log);
verify(mi, log);
}
public void testExceptionPathStillLogsCorrectly() throws Throwable {
Log log = createMock(Log.class);
MethodInvocation mi = createMock(MethodInvocation.class);
Method toString = String.class.getMethod("toString", new Class[]{});
expect(mi.getMethod()).andReturn(toString);
expect(mi.getThis()).andReturn(this);
log.trace(isA(String.class));
IllegalArgumentException exception = new IllegalArgumentException();
expect(mi.proceed()).andThrow(exception);
log.trace(isA(String.class));
replay(mi, log);
final SimpleTraceInterceptor interceptor = new SimpleTraceInterceptor(true);
try {
interceptor.invokeUnderTrace(mi, log);
fail("Must have propagated the IllegalArgumentException.");
} catch (IllegalArgumentException expected) {
}
verify(mi, log);
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.easymock.EasyMock.*;
import org.junit.Test;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
/**
* Unit tests for the {@link DefaultScopedObject} class.
*
* @author Rick Evans
* @author Chris Beams
*/
public final class DefaultScopedObjectTests {
private static final String GOOD_BEAN_NAME = "foo";
@Test(expected=IllegalArgumentException.class)
public void testCtorWithNullBeanFactory() throws Exception {
new DefaultScopedObject(null, GOOD_BEAN_NAME);
}
@Test(expected=IllegalArgumentException.class)
public void testCtorWithNullTargetBeanName() throws Exception {
testBadTargetBeanName(null);
}
@Test(expected=IllegalArgumentException.class)
public void testCtorWithEmptyTargetBeanName() throws Exception {
testBadTargetBeanName("");
}
@Test(expected=IllegalArgumentException.class)
public void testCtorWithJustWhitespacedTargetBeanName() throws Exception {
testBadTargetBeanName(" ");
}
private static void testBadTargetBeanName(final String badTargetBeanName) {
ConfigurableBeanFactory factory = createMock(ConfigurableBeanFactory.class);
replay(factory);
new DefaultScopedObject(factory, badTargetBeanName);
verify(factory);
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false">
<aop:scoped-proxy/>
</bean>
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true"/>
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
</beans>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="scoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="true">
<aop:scoped-proxy/>
</bean>
<bean id="unscoped" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire-candidate="false"/>
<bean id="autowired" class="org.springframework.aop.scope.ScopedProxyAutowireTests$TestBean" autowire="byType"/>
</beans>

View File

@@ -0,0 +1,67 @@
/*
* 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.assertSame;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
/**
* @author Mark Fisher
* @author Chris Beams
*/
public final class ScopedProxyAutowireTests {
private static final Class<?> CLASS = ScopedProxyAutowireTests.class;
private static final Resource SCOPED_AUTOWIRE_TRUE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireTrue.xml");
private static final Resource SCOPED_AUTOWIRE_FALSE_CONTEXT = qualifiedResource(CLASS, "scopedAutowireFalse.xml");
@Test
public void testScopedProxyInheritsAutowireCandidateFalse() {
XmlBeanFactory bf = new XmlBeanFactory(SCOPED_AUTOWIRE_FALSE_CONTEXT);
TestBean autowired = (TestBean) bf.getBean("autowired");
TestBean unscoped = (TestBean) bf.getBean("unscoped");
assertSame(unscoped, autowired.getChild());
}
@Test
public void testScopedProxyReplacesAutowireCandidateTrue() {
XmlBeanFactory bf = new XmlBeanFactory(SCOPED_AUTOWIRE_TRUE_CONTEXT);
TestBean autowired = (TestBean) bf.getBean("autowired");
TestBean scoped = (TestBean) bf.getBean("scoped");
assertSame(scoped, autowired.getChild());
}
static class TestBean {
private TestBean child;
public void setChild(TestBean child) {
this.child = child;
}
public TestBean getChild() {
return this.child;
}
}
}

View File

@@ -0,0 +1,114 @@
/*
* 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.support;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
/**
* @author Rod Johnson
* @author Dmitriy Kopylenko
* @author Chris Beams
*/
public abstract class AbstractRegexpMethodPointcutTests {
private AbstractRegexpMethodPointcut rpc;
@Before
public void setUp() {
rpc = getRegexpMethodPointcut();
}
protected abstract AbstractRegexpMethodPointcut getRegexpMethodPointcut();
@Test
public void testNoPatternSupplied() throws Exception {
noPatternSuppliedTests(rpc);
}
@Test
public void testSerializationWithNoPatternSupplied() throws Exception {
rpc = (AbstractRegexpMethodPointcut) SerializationTestUtils.serializeAndDeserialize(rpc);
noPatternSuppliedTests(rpc);
}
protected void noPatternSuppliedTests(AbstractRegexpMethodPointcut rpc) throws Exception {
assertFalse(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class));
assertFalse(rpc.matches(Object.class.getMethod("wait", (Class[]) null), Object.class));
assertEquals(0, rpc.getPatterns().length);
}
@Test
public void testExactMatch() throws Exception {
rpc.setPattern("java.lang.Object.hashCode");
exactMatchTests(rpc);
rpc = (AbstractRegexpMethodPointcut) SerializationTestUtils.serializeAndDeserialize(rpc);
exactMatchTests(rpc);
}
protected void exactMatchTests(AbstractRegexpMethodPointcut rpc) throws Exception {
// assumes rpc.setPattern("java.lang.Object.hashCode");
assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class));
assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), Object.class));
assertFalse(rpc.matches(Object.class.getMethod("wait", (Class[]) null), Object.class));
}
@Test
public void testSpecificMatch() throws Exception {
rpc.setPattern("java.lang.String.hashCode");
assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class));
assertFalse(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), Object.class));
}
@Test
public void testWildcard() throws Exception {
rpc.setPattern(".*Object.hashCode");
assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), Object.class));
assertFalse(rpc.matches(Object.class.getMethod("wait", (Class[]) null), Object.class));
}
@Test
public void testWildcardForOneClass() throws Exception {
rpc.setPattern("java.lang.Object.*");
assertTrue(rpc.matches(Object.class.getMethod("hashCode", (Class[]) null), String.class));
assertTrue(rpc.matches(Object.class.getMethod("wait", (Class[]) null), String.class));
}
@Test
public void testMatchesObjectClass() throws Exception {
rpc.setPattern("java.lang.Object.*");
assertTrue(rpc.matches(Exception.class.getMethod("hashCode", (Class[]) null), IOException.class));
// Doesn't match a method from Throwable
assertFalse(rpc.matches(Exception.class.getMethod("getMessage", (Class[]) null), Exception.class));
}
@Test
public void testWithExclusion() throws Exception {
this.rpc.setPattern(".*get.*");
this.rpc.setExcludedPattern(".*Age.*");
assertTrue(this.rpc.matches(TestBean.class.getMethod("getName"), TestBean.class));
assertFalse(this.rpc.matches(TestBean.class.getMethod("getAge"), TestBean.class));
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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.support;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
import org.springframework.aop.target.EmptyTargetSource;
import test.aop.NopInterceptor;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class AopUtilsTests {
@Test
public void testPointcutCanNeverApply() {
class TestPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method method, Class<?> clazzy) {
return false;
}
}
Pointcut no = new TestPointcut();
assertFalse(AopUtils.canApply(no, Object.class));
}
@Test
public void testPointcutAlwaysApplies() {
assertTrue(AopUtils.canApply(new DefaultPointcutAdvisor(new NopInterceptor()), Object.class));
assertTrue(AopUtils.canApply(new DefaultPointcutAdvisor(new NopInterceptor()), TestBean.class));
}
@Test
public void testPointcutAppliesToOneMethodOnObject() {
class TestPointcut extends StaticMethodMatcherPointcut {
public boolean matches(Method method, Class<?> clazz) {
return method.getName().equals("hashCode");
}
}
Pointcut pc = new TestPointcut();
// will return true if we're not proxying interfaces
assertTrue(AopUtils.canApply(pc, Object.class));
}
/**
* Test that when we serialize and deserialize various canonical instances
* of AOP classes, they return the same instance, not a new instance
* that's subverted the singleton construction limitation.
*/
@Test
public void testCanonicalFrameworkClassesStillCanonicalOnDeserialization() throws Exception {
assertSame(MethodMatcher.TRUE, SerializationTestUtils.serializeAndDeserialize(MethodMatcher.TRUE));
assertSame(ClassFilter.TRUE, SerializationTestUtils.serializeAndDeserialize(ClassFilter.TRUE));
assertSame(Pointcut.TRUE, SerializationTestUtils.serializeAndDeserialize(Pointcut.TRUE));
assertSame(EmptyTargetSource.INSTANCE, SerializationTestUtils.serializeAndDeserialize(EmptyTargetSource.INSTANCE));
assertSame(Pointcuts.SETTERS, SerializationTestUtils.serializeAndDeserialize(Pointcuts.SETTERS));
assertSame(Pointcuts.GETTERS, SerializationTestUtils.serializeAndDeserialize(Pointcuts.GETTERS));
assertSame(ExposeInvocationInterceptor.INSTANCE,
SerializationTestUtils.serializeAndDeserialize(ExposeInvocationInterceptor.INSTANCE));
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.support;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.core.NestedRuntimeException;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class ClassFiltersTests {
private ClassFilter exceptionFilter = new RootClassFilter(Exception.class);
private ClassFilter itbFilter = new RootClassFilter(ITestBean.class);
private ClassFilter hasRootCauseFilter = new RootClassFilter(NestedRuntimeException.class);
@Test
public void testUnion() {
assertTrue(exceptionFilter.matches(RuntimeException.class));
assertFalse(exceptionFilter.matches(TestBean.class));
assertFalse(itbFilter.matches(Exception.class));
assertTrue(itbFilter.matches(TestBean.class));
ClassFilter union = ClassFilters.union(exceptionFilter, itbFilter);
assertTrue(union.matches(RuntimeException.class));
assertTrue(union.matches(TestBean.class));
}
@Test
public void testIntersection() {
assertTrue(exceptionFilter.matches(RuntimeException.class));
assertTrue(hasRootCauseFilter.matches(NestedRuntimeException.class));
ClassFilter intersection = ClassFilters.intersection(exceptionFilter, hasRootCauseFilter);
assertFalse(intersection.matches(RuntimeException.class));
assertFalse(intersection.matches(TestBean.class));
assertTrue(intersection.matches(NestedRuntimeException.class));
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2002-2009 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.support;
import junit.framework.TestCase;
import org.springframework.aop.framework.ProxyFactory;
import test.beans.TestBean;
import org.springframework.util.ClassUtils;
/**
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @author Rob Harrop
* @author Rick Evans
*/
public class ClassUtilsTests extends TestCase {
public void testGetShortNameForCglibClass() {
TestBean tb = new TestBean();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(tb);
pf.setProxyTargetClass(true);
TestBean proxy = (TestBean) pf.getProxy();
String className = ClassUtils.getShortName(proxy.getClass());
assertEquals("Class name did not match", "TestBean", className);
}
}

View File

@@ -0,0 +1,152 @@
/*
* 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.support;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.core.NestedRuntimeException;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class ComposablePointcutTests {
public static MethodMatcher GETTER_METHOD_MATCHER = new StaticMethodMatcher() {
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith("get");
}
};
public static MethodMatcher GET_AGE_METHOD_MATCHER = new StaticMethodMatcher() {
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().equals("getAge");
}
};
public static MethodMatcher ABSQUATULATE_METHOD_MATCHER = new StaticMethodMatcher() {
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().equals("absquatulate");
}
};
public static MethodMatcher SETTER_METHOD_MATCHER = new StaticMethodMatcher() {
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith("set");
}
};
@Test
public void testMatchAll() throws NoSuchMethodException {
Pointcut pc = new ComposablePointcut();
assertTrue(pc.getClassFilter().matches(Object.class));
assertTrue(pc.getMethodMatcher().matches(Object.class.getMethod("hashCode", (Class[]) null), Exception.class));
}
@Test
public void testFilterByClass() throws NoSuchMethodException {
ComposablePointcut pc = new ComposablePointcut();
assertTrue(pc.getClassFilter().matches(Object.class));
ClassFilter cf = new RootClassFilter(Exception.class);
pc.intersection(cf);
assertFalse(pc.getClassFilter().matches(Object.class));
assertTrue(pc.getClassFilter().matches(Exception.class));
pc.intersection(new RootClassFilter(NestedRuntimeException.class));
assertFalse(pc.getClassFilter().matches(Exception.class));
assertTrue(pc.getClassFilter().matches(NestedRuntimeException.class));
assertFalse(pc.getClassFilter().matches(String.class));
pc.union(new RootClassFilter(String.class));
assertFalse(pc.getClassFilter().matches(Exception.class));
assertTrue(pc.getClassFilter().matches(String.class));
assertTrue(pc.getClassFilter().matches(NestedRuntimeException.class));
}
@Test
public void testUnionMethodMatcher() {
// Matches the getAge() method in any class
ComposablePointcut pc = new ComposablePointcut(ClassFilter.TRUE, GET_AGE_METHOD_MATCHER);
assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null));
pc.union(GETTER_METHOD_MATCHER);
// Should now match all getter methods
assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null));
pc.union(ABSQUATULATE_METHOD_MATCHER);
// Should now match absquatulate() as well
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null));
// But it doesn't match everything
assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_SET_AGE, TestBean.class, null));
}
@Test
public void testIntersectionMethodMatcher() {
ComposablePointcut pc = new ComposablePointcut();
assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class));
assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class));
assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class));
pc.intersection(GETTER_METHOD_MATCHER);
assertFalse(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class));
assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class));
assertTrue(pc.getMethodMatcher().matches(PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class));
pc.intersection(GET_AGE_METHOD_MATCHER);
// Use the Pointcuts matches method
assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertTrue(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(pc, PointcutsTests.TEST_BEAN_GET_NAME, TestBean.class, null));
}
@Test
public void testEqualsAndHashCode() throws Exception {
ComposablePointcut pc1 = new ComposablePointcut();
ComposablePointcut pc2 = new ComposablePointcut();
assertEquals(pc1, pc2);
assertEquals(pc1.hashCode(), pc2.hashCode());
pc1.intersection(GETTER_METHOD_MATCHER);
assertFalse(pc1.equals(pc2));
assertFalse(pc1.hashCode() == pc2.hashCode());
pc2.intersection(GETTER_METHOD_MATCHER);
assertEquals(pc1, pc2);
assertEquals(pc1.hashCode(), pc2.hashCode());
pc1.union(GET_AGE_METHOD_MATCHER);
pc2.union(GET_AGE_METHOD_MATCHER);
assertEquals(pc1, pc2);
assertEquals(pc1.hashCode(), pc2.hashCode());
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.support;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import test.aop.NopInterceptor;
import test.beans.ITestBean;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class ControlFlowPointcutTests {
@Test
public void testMatches() {
TestBean target = new TestBean();
target.setAge(27);
NopInterceptor nop = new NopInterceptor();
ControlFlowPointcut cflow = new ControlFlowPointcut(One.class, "getAge");
ProxyFactory pf = new ProxyFactory(target);
ITestBean proxied = (ITestBean) pf.getProxy();
pf.addAdvisor(new DefaultPointcutAdvisor(cflow, nop));
// Not advised, not under One
assertEquals(target.getAge(), proxied.getAge());
assertEquals(0, nop.getCount());
// Will be advised
assertEquals(target.getAge(), new One().getAge(proxied));
assertEquals(1, nop.getCount());
// Won't be advised
assertEquals(target.getAge(), new One().nomatch(proxied));
assertEquals(1, nop.getCount());
assertEquals(3, cflow.getEvaluations());
}
/**
* Check that we can use a cflow pointcut only in conjunction with
* a static pointcut: e.g. all setter methods that are invoked under
* a particular class. This greatly reduces the number of calls
* to the cflow pointcut, meaning that it's not so prohibitively
* expensive.
*/
@Test
public void testSelectiveApplication() {
TestBean target = new TestBean();
target.setAge(27);
NopInterceptor nop = new NopInterceptor();
ControlFlowPointcut cflow = new ControlFlowPointcut(One.class);
Pointcut settersUnderOne = Pointcuts.intersection(Pointcuts.SETTERS, cflow);
ProxyFactory pf = new ProxyFactory(target);
ITestBean proxied = (ITestBean) pf.getProxy();
pf.addAdvisor(new DefaultPointcutAdvisor(settersUnderOne, nop));
// Not advised, not under One
target.setAge(16);
assertEquals(0, nop.getCount());
// Not advised; under One but not a setter
assertEquals(16, new One().getAge(proxied));
assertEquals(0, nop.getCount());
// Won't be advised
new One().set(proxied);
assertEquals(1, nop.getCount());
// We saved most evaluations
assertEquals(1, cflow.getEvaluations());
}
@Test
public void testEqualsAndHashCode() throws Exception {
assertEquals(new ControlFlowPointcut(One.class), new ControlFlowPointcut(One.class));
assertEquals(new ControlFlowPointcut(One.class, "getAge"), new ControlFlowPointcut(One.class, "getAge"));
assertFalse(new ControlFlowPointcut(One.class, "getAge").equals(new ControlFlowPointcut(One.class)));
assertEquals(new ControlFlowPointcut(One.class).hashCode(), new ControlFlowPointcut(One.class).hashCode());
assertEquals(new ControlFlowPointcut(One.class, "getAge").hashCode(), new ControlFlowPointcut(One.class, "getAge").hashCode());
assertFalse(new ControlFlowPointcut(One.class, "getAge").hashCode() == new ControlFlowPointcut(One.class).hashCode());
}
public class One {
int getAge(ITestBean proxied) {
return proxied.getAge();
}
int nomatch(ITestBean proxied) {
return proxied.getAge();
}
void set(ITestBean proxied) {
proxied.setAge(5);
}
}
}

View File

@@ -0,0 +1,310 @@
/*
* 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.support;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import java.io.Serializable;
import org.aopalliance.intercept.MethodInterceptor;
import org.junit.Test;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.IntroductionInterceptor;
import org.springframework.aop.framework.ProxyFactory;
import test.aop.SerializableNopInterceptor;
import test.beans.INestedTestBean;
import test.beans.ITestBean;
import test.beans.NestedTestBean;
import test.beans.Person;
import test.beans.SerializablePerson;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
import test.util.TimeStamped;
/**
* @author Rod Johnson
* @author Chris Beams
* @since 13.05.2003
*/
public final class DelegatingIntroductionInterceptorTests {
@Test(expected=IllegalArgumentException.class)
public void testNullTarget() throws Exception {
// Shouldn't accept null target
new DelegatingIntroductionInterceptor(null);
}
@Test
public void testIntroductionInterceptorWithDelegation() throws Exception {
TestBean raw = new TestBean();
assertTrue(! (raw instanceof TimeStamped));
ProxyFactory factory = new ProxyFactory(raw);
TimeStamped ts = createMock(TimeStamped.class);
long timestamp = 111L;
expect(ts.getTimeStamp()).andReturn(timestamp);
replay(ts);
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts)));
TimeStamped tsp = (TimeStamped) factory.getProxy();
assertTrue(tsp.getTimeStamp() == timestamp);
verify(ts);
}
@Test
public void testIntroductionInterceptorWithInterfaceHierarchy() throws Exception {
TestBean raw = new TestBean();
assertTrue(! (raw instanceof SubTimeStamped));
ProxyFactory factory = new ProxyFactory(raw);
TimeStamped ts = createMock(SubTimeStamped.class);
long timestamp = 111L;
expect(ts.getTimeStamp()).andReturn(timestamp);
replay(ts);
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), SubTimeStamped.class));
SubTimeStamped tsp = (SubTimeStamped) factory.getProxy();
assertTrue(tsp.getTimeStamp() == timestamp);
verify(ts);
}
@Test
public void testIntroductionInterceptorWithSuperInterface() throws Exception {
TestBean raw = new TestBean();
assertTrue(! (raw instanceof TimeStamped));
ProxyFactory factory = new ProxyFactory(raw);
TimeStamped ts = createMock(SubTimeStamped.class);
long timestamp = 111L;
expect(ts.getTimeStamp()).andReturn(timestamp);
replay(ts);
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts), TimeStamped.class));
TimeStamped tsp = (TimeStamped) factory.getProxy();
assertTrue(!(tsp instanceof SubTimeStamped));
assertTrue(tsp.getTimeStamp() == timestamp);
verify(ts);
}
@Test
public void testAutomaticInterfaceRecognitionInDelegate() throws Exception {
final long t = 1001L;
class Tester implements TimeStamped, ITester {
public void foo() throws Exception {
}
public long getTimeStamp() {
return t;
}
}
DelegatingIntroductionInterceptor ii = new DelegatingIntroductionInterceptor(new Tester());
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii));
//assertTrue(Arrays.binarySearch(pf.getProxiedInterfaces(), TimeStamped.class) != -1);
TimeStamped ts = (TimeStamped) pf.getProxy();
assertTrue(ts.getTimeStamp() == t);
((ITester) ts).foo();
((ITestBean) ts).getAge();
}
@Test
public void testAutomaticInterfaceRecognitionInSubclass() throws Exception {
final long t = 1001L;
@SuppressWarnings("serial")
class TestII extends DelegatingIntroductionInterceptor implements TimeStamped, ITester {
public void foo() throws Exception {
}
public long getTimeStamp() {
return t;
}
}
DelegatingIntroductionInterceptor ii = new TestII();
TestBean target = new TestBean();
ProxyFactory pf = new ProxyFactory(target);
IntroductionAdvisor ia = new DefaultIntroductionAdvisor(ii);
assertTrue(ia.isPerInstance());
pf.addAdvisor(0, ia);
//assertTrue(Arrays.binarySearch(pf.getProxiedInterfaces(), TimeStamped.class) != -1);
TimeStamped ts = (TimeStamped) pf.getProxy();
assertTrue(ts instanceof TimeStamped);
// Shoulnd't proxy framework interfaces
assertTrue(!(ts instanceof MethodInterceptor));
assertTrue(!(ts instanceof IntroductionInterceptor));
assertTrue(ts.getTimeStamp() == t);
((ITester) ts).foo();
((ITestBean) ts).getAge();
// Test removal
ii.suppressInterface(TimeStamped.class);
// Note that we need to construct a new proxy factory,
// or suppress the interface on the proxy factory
pf = new ProxyFactory(target);
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii));
Object o = pf.getProxy();
assertTrue(!(o instanceof TimeStamped));
}
@SuppressWarnings("serial")
@Test
public void testIntroductionInterceptorDoesntReplaceToString() throws Exception {
TestBean raw = new TestBean();
assertTrue(! (raw instanceof TimeStamped));
ProxyFactory factory = new ProxyFactory(raw);
TimeStamped ts = new SerializableTimeStamped(0);
factory.addAdvisor(0, new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts) {
public String toString() {
throw new UnsupportedOperationException("Shouldn't be invoked");
}
}));
TimeStamped tsp = (TimeStamped) factory.getProxy();
assertEquals(0, tsp.getTimeStamp());
assertEquals(raw.toString(), tsp.toString());
}
@Test
public void testDelegateReturnsThisIsMassagedToReturnProxy() {
NestedTestBean target = new NestedTestBean();
String company = "Interface21";
target.setCompany(company);
TestBean delegate = new TestBean() {
public ITestBean getSpouse() {
return this;
}
};
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvice(new DelegatingIntroductionInterceptor(delegate));
INestedTestBean proxy = (INestedTestBean) pf.getProxy();
assertEquals(company, proxy.getCompany());
ITestBean introduction = (ITestBean) proxy;
assertSame("Introduced method returning delegate returns proxy", introduction, introduction.getSpouse());
assertTrue("Introduced method returning delegate returns proxy", AopUtils.isAopProxy(introduction.getSpouse()));
}
@Test
public void testSerializableDelegatingIntroductionInterceptorSerializable() throws Exception {
SerializablePerson serializableTarget = new SerializablePerson();
String name = "Tony";
serializableTarget.setName("Tony");
ProxyFactory factory = new ProxyFactory(serializableTarget);
factory.addInterface(Person.class);
long time = 1000;
TimeStamped ts = new SerializableTimeStamped(time);
factory.addAdvisor(new DefaultIntroductionAdvisor(new DelegatingIntroductionInterceptor(ts)));
factory.addAdvice(new SerializableNopInterceptor());
Person p = (Person) factory.getProxy();
assertEquals(name, p.getName());
assertEquals(time, ((TimeStamped) p).getTimeStamp());
Person p1 = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertEquals(name, p1.getName());
assertEquals(time, ((TimeStamped) p1).getTimeStamp());
}
// Test when target implements the interface: should get interceptor by preference.
@Test
public void testIntroductionMasksTargetImplementation() throws Exception {
final long t = 1001L;
@SuppressWarnings("serial")
class TestII extends DelegatingIntroductionInterceptor implements TimeStamped {
public long getTimeStamp() {
return t;
}
}
DelegatingIntroductionInterceptor ii = new TestII();
// != t
TestBean target = new TargetClass(t + 1);
ProxyFactory pf = new ProxyFactory(target);
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ii));
TimeStamped ts = (TimeStamped) pf.getProxy();
// From introduction interceptor, not target
assertTrue(ts.getTimeStamp() == t);
}
@SuppressWarnings("serial")
private static class SerializableTimeStamped implements TimeStamped, Serializable {
private final long ts;
public SerializableTimeStamped(long ts) {
this.ts = ts;
}
public long getTimeStamp() {
return ts;
}
}
public static class TargetClass extends TestBean implements TimeStamped {
long t;
public TargetClass(long t) {
this.t = t;
}
public long getTimeStamp() {
return t;
}
}
public interface ITester {
void foo() throws Exception;
}
private static interface SubTimeStamped extends TimeStamped {
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.support;
/**
* @author Dmitriy Kopylenko
*/
public final class JdkRegexpMethodPointcutTests extends AbstractRegexpMethodPointcutTests {
protected AbstractRegexpMethodPointcut getRegexpMethodPointcut() {
return new JdkRegexpMethodPointcut();
}
}

View File

@@ -0,0 +1,128 @@
/*
* 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.support;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.MethodMatcher;
import test.beans.IOther;
import test.beans.ITestBean;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
/**
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class MethodMatchersTests {
private final Method EXCEPTION_GETMESSAGE;
private final Method ITESTBEAN_SETAGE;
private final Method ITESTBEAN_GETAGE;
private final Method IOTHER_ABSQUATULATE;
public MethodMatchersTests() throws Exception {
EXCEPTION_GETMESSAGE = Exception.class.getMethod("getMessage", (Class[]) null);
ITESTBEAN_GETAGE = ITestBean.class.getMethod("getAge", (Class[]) null);
ITESTBEAN_SETAGE = ITestBean.class.getMethod("setAge", new Class[] { int.class });
IOTHER_ABSQUATULATE = IOther.class.getMethod("absquatulate", (Class[]) null);
}
@Test
public void testDefaultMatchesAll() throws Exception {
MethodMatcher defaultMm = MethodMatcher.TRUE;
assertTrue(defaultMm.matches(EXCEPTION_GETMESSAGE, Exception.class));
assertTrue(defaultMm.matches(ITESTBEAN_SETAGE, TestBean.class));
}
@Test
public void testMethodMatcherTrueSerializable() throws Exception {
assertSame(SerializationTestUtils.serializeAndDeserialize(MethodMatcher.TRUE), MethodMatcher.TRUE);
}
@Test
public void testSingle() throws Exception {
MethodMatcher defaultMm = MethodMatcher.TRUE;
assertTrue(defaultMm.matches(EXCEPTION_GETMESSAGE, Exception.class));
assertTrue(defaultMm.matches(ITESTBEAN_SETAGE, TestBean.class));
defaultMm = MethodMatchers.intersection(defaultMm, new StartsWithMatcher("get"));
assertTrue(defaultMm.matches(EXCEPTION_GETMESSAGE, Exception.class));
assertFalse(defaultMm.matches(ITESTBEAN_SETAGE, TestBean.class));
}
@Test
public void testDynamicAndStaticMethodMatcherIntersection() throws Exception {
MethodMatcher mm1 = MethodMatcher.TRUE;
MethodMatcher mm2 = new TestDynamicMethodMatcherWhichMatches();
MethodMatcher intersection = MethodMatchers.intersection(mm1, mm2);
assertTrue("Intersection is a dynamic matcher", intersection.isRuntime());
assertTrue("2Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class));
assertTrue("3Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Object[] { new Integer(5) }));
// Knock out dynamic part
intersection = MethodMatchers.intersection(intersection, new TestDynamicMethodMatcherWhichDoesNotMatch());
assertTrue("Intersection is a dynamic matcher", intersection.isRuntime());
assertTrue("2Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class));
assertFalse("3 - not Matched setAge method", intersection.matches(ITESTBEAN_SETAGE, TestBean.class, new Object[] { new Integer(5) }));
}
@Test
public void testStaticMethodMatcherUnion() throws Exception {
MethodMatcher getterMatcher = new StartsWithMatcher("get");
MethodMatcher setterMatcher = new StartsWithMatcher("set");
MethodMatcher union = MethodMatchers.union(getterMatcher, setterMatcher);
assertFalse("Union is a static matcher", union.isRuntime());
assertTrue("Matched setAge method", union.matches(ITESTBEAN_SETAGE, TestBean.class));
assertTrue("Matched getAge method", union.matches(ITESTBEAN_GETAGE, TestBean.class));
assertFalse("Didn't matched absquatulate method", union.matches(IOTHER_ABSQUATULATE, TestBean.class));
}
public static class StartsWithMatcher extends StaticMethodMatcher {
private String prefix;
public StartsWithMatcher(String s) {
this.prefix = s;
}
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith(prefix);
}
}
private static class TestDynamicMethodMatcherWhichMatches extends DynamicMethodMatcher {
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return true;
}
}
private static class TestDynamicMethodMatcherWhichDoesNotMatch extends DynamicMethodMatcher {
public boolean matches(Method m, Class<?> targetClass, Object[] args) {
return false;
}
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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.support;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import test.aop.NopInterceptor;
import test.aop.SerializableNopInterceptor;
import test.beans.Person;
import test.beans.SerializablePerson;
import test.util.SerializationTestUtils;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class NameMatchMethodPointcutTests {
protected NameMatchMethodPointcut pc;
protected Person proxied;
protected SerializableNopInterceptor nop;
/**
* Create an empty pointcut, populating instance variables.
*/
@Before
public void setUp() {
ProxyFactory pf = new ProxyFactory(new SerializablePerson());
nop = new SerializableNopInterceptor();
pc = new NameMatchMethodPointcut();
pf.addAdvisor(new DefaultPointcutAdvisor(pc, nop));
proxied = (Person) pf.getProxy();
}
@Test
public void testMatchingOnly() {
// Can't do exact matching through isMatch
assertTrue(pc.isMatch("echo", "ech*"));
assertTrue(pc.isMatch("setName", "setN*"));
assertTrue(pc.isMatch("setName", "set*"));
assertFalse(pc.isMatch("getName", "set*"));
assertFalse(pc.isMatch("setName", "set"));
assertTrue(pc.isMatch("testing", "*ing"));
}
@Test
public void testEmpty() throws Throwable {
assertEquals(0, nop.getCount());
proxied.getName();
proxied.setName("");
proxied.echo(null);
assertEquals(0, nop.getCount());
}
@Test
public void testMatchOneMethod() throws Throwable {
pc.addMethodName("echo");
pc.addMethodName("set*");
assertEquals(0, nop.getCount());
proxied.getName();
proxied.getName();
assertEquals(0, nop.getCount());
proxied.echo(null);
assertEquals(1, nop.getCount());
proxied.setName("");
assertEquals(2, nop.getCount());
proxied.setAge(25);
assertEquals(25, proxied.getAge());
assertEquals(3, nop.getCount());
}
@Test
public void testSets() throws Throwable {
pc.setMappedNames(new String[] { "set*", "echo" });
assertEquals(0, nop.getCount());
proxied.getName();
proxied.setName("");
assertEquals(1, nop.getCount());
proxied.echo(null);
assertEquals(2, nop.getCount());
}
@Test
public void testSerializable() throws Throwable {
testSets();
// Count is now 2
Person p2 = (Person) SerializationTestUtils.serializeAndDeserialize(proxied);
NopInterceptor nop2 = (NopInterceptor) ((Advised) p2).getAdvisors()[0].getAdvice();
p2.getName();
assertEquals(2, nop2.getCount());
p2.echo(null);
assertEquals(3, nop2.getCount());
}
@Test
public void testEqualsAndHashCode() throws Exception {
NameMatchMethodPointcut pc1 = new NameMatchMethodPointcut();
NameMatchMethodPointcut pc2 = new NameMatchMethodPointcut();
String foo = "foo";
assertEquals(pc1, pc2);
assertEquals(pc1.hashCode(), pc2.hashCode());
pc1.setMappedName(foo);
assertFalse(pc1.equals(pc2));
assertTrue(pc1.hashCode() != pc2.hashCode());
pc2.setMappedName(foo);
assertEquals(pc1, pc2);
assertEquals(pc1.hashCode(), pc2.hashCode());
}
}

View File

@@ -0,0 +1,244 @@
/*
* 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.support;
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import org.junit.Test;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.Pointcut;
import test.beans.TestBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class PointcutsTests {
public static Method TEST_BEAN_SET_AGE;
public static Method TEST_BEAN_GET_AGE;
public static Method TEST_BEAN_GET_NAME;
public static Method TEST_BEAN_ABSQUATULATE;
static {
try {
TEST_BEAN_SET_AGE = TestBean.class.getMethod("setAge", new Class[] { int.class });
TEST_BEAN_GET_AGE = TestBean.class.getMethod("getAge", (Class[]) null);
TEST_BEAN_GET_NAME = TestBean.class.getMethod("getName", (Class[]) null);
TEST_BEAN_ABSQUATULATE = TestBean.class.getMethod("absquatulate", (Class[]) null);
}
catch (Exception ex) {
throw new RuntimeException("Shouldn't happen: error in test suite");
}
}
/**
* Matches only TestBean class, not subclasses
*/
public static Pointcut allTestBeanMethodsPointcut = new StaticMethodMatcherPointcut() {
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class<?> clazz) {
return clazz.equals(TestBean.class);
}
};
}
public boolean matches(Method m, Class<?> targetClass) {
return true;
}
};
public static Pointcut allClassSetterPointcut = Pointcuts.SETTERS;
// Subclass used for matching
public static class MyTestBean extends TestBean {
}
public static Pointcut myTestBeanSetterPointcut = new StaticMethodMatcherPointcut() {
public ClassFilter getClassFilter() {
return new RootClassFilter(MyTestBean.class);
}
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith("set");
}
};
// Will match MyTestBeanSubclass
public static Pointcut myTestBeanGetterPointcut = new StaticMethodMatcherPointcut() {
public ClassFilter getClassFilter() {
return new RootClassFilter(MyTestBean.class);
}
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith("get");
}
};
// Still more specific class
public static class MyTestBeanSubclass extends MyTestBean {
}
public static Pointcut myTestBeanSubclassGetterPointcut = new StaticMethodMatcherPointcut() {
public ClassFilter getClassFilter() {
return new RootClassFilter(MyTestBeanSubclass.class);
}
public boolean matches(Method m, Class<?> targetClass) {
return m.getName().startsWith("get");
}
};
public static Pointcut allClassGetterPointcut = Pointcuts.GETTERS;
public static Pointcut allClassGetAgePointcut = new NameMatchMethodPointcut().addMethodName("getAge");
public static Pointcut allClassGetNamePointcut = new NameMatchMethodPointcut().addMethodName("getName");
@Test
public void testTrue() {
assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(Pointcut.TRUE, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
}
@Test
public void testMatches() {
assertTrue(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertFalse(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(allClassSetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertFalse(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(allClassGetterPointcut, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
}
/**
* Should match all setters and getters on any class
*/
@Test
public void testUnionOfSettersAndGetters() {
Pointcut union = Pointcuts.union(allClassGetterPointcut, allClassSetterPointcut);
assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
}
@Test
public void testUnionOfSpecificGetters() {
Pointcut union = Pointcuts.union(allClassGetAgePointcut, allClassGetNamePointcut);
assertFalse(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class, null));
assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
// Union with all setters
union = Pointcuts.union(union, allClassSetterPointcut);
assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_NAME, TestBean.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class, null));
assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
}
/**
* Tests vertical composition. First pointcut matches all setters.
* Second one matches all getters in the MyTestBean class. TestBean getters shouldn't pass.
*/
@Test
public void testUnionOfAllSettersAndSubclassSetters() {
assertFalse(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertTrue(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_SET_AGE, MyTestBean.class, new Object[] { new Integer(6)}));
assertFalse(Pointcuts.matches(myTestBeanSetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null));
Pointcut union = Pointcuts.union(myTestBeanSetterPointcut, allClassGetterPointcut);
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBean.class, null));
// Still doesn't match superclass setter
assertTrue(Pointcuts.matches(union, TEST_BEAN_SET_AGE, MyTestBean.class, new Object[] { new Integer(6)}));
assertFalse(Pointcuts.matches(union, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
}
/**
* Intersection should be MyTestBean getAge() only:
* it's the union of allClassGetAge and subclass getters
*/
@Test
public void testIntersectionOfSpecificGettersAndSubclassGetters() {
assertTrue(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(allClassGetAgePointcut, TEST_BEAN_GET_AGE, MyTestBean.class, null));
assertFalse(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_NAME, TestBean.class, null));
assertFalse(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_AGE, TestBean.class, null));
assertTrue(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_NAME, MyTestBean.class, null));
assertTrue(Pointcuts.matches(myTestBeanGetterPointcut, TEST_BEAN_GET_AGE, MyTestBean.class, null));
Pointcut intersection = Pointcuts.intersection(allClassGetAgePointcut, myTestBeanGetterPointcut);
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, TestBean.class, null));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBean.class, null));
assertTrue(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBean.class, null));
// Matches subclass of MyTestBean
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBeanSubclass.class, null));
assertTrue(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBeanSubclass.class, null));
// Now intersection with MyTestBeanSubclass getters should eliminate MyTestBean target
intersection = Pointcuts.intersection(intersection, myTestBeanSubclassGetterPointcut);
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, TestBean.class, null));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBean.class, null));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBean.class, null));
// Still matches subclass of MyTestBean
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_NAME, MyTestBeanSubclass.class, null));
assertTrue(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, MyTestBeanSubclass.class, null));
// Now union with all TestBean methods
Pointcut union = Pointcuts.union(intersection, allTestBeanMethodsPointcut);
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_NAME, TestBean.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(union, TEST_BEAN_GET_NAME, MyTestBean.class, null));
assertFalse(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBean.class, null));
// Still matches subclass of MyTestBean
assertFalse(Pointcuts.matches(union, TEST_BEAN_GET_NAME, MyTestBeanSubclass.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_GET_AGE, MyTestBeanSubclass.class, null));
assertTrue(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
assertFalse(Pointcuts.matches(union, TEST_BEAN_ABSQUATULATE, MyTestBean.class, null));
}
/**
* The intersection of these two pointcuts leaves nothing.
*/
@Test
public void testSimpleIntersection() {
Pointcut intersection = Pointcuts.intersection(allClassGetterPointcut, allClassSetterPointcut);
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_SET_AGE, TestBean.class, new Object[] { new Integer(6)}));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_GET_AGE, TestBean.class, null));
assertFalse(Pointcuts.matches(intersection, TEST_BEAN_ABSQUATULATE, TestBean.class, null));
}
}

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<!-- Simple target -->
<bean id="test" class="test.beans.TestBean">
<property name="name"><value>custom</value></property>
<property name="age"><value>666</value></property>
</bean>
<bean id="nopInterceptor" class="test.aop.SerializableNopInterceptor"/>
<bean id="settersAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice"><ref local="nopInterceptor"/></property>
<property name="pattern">
<value>
.*set.*
</value>
</property>
</bean>
<bean id="settersAdvised" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>test.beans.ITestBean</value></property>
<property name="target"><ref local="test"/></property>
<property name="interceptorNames"><value>settersAdvisor</value></property>
</bean>
<bean id="serializableSettersAdvised" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>test.beans.Person</value></property>
<property name="target">
<bean class="test.beans.SerializablePerson">
<property name="name"><value>serializableSettersAdvised</value></property>
</bean>
</property>
<property name="interceptorNames"><value>settersAdvisor</value></property>
</bean>
<!-- Illustrates use of multiple patterns -->
<bean id="settersAndAbsquatulateAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice"><ref local="nopInterceptor"/></property>
<property name="patterns">
<list>
<value>.*get.*</value>
<value>.*absquatulate</value>
</list>
</property>
</bean>
<bean id="settersAndAbsquatulateAdvised" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>test.beans.ITestBean</value></property>
<!-- Force CGLIB so we can cast to TestBean -->
<property name="proxyTargetClass"><value>true</value></property>
<property name="target"><ref local="test"/></property>
<property name="interceptorNames"><value>settersAndAbsquatulateAdvisor</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,119 @@
/*
* 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.support;
import static org.junit.Assert.assertEquals;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import test.aop.NopInterceptor;
import test.aop.SerializableNopInterceptor;
import test.beans.ITestBean;
import test.beans.Person;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class RegexpMethodPointcutAdvisorIntegrationTests {
private static final Resource CONTEXT =
qualifiedResource(RegexpMethodPointcutAdvisorIntegrationTests.class, "context.xml");
@Test
public void testSinglePattern() throws Throwable {
BeanFactory bf = new XmlBeanFactory(CONTEXT);
ITestBean advised = (ITestBean) bf.getBean("settersAdvised");
// Interceptor behind regexp advisor
NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor");
assertEquals(0, nop.getCount());
int newAge = 12;
// Not advised
advised.exceptional(null);
assertEquals(0, nop.getCount());
advised.setAge(newAge);
assertEquals(newAge, advised.getAge());
// Only setter fired
assertEquals(1, nop.getCount());
}
@Test
public void testMultiplePatterns() throws Throwable {
BeanFactory bf = new XmlBeanFactory(CONTEXT);
// This is a CGLIB proxy, so we can proxy it to the target class
TestBean advised = (TestBean) bf.getBean("settersAndAbsquatulateAdvised");
// Interceptor behind regexp advisor
NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor");
assertEquals(0, nop.getCount());
int newAge = 12;
// Not advised
advised.exceptional(null);
assertEquals(0, nop.getCount());
// This is proxied
advised.absquatulate();
assertEquals(1, nop.getCount());
advised.setAge(newAge);
assertEquals(newAge, advised.getAge());
// Only setter fired
assertEquals(2, nop.getCount());
}
@Test
public void testSerialization() throws Throwable {
BeanFactory bf = new XmlBeanFactory(CONTEXT);
// This is a CGLIB proxy, so we can proxy it to the target class
Person p = (Person) bf.getBean("serializableSettersAdvised");
// Interceptor behind regexp advisor
NopInterceptor nop = (NopInterceptor) bf.getBean("nopInterceptor");
assertEquals(0, nop.getCount());
int newAge = 12;
// Not advised
assertEquals(0, p.getAge());
assertEquals(0, nop.getCount());
// This is proxied
p.setAge(newAge);
assertEquals(1, nop.getCount());
p.setAge(newAge);
assertEquals(newAge, p.getAge());
// Only setter fired
assertEquals(2, nop.getCount());
// Serialize and continue...
p = (Person) SerializationTestUtils.serializeAndDeserialize(p);
assertEquals(newAge, p.getAge());
// Remembers count, but we need to get a new reference to nop...
nop = (SerializableNopInterceptor) ((Advised) p).getAdvisors()[0].getAdvice();
assertEquals(2, nop.getCount());
assertEquals("serializableSettersAdvised", p.getName());
p.setAge(newAge + 1);
assertEquals(3, nop.getCount());
assertEquals(newAge + 1, p.getAge());
}
}

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="testBeanTarget" class="test.beans.TestBean" scope="prototype"/>
<bean id="targetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName" value="testBeanTarget"/>
</bean>
<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource" ref="targetSource"/>
</bean>
</beans>

View File

@@ -0,0 +1,49 @@
/*
* 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.target;
import static org.junit.Assert.assertTrue;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.Resource;
import test.beans.ITestBean;
/**
* @author Rob Harrop
* @author Chris Beams
* @since 2.0
*/
public final class CommonsPoolTargetSourceProxyTests {
private static final Resource CONTEXT =
qualifiedResource(CommonsPoolTargetSourceProxyTests.class, "context.xml");
@Test
public void testProxy() throws Exception {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(CONTEXT);
beanFactory.preInstantiateSingletons();
ITestBean bean = (ITestBean)beanFactory.getBean("testBean");
assertTrue(AopUtils.isAopProxy(bean));
}
}

View File

@@ -0,0 +1,27 @@
<?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="target1" class="test.beans.SideEffectBean">
<property name="count"><value>10</value></property>
</bean>
<bean id="target2" class="test.beans.SideEffectBean" scope="singleton">
<property name="count"><value>20</value></property>
</bean>
<!--
Hot swappable target source. Note the use of Type 3 IoC.
-->
<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg><ref local="target1"/></constructor-arg>
</bean>
<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="swapper"/></property>
</bean>
</beans>

View File

@@ -0,0 +1,167 @@
/*
* 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.target;
import static org.junit.Assert.*;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import test.aop.SerializableNopInterceptor;
import test.beans.Person;
import test.beans.SerializablePerson;
import test.beans.SideEffectBean;
import test.util.SerializationTestUtils;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class HotSwappableTargetSourceTests {
private static final Resource CONTEXT = qualifiedResource(HotSwappableTargetSourceTests.class, "context.xml");
/** 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(CONTEXT);
}
/**
* We must simulate container shutdown, which should clear threads.
*/
@After
public void tearDown() {
// Will call pool.close()
this.beanFactory.destroySingletons();
}
/**
* Check it works like a normal invoker
*
*/
@Test
public void testBasicFunctionality() {
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
assertEquals(INITIAL_COUNT, proxied.getCount() );
proxied.doWork();
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
proxied = (SideEffectBean) beanFactory.getBean("swappable");
proxied.doWork();
assertEquals(INITIAL_COUNT + 2, proxied.getCount() );
}
@Test
public void testValidSwaps() {
SideEffectBean target1 = (SideEffectBean) beanFactory.getBean("target1");
SideEffectBean target2 = (SideEffectBean) beanFactory.getBean("target2");
SideEffectBean proxied = (SideEffectBean) beanFactory.getBean("swappable");
assertEquals(target1.getCount(), proxied.getCount() );
proxied.doWork();
assertEquals(INITIAL_COUNT + 1, proxied.getCount() );
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object old = swapper.swap(target2);
assertEquals("Correct old target was returned", target1, old);
// TODO should be able to make this assertion: need to fix target handling
// in AdvisedSupport
//assertEquals(target2, ((Advised) proxied).getTarget());
assertEquals(20, proxied.getCount());
proxied.doWork();
assertEquals(21, target2.getCount());
// Swap it back
swapper.swap(target1);
assertEquals(target1.getCount(), proxied.getCount());
}
/**
*
* @param invalid
* @return the message
*/
private IllegalArgumentException testRejectsSwapToInvalidValue(Object invalid) {
HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
IllegalArgumentException aopex = null;
try {
swapper.swap(invalid);
fail("Shouldn't be able to swap to invalid value [" + invalid + "]");
}
catch (IllegalArgumentException ex) {
// Ok
aopex = ex;
}
// It shouldn't be corrupted, it should still work
testBasicFunctionality();
return aopex;
}
@Test
public void testRejectsSwapToNull() {
IllegalArgumentException ex = testRejectsSwapToInvalidValue(null);
assertTrue(ex.getMessage().indexOf("null") != -1);
}
// TODO test reject swap to wrong interface or class?
// how to decide what's valid?
@Test
public void testSerialization() throws Exception {
SerializablePerson sp1 = new SerializablePerson();
sp1.setName("Tony");
SerializablePerson sp2 = new SerializablePerson();
sp1.setName("Gordon");
HotSwappableTargetSource hts = new HotSwappableTargetSource(sp1);
ProxyFactory pf = new ProxyFactory();
pf.addInterface(Person.class);
pf.setTargetSource(hts);
pf.addAdvisor(new DefaultPointcutAdvisor(new SerializableNopInterceptor()));
Person p = (Person) pf.getProxy();
assertEquals(sp1.getName(), p.getName());
hts.swap(sp2);
assertEquals(sp2.getName(), p.getName());
p = (Person) SerializationTestUtils.serializeAndDeserialize(p);
// We need to get a reference to the client-side targetsource
hts = (HotSwappableTargetSource) ((Advised) p).getTargetSource();
assertEquals(sp2.getName(), p.getName());
hts.swap(sp1);
assertEquals(sp1.getName(), p.getName());
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.target;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.ProxyFactory;
/**
* @author Rob Harrop
* @author Juergen Hoeller
* @author Chris Beams
*/
public final class LazyCreationTargetSourceTests {
@Test
public void testCreateLazy() {
TargetSource targetSource = new AbstractLazyCreationTargetSource() {
protected Object createObject() {
return new InitCountingBean();
}
public Class<?> getTargetClass() {
return InitCountingBean.class;
}
};
InitCountingBean proxy = (InitCountingBean) ProxyFactory.getProxy(targetSource);
assertEquals("Init count should be 0", 0, InitCountingBean.initCount);
assertEquals("Target class incorrect", InitCountingBean.class, targetSource.getTargetClass());
assertEquals("Init count should still be 0 after getTargetClass()", 0, InitCountingBean.initCount);
proxy.doSomething();
assertEquals("Init count should now be 1", 1, InitCountingBean.initCount);
proxy.doSomething();
assertEquals("Init count should still be 1", 1, InitCountingBean.initCount);
}
private static class InitCountingBean {
public static int initCount;
public InitCountingBean() {
if (InitCountingBean.class.equals(getClass())) {
// only increment when creating the actual target - not the proxy
initCount++;
}
}
public void doSomething() {
//no-op
}
}
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="target" class="test.beans.TestBean" lazy-init="true">
<property name="age"><value>10</value></property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSourceTests$CustomLazyInitTargetSource">
<property name="targetBeanName"><idref local="target"/></property>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="target1" class="org.springframework.beans.factory.config.SetFactoryBean" lazy-init="true">
<property name="sourceSet">
<set>
<value>10</value>
</set>
</property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="java.util.Set"/>
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName" value="target1"/>
</bean>
</property>
</bean>
<bean id="target2" class="org.springframework.beans.factory.config.SetFactoryBean" lazy-init="true">
<property name="sourceSet">
<set>
<value>20</value>
</set>
</property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="autodetectInterfaces" value="true"/>
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName" value="target2"/>
<property name="targetClass" value="java.util.Set"/>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
<beans>
<bean id="target" class="test.beans.TestBean" lazy-init="true">
<property name="age"><value>10</value></property>
</bean>
<!--
This will create a proxy that lazily fetches its target bean (with name "target").
-->
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<bean class="org.springframework.aop.target.LazyInitTargetSource">
<property name="targetBeanName"><idref local="target"/></property>
</bean>
</property>
</bean>
</beans>

View File

@@ -0,0 +1,90 @@
/*
* 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.target;
import static org.junit.Assert.*;
import static test.util.TestResourceUtils.qualifiedResource;
import java.util.Set;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import test.beans.ITestBean;
/**
* @author Juergen Hoeller
* @author Rob Harrop
* @author Chris Beams
* @since 07.01.2005
*/
public final class LazyInitTargetSourceTests {
private static final Class<?> CLASS = LazyInitTargetSourceTests.class;
private static final Resource SINGLETON_CONTEXT = qualifiedResource(CLASS, "singleton.xml");
private static final Resource CUSTOM_TARGET_CONTEXT = qualifiedResource(CLASS, "customTarget.xml");
private static final Resource FACTORY_BEAN_CONTEXT = qualifiedResource(CLASS, "factoryBean.xml");
@Test
public void testLazyInitSingletonTargetSource() {
XmlBeanFactory bf = new XmlBeanFactory(SINGLETON_CONTEXT);
bf.preInstantiateSingletons();
ITestBean tb = (ITestBean) bf.getBean("proxy");
assertFalse(bf.containsSingleton("target"));
assertEquals(10, tb.getAge());
assertTrue(bf.containsSingleton("target"));
}
@Test
public void testCustomLazyInitSingletonTargetSource() {
XmlBeanFactory bf = new XmlBeanFactory(CUSTOM_TARGET_CONTEXT);
bf.preInstantiateSingletons();
ITestBean tb = (ITestBean) bf.getBean("proxy");
assertFalse(bf.containsSingleton("target"));
assertEquals("Rob Harrop", tb.getName());
assertTrue(bf.containsSingleton("target"));
}
@Test
public void testLazyInitFactoryBeanTargetSource() {
XmlBeanFactory bf = new XmlBeanFactory(FACTORY_BEAN_CONTEXT);
bf.preInstantiateSingletons();
Set<?> set1 = (Set<?>) bf.getBean("proxy1");
assertFalse(bf.containsSingleton("target1"));
assertTrue(set1.contains("10"));
assertTrue(bf.containsSingleton("target1"));
Set<?> set2 = (Set<?>) bf.getBean("proxy2");
assertFalse(bf.containsSingleton("target2"));
assertTrue(set2.contains("20"));
assertTrue(bf.containsSingleton("target2"));
}
public static class CustomLazyInitTargetSource extends LazyInitTargetSource {
protected void postProcessTargetObject(Object targetObject) {
((ITestBean) targetObject).setName("Rob Harrop");
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.target;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.aop.TargetSource;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import test.beans.SerializablePerson;
import test.beans.TestBean;
import test.util.SerializationTestUtils;
/**
* Unit tests relating to the abstract {@link AbstractPrototypeBasedTargetSource}
* and not subclasses.
*
* @author Rod Johnson
* @author Chris Beams
*/
public final class PrototypeBasedTargetSourceTests {
@Test
public void testSerializability() throws Exception {
MutablePropertyValues tsPvs = new MutablePropertyValues();
tsPvs.add("targetBeanName", "person");
RootBeanDefinition tsBd = new RootBeanDefinition(TestTargetSource.class, tsPvs);
MutablePropertyValues pvs = new MutablePropertyValues();
RootBeanDefinition bd = new RootBeanDefinition(SerializablePerson.class, pvs);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.registerBeanDefinition("ts", tsBd);
bf.registerBeanDefinition("person", bd);
TestTargetSource cpts = (TestTargetSource) bf.getBean("ts");
TargetSource serialized = (TargetSource) SerializationTestUtils.serializeAndDeserialize(cpts);
assertTrue("Changed to SingletonTargetSource on deserialization",
serialized instanceof SingletonTargetSource);
SingletonTargetSource sts = (SingletonTargetSource) serialized;
assertNotNull(sts.getTarget());
}
private static class TestTargetSource extends AbstractPrototypeBasedTargetSource {
/**
* Nonserializable test field to check that subclass
* state can't prevent serialization from working
*/
private TestBean thisFieldIsNotSerializable = new TestBean();
public Object getTarget() throws Exception {
return newPrototypeInstance();
}
public void releaseTarget(Object target) throws Exception {
// Do nothing
}
}
}

View File

@@ -0,0 +1,33 @@
<?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="test.beans.SideEffectBean">
<property name="count"><value>10</value></property>
</bean>
<bean id="prototypeTest" class="test.beans.SideEffectBean" scope="prototype">
<property name="count"><value>10</value></property>
</bean>
<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
<property name="targetBeanName"><value>prototypeTest</value></property>
</bean>
<bean id="debugInterceptor" class="test.aop.NopInterceptor" />
<bean id="singleton" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,test</value></property>
</bean>
<!--
This will create a bean that creates a new target on each invocation.
-->
<bean id="prototype" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="prototypeTargetSource"/></property>
<property name="interceptorNames"><value>debugInterceptor</value></property>
</bean>
</beans>

View File

@@ -0,0 +1,68 @@
/*
* 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.target;
import static org.junit.Assert.assertEquals;
import static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import test.beans.SideEffectBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public final class PrototypeTargetSourceTests {
private static final Resource CONTEXT = qualifiedResource(PrototypeTargetSourceTests.class, "context.xml");
/** Initial count value set in bean factory XML */
private static final int INITIAL_COUNT = 10;
private BeanFactory beanFactory;
@Before
public void setUp() throws Exception {
this.beanFactory = new XmlBeanFactory(CONTEXT);
}
/**
* Test that multiple invocations of the prototype bean will result
* in no change to visible state, as a new instance is used.
* With the singleton, there will be change.
*/
@Test
public void testPrototypeAndSingletonBehaveDifferently() {
SideEffectBean singleton = (SideEffectBean) beanFactory.getBean("singleton");
assertEquals(INITIAL_COUNT, singleton.getCount() );
singleton.doWork();
assertEquals(INITIAL_COUNT + 1, singleton.getCount() );
SideEffectBean prototype = (SideEffectBean) beanFactory.getBean("prototype");
assertEquals(INITIAL_COUNT, prototype.getCount() );
prototype.doWork();
assertEquals(INITIAL_COUNT, prototype.getCount() );
}
}

View File

@@ -0,0 +1,55 @@
<?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="threadLocalTs" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName"><value>prototypeTest</value></property>
</bean>
<bean id="debugInterceptor" class="test.aop.NopInterceptor" />
<!--
We want to invoke the getStatsMixin method on our ThreadLocal invoker
-->
<bean id="statsAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="threadLocalTs" /></property>
<property name="targetMethod"><value>getStatsMixin</value></property>
</bean>
<!--
This will create a bean for each thread ("apartment")
-->
<bean id="apartment" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames"><value>debugInterceptor,statsAdvisor</value></property>
<property name="targetSource"><ref local="threadLocalTs"/></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>
<!-- ================ Definitions for second ThreadLocalTargetSource ====== -->
<bean id="test" class="test.beans.TestBean" scope="prototype">
<property name="name"><value>Rod</value></property>
<property name="spouse"><ref local="wife"/></property>
</bean>
<bean id="wife" class="test.beans.TestBean">
<property name="name"><value>Kerry</value></property>
</bean>
<bean id="threadLocalTs2" class="org.springframework.aop.target.ThreadLocalTargetSource">
<property name="targetBeanName"><value>test</value></property>
</bean>
<bean id="threadLocal2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource"><ref local="threadLocalTs2"/></property>
</bean>
</beans>

View File

@@ -0,0 +1,160 @@
/*
* 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 static test.util.TestResourceUtils.qualifiedResource;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.Resource;
import test.beans.ITestBean;
import test.beans.SideEffectBean;
/**
* @author Rod Johnson
* @author Chris Beams
*/
public class ThreadLocalTargetSourceTests {
private static final Resource CONTEXT = qualifiedResource(ThreadLocalTargetSourceTests.class, "context.xml");
/** 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(CONTEXT);
}
/**
* We must simulate container shutdown, which should clear threads.
*/
protected void tearDown() {
this.beanFactory.destroySingletons();
}
/**
* Check we can use two different ThreadLocalTargetSources
* managing objects of different types without them interfering
* with one another.
*/
@Test
public void testUseDifferentManagedInstancesInSameThread() {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
apartment.doWork();
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
ITestBean test = (ITestBean) beanFactory.getBean("threadLocal2");
assertEquals("Rod", test.getName());
assertEquals("Kerry", test.getSpouse().getName());
}
@Test
public void testReuseInSameThread() {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
apartment.doWork();
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT + 1, apartment.getCount() );
}
/**
* Relies on introduction.
*/
@Test
public void testCanGetStatsViaMixin() {
ThreadLocalTargetSourceStats stats = (ThreadLocalTargetSourceStats) beanFactory.getBean("apartment");
// +1 because creating target for stats call counts
assertEquals(1, stats.getInvocationCount());
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
apartment.doWork();
// +1 again
assertEquals(3, stats.getInvocationCount());
// + 1 for states call!
assertEquals(3, stats.getHitCount());
apartment.doWork();
assertEquals(6, stats.getInvocationCount());
assertEquals(6, stats.getHitCount());
// Only one thread so only one object can have been bound
assertEquals(1, stats.getObjectCount());
}
@Test
public void testNewThreadHasOwnInstance() throws InterruptedException {
SideEffectBean apartment = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, apartment.getCount() );
apartment.doWork();
apartment.doWork();
apartment.doWork();
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
class Runner implements Runnable {
public SideEffectBean mine;
public void run() {
this.mine = (SideEffectBean) beanFactory.getBean("apartment");
assertEquals(INITIAL_COUNT, mine.getCount() );
mine.doWork();
assertEquals(INITIAL_COUNT + 1, mine.getCount() );
}
}
Runner r = new Runner();
Thread t = new Thread(r);
t.start();
t.join();
assertNotNull(r);
// Check it didn't affect the other thread's copy
assertEquals(INITIAL_COUNT + 3, apartment.getCount() );
// When we use other thread's copy in this thread
// it should behave like ours
assertEquals(INITIAL_COUNT + 3, r.mine.getCount() );
// Bound to two threads
assertEquals(2, ((ThreadLocalTargetSourceStats) apartment).getObjectCount());
}
/**
* Test for SPR-1442. Destroyed target should re-associated with thread and not throw NPE
*/
@Test
public void testReuseDestroyedTarget() {
ThreadLocalTargetSource source = (ThreadLocalTargetSource)this.beanFactory.getBean("threadLocalTs");
// try first time
source.getTarget();
source.destroy();
// try second time
try {
source.getTarget();
} catch(NullPointerException ex) {
fail("Should not throw NPE");
}
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.target.dynamic;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* @author Rob Harrop
* @author Chris Beams
*/
public final class RefreshableTargetSourceTests {
/**
* Test what happens when checking for refresh but not refreshing object.
*/
@Test
public void testRefreshCheckWithNonRefresh() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource();
ts.setRefreshCheckDelay(0);
Object a = ts.getTarget();
Thread.sleep(1);
Object b = ts.getTarget();
assertEquals("Should be one call to freshTarget to get initial target", 1, ts.getCallCount());
assertSame("Returned objects should be the same - no refresh should occur", a, b);
}
/**
* Test what happens when checking for refresh and refresh occurs.
*/
@Test
public void testRefreshCheckWithRefresh() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(0);
Object a = ts.getTarget();
Thread.sleep(100);
Object b = ts.getTarget();
assertEquals("Should have called freshTarget twice", 2, ts.getCallCount());
assertNotSame("Should be different objects", a, b);
}
/**
* Test what happens when no refresh occurs.
*/
@Test
public void testWithNoRefreshCheck() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(-1);
Object a = ts.getTarget();
Object b = ts.getTarget();
assertEquals("Refresh target should only be called once", 1, ts.getCallCount());
assertSame("Objects should be the same - refresh check delay not elapsed", a, b);
}
@Test
public void testRefreshOverTime() throws Exception {
CountingRefreshableTargetSource ts = new CountingRefreshableTargetSource(true);
ts.setRefreshCheckDelay(100);
Object a = ts.getTarget();
Object b = ts.getTarget();
assertEquals("Objects should be same", a, b);
Thread.sleep(50);
Object c = ts.getTarget();
assertEquals("A and C should be same", a, c);
Thread.sleep(60);
Object d = ts.getTarget();
assertNotNull("D should not be null", d);
assertFalse("A and D should not be equal", a.equals(d));
Object e = ts.getTarget();
assertEquals("D and E should be equal", d, e);
Thread.sleep(110);
Object f = ts.getTarget();
assertFalse("E and F should be different", e.equals(f));
}
private static class CountingRefreshableTargetSource extends AbstractRefreshableTargetSource {
private int callCount;
private boolean requiresRefresh;
public CountingRefreshableTargetSource() {
}
public CountingRefreshableTargetSource(boolean requiresRefresh) {
this.requiresRefresh = requiresRefresh;
}
protected Object freshTarget() {
this.callCount++;
return new Object();
}
public int getCallCount() {
return this.callCount;
}
protected boolean requiresRefresh() {
return this.requiresRefresh;
}
}
}