diff options
Diffstat (limited to 'spring-aop/src')
48 files changed, 1233 insertions, 98 deletions
diff --git a/spring-aop/src/main/java/org/aopalliance/aop/Advice.java b/spring-aop/src/main/java/org/aopalliance/aop/Advice.java new file mode 100644 index 00000000..6dcbc4af --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/aop/Advice.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2016 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.aopalliance.aop; + +/** + * Tag interface for Advice. Implementations can be any type + * of advice, such as Interceptors. + * + * @author Rod Johnson + * @version $Id: Advice.java,v 1.1 2004/03/19 17:02:16 johnsonr Exp $ + */ +public interface Advice { + +} diff --git a/spring-aop/src/main/java/org/aopalliance/aop/AspectException.java b/spring-aop/src/main/java/org/aopalliance/aop/AspectException.java new file mode 100644 index 00000000..c634d51a --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/aop/AspectException.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2016 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.aopalliance.aop; + +/** + * Superclass for all AOP infrastructure exceptions. + * Unchecked, as such exceptions are fatal and end user + * code shouldn't be forced to catch them. + * + * @author Rod Johnson + * @author Bob Lee + * @author Juergen Hoeller + */ +@SuppressWarnings("serial") +public class AspectException extends RuntimeException { + + /** + * Constructor for AspectException. + * @param message the exception message + */ + public AspectException(String message) { + super(message); + } + + /** + * Constructor for AspectException. + * @param message the exception message + * @param cause the root cause, if any + */ + public AspectException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/ConstructorInterceptor.java b/spring-aop/src/main/java/org/aopalliance/intercept/ConstructorInterceptor.java new file mode 100644 index 00000000..7e0ac706 --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/ConstructorInterceptor.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +/** + * Intercepts the construction of a new object. + * + * <p>The user should implement the {@link + * #construct(ConstructorInvocation)} method to modify the original + * behavior. E.g. the following class implements a singleton + * interceptor (allows only one unique instance for the intercepted + * class): + * + * <pre class=code> + * class DebuggingInterceptor implements ConstructorInterceptor { + * Object instance=null; + * + * Object construct(ConstructorInvocation i) throws Throwable { + * if(instance==null) { + * return instance=i.proceed(); + * } else { + * throw new Exception("singleton does not allow multiple instance"); + * } + * } + * } + * </pre> + * + * @author Rod Johnson + */ +public interface ConstructorInterceptor extends Interceptor { + + /** + * Implement this method to perform extra treatments before and + * after the construction of a new object. Polite implementations + * would certainly like to invoke {@link Joinpoint#proceed()}. + * @param invocation the construction joinpoint + * @return the newly created object, which is also the result of + * the call to {@link Joinpoint#proceed()}; might be replaced by + * the interceptor + * @throws Throwable if the interceptors or the target object + * throws an exception + */ + Object construct(ConstructorInvocation invocation) throws Throwable; + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/ConstructorInvocation.java b/spring-aop/src/main/java/org/aopalliance/intercept/ConstructorInvocation.java new file mode 100644 index 00000000..a453ac32 --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/ConstructorInvocation.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +import java.lang.reflect.Constructor; + +/** + * Description of an invocation to a constuctor, given to an + * interceptor upon constructor-call. + * + * <p>A constructor invocation is a joinpoint and can be intercepted + * by a constructor interceptor. + * + * @author Rod Johnson + * @see ConstructorInterceptor + */ +public interface ConstructorInvocation extends Invocation { + + /** + * Get the constructor being called. + * <p>This method is a friendly implementation of the + * {@link Joinpoint#getStaticPart()} method (same result). + * @return the constructor being called + */ + Constructor<?> getConstructor(); + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/Interceptor.java b/spring-aop/src/main/java/org/aopalliance/intercept/Interceptor.java new file mode 100644 index 00000000..eef409a7 --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/Interceptor.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +import org.aopalliance.aop.Advice; + +/** + * This interface represents a generic interceptor. + * + * <p>A generic interceptor can intercept runtime events that occur + * within a base program. Those events are materialized by (reified + * in) joinpoints. Runtime joinpoints can be invocations, field + * access, exceptions... + * + * <p>This interface is not used directly. Use the sub-interfaces + * to intercept specific events. For instance, the following class + * implements some specific interceptors in order to implement a + * debugger: + * + * <pre class=code> + * class DebuggingInterceptor implements MethodInterceptor, + * ConstructorInterceptor, FieldInterceptor { + * + * Object invoke(MethodInvocation i) throws Throwable { + * debug(i.getMethod(), i.getThis(), i.getArgs()); + * return i.proceed(); + * } + * + * Object construct(ConstructorInvocation i) throws Throwable { + * debug(i.getConstructor(), i.getThis(), i.getArgs()); + * return i.proceed(); + * } + * + * Object get(FieldAccess fa) throws Throwable { + * debug(fa.getField(), fa.getThis(), null); + * return fa.proceed(); + * } + * + * Object set(FieldAccess fa) throws Throwable { + * debug(fa.getField(), fa.getThis(), fa.getValueToSet()); + * return fa.proceed(); + * } + * + * void debug(AccessibleObject ao, Object this, Object value) { + * ... + * } + * } + * </pre> + * + * @author Rod Johnson + * @see Joinpoint + */ +public interface Interceptor extends Advice { + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/Invocation.java b/spring-aop/src/main/java/org/aopalliance/intercept/Invocation.java new file mode 100644 index 00000000..e785afb4 --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/Invocation.java @@ -0,0 +1,37 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +/** + * This interface represents an invocation in the program. + * + * <p>An invocation is a joinpoint and can be intercepted by an + * interceptor. + * + * @author Rod Johnson + */ +public interface Invocation extends Joinpoint { + + /** + * Get the arguments as an array object. + * It is possible to change element values within this + * array to change the arguments. + * @return the argument of the invocation + */ + Object[] getArguments(); + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java b/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java new file mode 100644 index 00000000..9328f333 --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/Joinpoint.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +import java.lang.reflect.AccessibleObject; + +/** + * This interface represents a generic runtime joinpoint (in the AOP + * terminology). + * + * <p>A runtime joinpoint is an <i>event</i> that occurs on a static + * joinpoint (i.e. a location in a the program). For instance, an + * invocation is the runtime joinpoint on a method (static joinpoint). + * The static part of a given joinpoint can be generically retrieved + * using the {@link #getStaticPart()} method. + * + * <p>In the context of an interception framework, a runtime joinpoint + * is then the reification of an access to an accessible object (a + * method, a constructor, a field), i.e. the static part of the + * joinpoint. It is passed to the interceptors that are installed on + * the static joinpoint. + * + * @author Rod Johnson + * @see Interceptor + */ +public interface Joinpoint { + + /** + * Proceed to the next interceptor in the chain. + * <p>The implementation and the semantics of this method depends + * on the actual joinpoint type (see the children interfaces). + * @return see the children interfaces' proceed definition + * @throws Throwable if the joinpoint throws an exception + */ + Object proceed() throws Throwable; + + /** + * Return the object that holds the current joinpoint's static part. + * <p>For instance, the target object for an invocation. + * @return the object (can be null if the accessible object is static) + */ + Object getThis(); + + /** + * Return the static part of this joinpoint. + * <p>The static part is an accessible object on which a chain of + * interceptors are installed. + */ + AccessibleObject getStaticPart(); + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/MethodInterceptor.java b/spring-aop/src/main/java/org/aopalliance/intercept/MethodInterceptor.java new file mode 100644 index 00000000..c08fd744 --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/MethodInterceptor.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +/** + * Intercepts calls on an interface on its way to the target. These + * are nested "on top" of the target. + * + * <p>The user should implement the {@link #invoke(MethodInvocation)} + * method to modify the original behavior. E.g. the following class + * implements a tracing interceptor (traces all the calls on the + * intercepted method(s)): + * + * <pre class=code> + * class TracingInterceptor implements MethodInterceptor { + * Object invoke(MethodInvocation i) throws Throwable { + * System.out.println("method "+i.getMethod()+" is called on "+ + * i.getThis()+" with args "+i.getArguments()); + * Object ret=i.proceed(); + * System.out.println("method "+i.getMethod()+" returns "+ret); + * return ret; + * } + * } + * </pre> + * + * @author Rod Johnson + */ +public interface MethodInterceptor extends Interceptor { + + /** + * Implement this method to perform extra treatments before and + * after the invocation. Polite implementations would certainly + * like to invoke {@link Joinpoint#proceed()}. + * @param invocation the method invocation joinpoint + * @return the result of the call to {@link Joinpoint#proceed()}; + * might be intercepted by the interceptor + * @throws Throwable if the interceptors or the target object + * throws an exception + */ + Object invoke(MethodInvocation invocation) throws Throwable; + +} diff --git a/spring-aop/src/main/java/org/aopalliance/intercept/MethodInvocation.java b/spring-aop/src/main/java/org/aopalliance/intercept/MethodInvocation.java new file mode 100644 index 00000000..6314824d --- /dev/null +++ b/spring-aop/src/main/java/org/aopalliance/intercept/MethodInvocation.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2016 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.aopalliance.intercept; + +import java.lang.reflect.Method; + +/** + * Description of an invocation to a method, given to an interceptor + * upon method-call. + * + * <p>A method invocation is a joinpoint and can be intercepted by a + * method interceptor. + * + * @author Rod Johnson + * @see MethodInterceptor + */ +public interface MethodInvocation extends Invocation { + + /** + * Get the method being called. + * <p>This method is a frienly implementation of the + * {@link Joinpoint#getStaticPart()} method (same result). + * @return the method being called + */ + Method getMethod(); + +} diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java index 71bd31d9..c7575168 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java @@ -16,6 +16,9 @@ package org.springframework.aop.aspectj; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; @@ -55,7 +58,8 @@ import org.springframework.util.StringUtils; * @author Ramnivas Laddad * @since 2.0 */ -public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation { +@SuppressWarnings("serial") +public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable { /** * Key used in ReflectiveMethodInvocation userAtributes map for the current joinpoint. @@ -86,10 +90,13 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence } - protected final Method aspectJAdviceMethod; + private final Class<?> declaringClass; - /** The total number of arguments we have to populate on advice dispatch */ - private final int adviceInvocationArgumentCount; + private final String methodName; + + private final Class<?>[] parameterTypes; + + protected transient Method aspectJAdviceMethod; private final AspectJExpressionPointcut pointcut; @@ -154,8 +161,10 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) { Assert.notNull(aspectJAdviceMethod, "Advice method must not be null"); + this.declaringClass = aspectJAdviceMethod.getDeclaringClass(); + this.methodName = aspectJAdviceMethod.getName(); + this.parameterTypes = aspectJAdviceMethod.getParameterTypes(); this.aspectJAdviceMethod = aspectJAdviceMethod; - this.adviceInvocationArgumentCount = this.aspectJAdviceMethod.getParameterTypes().length; this.pointcut = pointcut; this.aspectInstanceFactory = aspectInstanceFactory; } @@ -359,11 +368,11 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence */ public synchronized final void calculateArgumentBindings() { // The simple case... nothing to bind. - if (this.argumentsIntrospected || this.adviceInvocationArgumentCount == 0) { + if (this.argumentsIntrospected || this.parameterTypes.length == 0) { return; } - int numUnboundArgs = this.adviceInvocationArgumentCount; + int numUnboundArgs = this.parameterTypes.length; Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes(); if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) { numUnboundArgs--; @@ -462,7 +471,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence } // So we match in number... - int argumentIndexOffset = this.adviceInvocationArgumentCount - numArgumentsLeftToBind; + int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind; for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) { this.argumentBindings.put(this.argumentNames[i], i); } @@ -543,7 +552,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence calculateArgumentBindings(); // AMC start - Object[] adviceInvocationArgs = new Object[this.adviceInvocationArgumentCount]; + Object[] adviceInvocationArgs = new Object[this.parameterTypes.length]; int numBound = 0; if (this.joinPointArgumentIndex != -1) { @@ -580,8 +589,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence } } - if (numBound != this.adviceInvocationArgumentCount) { - throw new IllegalStateException("Required to bind " + this.adviceInvocationArgumentCount + + if (numBound != this.parameterTypes.length) { + throw new IllegalStateException("Required to bind " + this.parameterTypes.length + " arguments, but only bound " + numBound + " (JoinPointMatch " + (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)"); } @@ -664,6 +673,16 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence "aspect name '" + this.aspectName + "'"; } + private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { + inputStream.defaultReadObject(); + try { + this.aspectJAdviceMethod = this.declaringClass.getMethod(this.methodName, this.parameterTypes); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("Failed to find advice method on deserialization", ex); + } + } + /** * MethodMatcher that excludes the specified advice method. diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.java index a1900b89..3de3c25a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.java @@ -16,6 +16,7 @@ package org.springframework.aop.aspectj; +import java.io.Serializable; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; @@ -29,7 +30,9 @@ import org.springframework.aop.AfterAdvice; * @author Rod Johnson * @since 2.0 */ -public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice { +@SuppressWarnings("serial") +public class AspectJAfterAdvice extends AbstractAspectJAdvice + implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java index 3a852bdb..92f9cb4a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java @@ -16,6 +16,7 @@ package org.springframework.aop.aspectj; +import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Type; @@ -32,7 +33,9 @@ import org.springframework.util.TypeUtils; * @author Ramnivas Laddad * @since 2.0 */ -public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implements AfterReturningAdvice, AfterAdvice { +@SuppressWarnings("serial") +public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice + implements AfterReturningAdvice, AfterAdvice, Serializable { public AspectJAfterReturningAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.java index be74c7e4..fcf89a12 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.java @@ -16,6 +16,7 @@ package org.springframework.aop.aspectj; +import java.io.Serializable; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; @@ -29,7 +30,9 @@ import org.springframework.aop.AfterAdvice; * @author Rod Johnson * @since 2.0 */ -public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice { +@SuppressWarnings("serial") +public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice + implements MethodInterceptor, AfterAdvice, Serializable { public AspectJAfterThrowingAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.java index 3efefd27..66f3b03b 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.java @@ -16,6 +16,7 @@ package org.springframework.aop.aspectj; +import java.io.Serializable; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; @@ -33,7 +34,8 @@ import org.springframework.aop.ProxyMethodInvocation; * @author Juergen Hoeller * @since 2.0 */ -public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor { +@SuppressWarnings("serial") +public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable { public AspectJAroundAdvice( Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java index 65a5dce1..b1834566 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java @@ -16,6 +16,7 @@ package org.springframework.aop.aspectj; +import java.io.Serializable; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; @@ -27,7 +28,8 @@ import org.springframework.aop.MethodBeforeAdvice; * @author Adrian Colyer * @since 2.0 */ -public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice { +@SuppressWarnings("serial") +public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable { public AspectJMethodBeforeAdvice( Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java index 3272b922..47e46155 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/DeclareParentsAdvisor.java @@ -65,7 +65,7 @@ public class DeclareParentsAdvisor implements IntroductionAdvisor { /** * Private constructor to share common code between impl-based delegate and reference-based delegate - * (cannot use method such as init() to share common code, due the the use of final fields) + * (cannot use method such as init() to share common code, due the use of final fields) * @param interfaceType static field defining the introduction * @param typePattern type pattern the introduction is restricted to * @param implementationClass implementation class diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/SimpleAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/SimpleAspectInstanceFactory.java index f1275dae..5d413bd6 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/SimpleAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/SimpleAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 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. @@ -55,10 +55,12 @@ public class SimpleAspectInstanceFactory implements AspectInstanceFactory { return this.aspectClass.newInstance(); } catch (InstantiationException ex) { - throw new AopConfigException("Unable to instantiate aspect class [" + this.aspectClass.getName() + "]", ex); + throw new AopConfigException( + "Unable to instantiate aspect class: " + this.aspectClass.getName(), ex); } catch (IllegalAccessException ex) { - throw new AopConfigException("Cannot access element class [" + this.aspectClass.getName() + "]", ex); + throw new AopConfigException( + "Could not access aspect constructor: " + this.aspectClass.getName(), ex); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/SingletonAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/SingletonAspectInstanceFactory.java index 1e8f723e..d311f620 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/SingletonAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/SingletonAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -16,6 +16,8 @@ package org.springframework.aop.aspectj; +import java.io.Serializable; + import org.springframework.core.Ordered; import org.springframework.util.Assert; @@ -29,7 +31,8 @@ import org.springframework.util.Assert; * @since 2.0 * @see SimpleAspectInstanceFactory */ -public class SingletonAspectInstanceFactory implements AspectInstanceFactory { +@SuppressWarnings("serial") +public class SingletonAspectInstanceFactory implements AspectInstanceFactory, Serializable { private final Object aspectInstance; diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java index d20e5222..dd8823ec 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java @@ -16,6 +16,10 @@ package org.springframework.aop.aspectj.annotation; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; + import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.AjType; import org.aspectj.lang.reflect.AjTypeSystem; @@ -40,7 +44,8 @@ import org.springframework.aop.support.ComposablePointcut; * @since 2.0 * @see org.springframework.aop.aspectj.AspectJExpressionPointcut */ -public class AspectMetadata { +@SuppressWarnings("serial") +public class AspectMetadata implements Serializable { /** * The name of this aspect as defined to Spring (the bean name) - @@ -50,9 +55,16 @@ public class AspectMetadata { private final String aspectName; /** + * The aspect class, stored separately for re-resolution of the + * corresponding AjType on deserialization. + */ + private final Class<?> aspectClass; + + /** * AspectJ reflection information (AspectJ 5 / Java 5 specific). + * Re-resolved on deserialization since it isn't serializable itself. */ - private final AjType<?> ajType; + private transient AjType<?> ajType; /** * Spring AOP pointcut corresponding to the per clause of the @@ -86,6 +98,7 @@ public class AspectMetadata { if (ajType.getDeclarePrecedence().length > 0) { throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP"); } + this.aspectClass = ajType.getJavaClass(); this.ajType = ajType; switch (this.ajType.getPerClause().getKind()) { @@ -132,7 +145,7 @@ public class AspectMetadata { * Return the aspect class. */ public Class<?> getAspectClass() { - return this.ajType.getJavaClass(); + return this.aspectClass; } /** @@ -173,4 +186,10 @@ public class AspectMetadata { return (isPerThisOrPerTarget() || isPerTypeWithin()); } + + private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { + inputStream.defaultReadObject(); + this.ajType = AjTypeSystem.getAjType(this.aspectClass); + } + } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java index 713fb44f..f68fea56 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java @@ -16,6 +16,8 @@ package org.springframework.aop.aspectj.annotation; +import java.io.Serializable; + import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.Ordered; @@ -38,7 +40,8 @@ import org.springframework.util.ClassUtils; * @see org.springframework.beans.factory.BeanFactory * @see LazySingletonAspectInstanceFactoryDecorator */ -public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory { +@SuppressWarnings("serial") +public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable { private final BeanFactory beanFactory; @@ -92,6 +95,7 @@ public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInst return this.aspectMetadata; } + @Override public Object getAspectCreationMutex() { return (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex() : this); diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java index 750a1eb2..27d3a9ba 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java @@ -16,6 +16,9 @@ package org.springframework.aop.aspectj.annotation; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; import java.lang.reflect.Method; import org.aopalliance.aop.Advice; @@ -37,12 +40,19 @@ import org.springframework.aop.support.Pointcuts; * @author Juergen Hoeller * @since 2.0 */ +@SuppressWarnings("serial") class InstantiationModelAwarePointcutAdvisorImpl - implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation { + implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable { private final AspectJExpressionPointcut declaredPointcut; - private final Method aspectJAdviceMethod; + private final Class<?> declaringClass; + + private final String methodName; + + private final Class<?>[] parameterTypes; + + private transient Method aspectJAdviceMethod; private final AspectJAdvisorFactory aspectJAdvisorFactory; @@ -68,6 +78,9 @@ class InstantiationModelAwarePointcutAdvisorImpl MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { this.declaredPointcut = declaredPointcut; + this.declaringClass = aspectJAdviceMethod.getDeclaringClass(); + this.methodName = aspectJAdviceMethod.getName(); + this.parameterTypes = aspectJAdviceMethod.getParameterTypes(); this.aspectJAdviceMethod = aspectJAdviceMethod; this.aspectJAdvisorFactory = aspectJAdvisorFactory; this.aspectInstanceFactory = aspectInstanceFactory; @@ -227,6 +240,16 @@ class InstantiationModelAwarePointcutAdvisorImpl } + private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { + inputStream.defaultReadObject(); + try { + this.aspectJAdviceMethod = this.declaringClass.getMethod(this.methodName, this.parameterTypes); + } + catch (NoSuchMethodException ex) { + throw new IllegalStateException("Failed to find advice method on deserialization", ex); + } + } + /** * Pointcut implementation that changes its behaviour when the advice is instantiated. diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java index 78df5465..3e76fb47 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java @@ -16,6 +16,8 @@ package org.springframework.aop.aspectj.annotation; +import java.io.Serializable; + import org.springframework.util.Assert; /** @@ -25,7 +27,8 @@ import org.springframework.util.Assert; * @author Juergen Hoeller * @since 2.0 */ -public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwareAspectInstanceFactory { +@SuppressWarnings("serial") +public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwareAspectInstanceFactory, Serializable { private final MetadataAwareAspectInstanceFactory maaif; @@ -45,11 +48,7 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar @Override public Object getAspectInstance() { if (this.materialized == null) { - Object mutex = this; - if (this.maaif instanceof BeanFactoryAspectInstanceFactory) { - mutex = ((BeanFactoryAspectInstanceFactory) this.maaif).getAspectCreationMutex(); - } - synchronized (mutex) { + synchronized (this.maaif.getAspectCreationMutex()) { if (this.materialized == null) { this.materialized = this.maaif.getAspectInstance(); } @@ -73,6 +72,11 @@ public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwar } @Override + public Object getAspectCreationMutex() { + return this.maaif.getAspectCreationMutex(); + } + + @Override public int getOrder() { return this.maaif.getOrder(); } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/MetadataAwareAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/MetadataAwareAspectInstanceFactory.java index cb9a77d4..a001efbc 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/MetadataAwareAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/MetadataAwareAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2016 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. @@ -39,4 +39,11 @@ public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactor */ AspectMetadata getAspectMetadata(); + /** + * Return the best possible creation mutex for this factory. + * @return the mutex object (never {@code null}) + * @since 4.3 + */ + Object getAspectCreationMutex(); + } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/PrototypeAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/PrototypeAspectInstanceFactory.java index fc2978a9..e1e17155 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/PrototypeAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/PrototypeAspectInstanceFactory.java @@ -16,6 +16,8 @@ package org.springframework.aop.aspectj.annotation; +import java.io.Serializable; + import org.springframework.beans.factory.BeanFactory; /** @@ -32,7 +34,8 @@ import org.springframework.beans.factory.BeanFactory; * @see org.springframework.beans.factory.BeanFactory * @see LazySingletonAspectInstanceFactoryDecorator */ -public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory { +@SuppressWarnings("serial") +public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory implements Serializable { /** * Create a PrototypeAspectInstanceFactory. AspectJ will be called to diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java index 1a354930..ce139f71 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java @@ -16,6 +16,7 @@ package org.springframework.aop.aspectj.annotation; +import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -65,7 +66,8 @@ import org.springframework.util.comparator.InstanceComparator; * @author Phillip Webb * @since 2.0 */ -public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory { +@SuppressWarnings("serial") +public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable { private static final Comparator<Method> METHOD_COMPARATOR; diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java index 5b8113e7..2aa2431a 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SimpleMetadataAwareAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -51,6 +51,11 @@ public class SimpleMetadataAwareAspectInstanceFactory extends SimpleAspectInstan } @Override + public Object getAspectCreationMutex() { + return this; + } + + @Override protected int getOrderForAspectClass(Class<?> aspectClass) { return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE); } diff --git a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java index 0f83e6c2..15edfbbd 100644 --- a/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -16,6 +16,8 @@ package org.springframework.aop.aspectj.annotation; +import java.io.Serializable; + import org.springframework.aop.aspectj.SingletonAspectInstanceFactory; import org.springframework.core.Ordered; import org.springframework.core.annotation.OrderUtils; @@ -30,8 +32,9 @@ import org.springframework.core.annotation.OrderUtils; * @since 2.0 * @see SimpleMetadataAwareAspectInstanceFactory */ +@SuppressWarnings("serial") public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspectInstanceFactory - implements MetadataAwareAspectInstanceFactory { + implements MetadataAwareAspectInstanceFactory, Serializable { private final AspectMetadata metadata; @@ -53,6 +56,11 @@ public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspect } @Override + public Object getAspectCreationMutex() { + return this; + } + + @Override protected int getOrderForAspectClass(Class<?> aspectClass) { return OrderUtils.getOrder(aspectClass, Ordered.LOWEST_PRECEDENCE); } diff --git a/spring-aop/src/main/java/org/springframework/aop/config/AopConfigUtils.java b/spring-aop/src/main/java/org/springframework/aop/config/AopConfigUtils.java index d3f199c5..c2271500 100644 --- a/spring-aop/src/main/java/org/springframework/aop/config/AopConfigUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/config/AopConfigUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2016 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. @@ -97,7 +97,7 @@ public abstract class AopConfigUtils { } } - static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) { + public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("exposeProxy", Boolean.TRUE); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java index 9b3b3074..40940374 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -586,7 +586,7 @@ public class AdvisedSupport extends ProxyConfig implements Advised { * Simple wrapper class around a Method. Used as the key when * caching methods, for efficient equals and hashCode comparisons. */ - private static class MethodCacheKey { + private static final class MethodCacheKey implements Comparable<MethodCacheKey> { private final Method method; @@ -599,17 +599,28 @@ public class AdvisedSupport extends ProxyConfig implements Advised { @Override public boolean equals(Object other) { - if (other == this) { - return true; - } - MethodCacheKey otherKey = (MethodCacheKey) other; - return (this.method == otherKey.method); + return (this == other || (other instanceof MethodCacheKey && + this.method == ((MethodCacheKey) other).method)); } @Override public int hashCode() { return this.hashCode; } + + @Override + public String toString() { + return this.method.toString(); + } + + @Override + public int compareTo(MethodCacheKey other) { + int result = this.method.getName().compareTo(other.method.getName()); + if (result == 0) { + result = this.method.toString().compareTo(other.method.toString()); + } + return result; + } } } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java index 4e063d2b..15535a5e 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -26,6 +26,7 @@ import org.springframework.aop.TargetClassAware; import org.springframework.aop.TargetSource; import org.springframework.aop.support.AopUtils; import org.springframework.aop.target.SingletonTargetSource; +import org.springframework.core.DecoratingProxy; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -78,11 +79,29 @@ public abstract class AopProxyUtils { * <p>This will always add the {@link Advised} interface unless the AdvisedSupport's * {@link AdvisedSupport#setOpaque "opaque"} flag is on. Always adds the * {@link org.springframework.aop.SpringProxy} marker interface. + * @param advised the proxy config * @return the complete set of interfaces to proxy + * @see SpringProxy * @see Advised - * @see org.springframework.aop.SpringProxy */ public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) { + return completeProxiedInterfaces(advised, false); + } + + /** + * Determine the complete set of interfaces to proxy for the given AOP configuration. + * <p>This will always add the {@link Advised} interface unless the AdvisedSupport's + * {@link AdvisedSupport#setOpaque "opaque"} flag is on. Always adds the + * {@link org.springframework.aop.SpringProxy} marker interface. + * @param advised the proxy config + * @param decoratingProxy whether to expose the {@link DecoratingProxy} interface + * @return the complete set of interfaces to proxy + * @since 4.3 + * @see SpringProxy + * @see Advised + * @see DecoratingProxy + */ + static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) { Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces(); if (specifiedInterfaces.length == 0) { // No user-specified interfaces: check whether target class is an interface. @@ -99,6 +118,7 @@ public abstract class AopProxyUtils { } boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class); boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class); + boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class)); int nonUserIfcCount = 0; if (addSpringProxy) { nonUserIfcCount++; @@ -106,13 +126,22 @@ public abstract class AopProxyUtils { if (addAdvised) { nonUserIfcCount++; } + if (addDecoratingProxy) { + nonUserIfcCount++; + } Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount]; System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length); + int index = specifiedInterfaces.length; if (addSpringProxy) { - proxiedInterfaces[specifiedInterfaces.length] = SpringProxy.class; + proxiedInterfaces[index] = SpringProxy.class; + index++; } if (addAdvised) { - proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class; + proxiedInterfaces[index] = Advised.class; + index++; + } + if (addDecoratingProxy) { + proxiedInterfaces[index] = DecoratingProxy.class; } return proxiedInterfaces; } @@ -134,6 +163,9 @@ public abstract class AopProxyUtils { if (proxy instanceof Advised) { nonUserIfcCount++; } + if (proxy instanceof DecoratingProxy) { + nonUserIfcCount++; + } Class<?>[] userInterfaces = new Class<?>[proxyInterfaces.length - nonUserIfcCount]; System.arraycopy(proxyInterfaces, 0, userInterfaces, 0, userInterfaces.length); Assert.notEmpty(userInterfaces, "JDK proxy must implement one or more interfaces"); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java index e98c3085..1f90b0b5 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -30,6 +30,7 @@ import org.springframework.aop.AopInvocationException; import org.springframework.aop.RawTargetAccess; import org.springframework.aop.TargetSource; import org.springframework.aop.support.AopUtils; +import org.springframework.core.DecoratingProxy; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -116,7 +117,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } - Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised); + Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } @@ -164,11 +165,15 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa // The target does not implement the equals(Object) method itself. return equals(args[0]); } - if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { + else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // The target does not implement the hashCode() method itself. return hashCode(); } - if (!this.advised.opaque && method.getDeclaringClass().isInterface() && + else if (method.getDeclaringClass() == DecoratingProxy.class) { + // There is only getDecoratedClass() declared -> dispatch to proxy config. + return AopProxyUtils.ultimateTargetClass(this.advised); + } + else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations on ProxyConfig with the proxy config... return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args); diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java index af1cf603..a94c53b1 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ProxyProcessorSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2016 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. @@ -139,7 +139,8 @@ public class ProxyProcessorSupport extends ProxyConfig implements Ordered, BeanC * @return whether the given interface is an internal language interface */ protected boolean isInternalLanguageInterface(Class<?> ifc) { - return ifc.getName().equals("groovy.lang.GroovyObject"); + return (ifc.getName().equals("groovy.lang.GroovyObject") || + ifc.getName().endsWith(".cglib.proxy.Factory")); } } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java index eb476b4e..72934308 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -31,6 +31,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.Advisor; +import org.springframework.aop.Pointcut; import org.springframework.aop.TargetSource; import org.springframework.aop.framework.AopInfrastructureBean; import org.springframework.aop.framework.ProxyFactory; @@ -370,6 +371,7 @@ public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport */ protected boolean isInfrastructureClass(Class<?> beanClass) { boolean retVal = Advice.class.isAssignableFrom(beanClass) || + Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass); if (retVal && logger.isTraceEnabled()) { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AutoProxyUtils.java b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AutoProxyUtils.java index a771146f..af39672c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AutoProxyUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AutoProxyUtils.java @@ -35,7 +35,7 @@ public abstract class AutoProxyUtils { * to be proxied with its target class (in case of it getting proxied in the first * place). The value is {@code Boolean.TRUE} or {@code Boolean.FALSE}. * <p>Proxy factories can set this attribute if they built a target class proxy - * for a specific bean, and want to enforce that that bean can always be cast + * for a specific bean, and want to enforce that bean can always be cast * to its target class (even if AOP advices get applied through auto-proxying). * @see #shouldProxyTargetClass */ diff --git a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java index b1cdaa0f..28917436 100644 --- a/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/interceptor/AsyncExecutionAspectSupport.java @@ -235,7 +235,7 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware { if (logger.isInfoEnabled()) { logger.info("More than one TaskExecutor bean found within the context, and none is named " + "'taskExecutor'. Mark one of them as primary or name it 'taskExecutor' (possibly " + - "as an alias) in order to use it for async processing."); + "as an alias) in order to use it for async processing: " + ex.getBeanNamesFound()); } } } diff --git a/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java b/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java index 1ed373ca..4c8273ec 100644 --- a/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java +++ b/spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -18,6 +18,7 @@ package org.springframework.aop.support; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; import java.util.LinkedHashSet; import java.util.LinkedList; @@ -34,6 +35,7 @@ import org.springframework.aop.PointcutAdvisor; import org.springframework.aop.SpringProxy; import org.springframework.aop.TargetClassAware; import org.springframework.core.BridgeMethodResolver; +import org.springframework.core.MethodIntrospector; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -113,6 +115,30 @@ public abstract class AopUtils { } /** + * Select an invocable method on the target type: either the given method itself + * if actually exposed on the target type, or otherwise a corresponding method + * on one of the target type's interfaces or on the target type itself. + * @param method the method to check + * @param targetType the target type to search methods on (typically an AOP proxy) + * @return a corresponding invocable method on the target type + * @throws IllegalStateException if the given method is not invocable on the given + * target type (typically due to a proxy mismatch) + * @since 4.3 + * @see MethodIntrospector#selectInvocableMethod(Method, Class) + */ + public static Method selectInvocableMethod(Method method, Class<?> targetType) { + Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType); + if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) && + SpringProxy.class.isAssignableFrom(targetType)) { + throw new IllegalStateException(String.format( + "Need to invoke method '%s' found on proxy for target class '%s' but cannot " + + "be delegated to target bean. Switch its visibility to package or protected.", + method.getName(), method.getDeclaringClass().getSimpleName())); + } + return methodToUse; + } + + /** * Determine whether the given method is an "equals" method. * @see java.lang.Object#equals */ @@ -196,6 +222,11 @@ public abstract class AopUtils { } MethodMatcher methodMatcher = pc.getMethodMatcher(); + if (methodMatcher == MethodMatcher.TRUE) { + // No need to iterate the methods if we're matching any method anyway... + return true; + } + IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null; if (methodMatcher instanceof IntroductionAwareMethodMatcher) { introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher; @@ -204,7 +235,7 @@ public abstract class AopUtils { Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass)); classes.add(targetClass); for (Class<?> clazz : classes) { - Method[] methods = clazz.getMethods(); + Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz); for (Method method : methods) { if ((introductionAwareMethodMatcher != null && introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) || diff --git a/spring-aop/src/main/resources/META-INF/spring.schemas b/spring-aop/src/main/resources/META-INF/spring.schemas index 6f3dae37..fda92512 100644 --- a/spring-aop/src/main/resources/META-INF/spring.schemas +++ b/spring-aop/src/main/resources/META-INF/spring.schemas @@ -6,4 +6,5 @@ http\://www.springframework.org/schema/aop/spring-aop-3.2.xsd=org/springframewor http\://www.springframework.org/schema/aop/spring-aop-4.0.xsd=org/springframework/aop/config/spring-aop-4.0.xsd http\://www.springframework.org/schema/aop/spring-aop-4.1.xsd=org/springframework/aop/config/spring-aop-4.1.xsd http\://www.springframework.org/schema/aop/spring-aop-4.2.xsd=org/springframework/aop/config/spring-aop-4.2.xsd -http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.2.xsd +http\://www.springframework.org/schema/aop/spring-aop-4.3.xsd=org/springframework/aop/config/spring-aop-4.3.xsd +http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-4.3.xsd diff --git a/spring-aop/src/main/resources/org/springframework/aop/config/spring-aop-4.3.xsd b/spring-aop/src/main/resources/org/springframework/aop/config/spring-aop-4.3.xsd new file mode 100644 index 00000000..4dd43ca6 --- /dev/null +++ b/spring-aop/src/main/resources/org/springframework/aop/config/spring-aop-4.3.xsd @@ -0,0 +1,409 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> + +<xsd:schema xmlns="http://www.springframework.org/schema/aop" + xmlns:xsd="http://www.w3.org/2001/XMLSchema" + xmlns:tool="http://www.springframework.org/schema/tool" + targetNamespace="http://www.springframework.org/schema/aop" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> + + <xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"/> + <xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="http://www.springframework.org/schema/tool/spring-tool-4.3.xsd"/> + + <xsd:annotation> + <xsd:documentation><![CDATA[ + Defines the configuration elements for the Spring Framework's AOP support. + ]]></xsd:documentation> + </xsd:annotation> + + <xsd:element name="config"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A section (compartmentalization) of AOP-specific configuration (including + aspects, pointcuts, etc). + ]]></xsd:documentation> + </xsd:annotation> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="pointcut" type="pointcutType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A named pointcut definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="advisor" type="advisorType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation source="java:org.springframework.aop.Advisor"><![CDATA[ + A named advisor definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="aspect" type="aspectType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A named aspect definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Are class-based (CGLIB) proxies to be created? By default, standard + Java interface-based proxies are created. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="expose-proxy" type="xsd:boolean" default="false"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Indicate that the proxy should be exposed by the AOP framework as a + ThreadLocal for retrieval via the AopContext class. Off by default, + i.e. no guarantees that AopContext access will work. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="aspectj-autoproxy"> + <xsd:annotation> + <xsd:documentation source="java:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"><![CDATA[ + Enables the use of the @AspectJ style of Spring AOP. + + See org.springframework.context.annotation.EnableAspectJAutoProxy Javadoc + for information on code-based alternatives to this XML element. + ]]></xsd:documentation> + </xsd:annotation> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="include" type="includeType" minOccurs="0" maxOccurs="unbounded"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Indicates that only @AspectJ beans with names matched by the (regex) + pattern will be considered as defining aspects to use for Spring autoproxying. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:sequence> + <xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Are class-based (CGLIB) proxies to be created? By default, standard + Java interface-based proxies are created. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="expose-proxy" type="xsd:boolean" default="false"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Indicate that the proxy should be exposed by the AOP framework as a + ThreadLocal for retrieval via the AopContext class. Off by default, + i.e. no guarantees that AopContext access will work. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:element name="scoped-proxy"> + <xsd:complexType> + <xsd:annotation> + <xsd:documentation source="java:org.springframework.aop.scope.ScopedProxyFactoryBean"><![CDATA[ + Marks a bean definition as being a scoped proxy. + + A bean marked as such will be exposed via a proxy, with the 'real' + bean instance being retrieved from some other source (such as a + HttpSession) as and when required. + ]]></xsd:documentation> + </xsd:annotation> + <xsd:attribute name="proxy-target-class" type="xsd:boolean" default="true"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Are class-based (CGLIB) proxies to be created? This is the default; in order to + switch to standard Java interface-based proxies, turn this flag to "false". + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + </xsd:element> + + <xsd:complexType name="aspectType"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="pointcut" type="pointcutType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A named pointcut definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="declare-parents" type="declareParentsType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + Allows this aspect to introduce additional interfaces that the advised + object will transparently implement. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="before" type="basicAdviceType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A before advice definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="after" type="basicAdviceType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + An after advice definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="after-returning" type="afterReturningAdviceType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + An after-returning advice definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="after-throwing" type="afterThrowingAdviceType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + An after-throwing advice definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + <xsd:element name="around" type="basicAdviceType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + An around advice definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:element> + </xsd:choice> + <xsd:attribute name="id" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The unique identifier for an aspect. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="ref" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The name of the (backing) bean that encapsulates the aspect. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="order" type="xsd:token"> + <xsd:annotation> + <xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[ + Controls the ordering of the execution of this aspect when multiple + advice executes at a specific joinpoint. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="includeType"> + <xsd:attribute name="name" type="xsd:string"> + <xsd:annotation> + <xsd:documentation source="java:java.util.regex.Pattern"><![CDATA[ + The regular expression defining which beans are to be included in the + list of @AspectJ beans; beans with names matched by the pattern will + be included. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="pointcutType"> + <xsd:annotation> + <xsd:appinfo> + <tool:annotation> + <tool:exports type="org.springframework.aop.Pointcut"/> + </tool:annotation> + </xsd:appinfo> + </xsd:annotation> + <xsd:attribute name="id" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The unique identifier for a pointcut. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="expression" use="required" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The pointcut expression. + + For example : 'execution(* com.xyz.myapp.service.*.*(..))' + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="declareParentsType"> + <xsd:attribute name="types-matching" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation source="java:org.springframework.aop.aspectj.TypePatternClassFilter"><![CDATA[ + The AspectJ type expression that defines what types (classes) the + introduction is restricted to. + + An example would be 'org.springframework.beans.ITestBean+'. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="implement-interface" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation source="java:java.lang.Class"><![CDATA[ + The fully qualified name of the interface that will be introduced. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="default-impl" type="xsd:string"> + <xsd:annotation> + <xsd:documentation source="java:java.lang.Class"><![CDATA[ + The fully qualified name of the class that will be instantiated to serve + as the default implementation of the introduced interface. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="delegate-ref" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A reference to the bean that will serve + as the default implementation of the introduced interface. + ]]></xsd:documentation> + <xsd:appinfo> + <tool:annotation kind="ref"/> + </xsd:appinfo> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="basicAdviceType"> + <xsd:attribute name="pointcut" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The associated pointcut expression. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="pointcut-ref" type="pointcutRefType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The name of an associated pointcut definition. + ]]></xsd:documentation> + <xsd:appinfo> + <tool:annotation kind="ref"> + <tool:expected-type type="org.springframework.aop.Pointcut"/> + </tool:annotation> + </xsd:appinfo> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="method" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The name of the method that defines the logic of the advice. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="arg-names" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The comma-delimited list of advice method argument (parameter) names + that will be matched from pointcut parameters. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:complexType name="afterReturningAdviceType"> + <xsd:complexContent> + <xsd:extension base="basicAdviceType"> + <xsd:attribute name="returning" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The name of the method parameter to which the return value must + be passed. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="afterThrowingAdviceType"> + <xsd:complexContent> + <xsd:extension base="basicAdviceType"> + <xsd:attribute name="throwing" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + The name of the method parameter to which the thrown exception must + be passed. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="advisorType"> + <xsd:annotation> + <xsd:appinfo> + <tool:annotation> + <tool:exports type="org.springframework.aop.Advisor"/> + </tool:annotation> + </xsd:appinfo> + </xsd:annotation> + <xsd:attribute name="id" type="xsd:string"/> + <xsd:attribute name="advice-ref" type="xsd:string" use="required"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A reference to an advice bean. + ]]></xsd:documentation> + <xsd:appinfo> + <tool:annotation kind="ref"> + <tool:expected-type type="org.aopalliance.aop.Advice"/> + </tool:annotation> + </xsd:appinfo> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="pointcut" type="xsd:string"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A pointcut expression. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="pointcut-ref" type="pointcutRefType"> + <xsd:annotation> + <xsd:documentation><![CDATA[ + A reference to a pointcut definition. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + <xsd:attribute name="order" type="xsd:token"> + <xsd:annotation> + <xsd:documentation source="java:org.springframework.core.Ordered"><![CDATA[ + Controls the ordering of the execution of this advice when multiple + advice executes at a specific joinpoint. + ]]></xsd:documentation> + </xsd:annotation> + </xsd:attribute> + </xsd:complexType> + + <xsd:simpleType name="pointcutRefType"> + <xsd:annotation> + <xsd:appinfo> + <tool:annotation kind="ref"> + <tool:expected-type type="org.springframework.aop.Pointcut"/> + </tool:annotation> + </xsd:appinfo> + </xsd:annotation> + <xsd:union memberTypes="xsd:string"/> + </xsd:simpleType> + +</xsd:schema> diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java index 5167b5d7..3a365963 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/AspectJAdviceParameterNameDiscovererTests.java @@ -307,7 +307,8 @@ public class AspectJAdviceParameterNameDiscovererTests { try { discoverer.getParameterNames(m); fail("Expecting " + exceptionType.getName() + " with message '" + message + "'"); - } catch (RuntimeException expected) { + } + catch (RuntimeException expected) { assertEquals("Expecting exception of type " + exceptionType.getName(), exceptionType, expected.getClass()); assertEquals("Exception message does not match expected", message, expected.getMessage()); diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java index c4b1caac..f8c39e7b 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/MethodInvocationProceedingJoinPointTests.java @@ -215,7 +215,8 @@ public final class MethodInvocationProceedingJoinPointTests { itb.setSpouse(new TestBean()); try { itb.unreliableFileOperation(); - } catch (IOException ex) { + } + catch (IOException ex) { // we don't realy care... } } diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java index 22ef9db8..8a9d63a4 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/TrickyAspectJPointcutExpressionTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2002-2016 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.Documented; @@ -97,12 +113,14 @@ public class TrickyAspectJPointcutExpressionTests { try { bean.sayHello(); fail("Expected exception"); - } catch (TestException e) { - assertEquals(message, e.getMessage()); + } + catch (TestException ex) { + assertEquals(message, ex.getMessage()); } assertEquals(1, logAdvice.getCountThrows()); } + public static class SimpleThrowawayClassLoader extends OverridingClassLoader { /** @@ -115,15 +133,16 @@ public class TrickyAspectJPointcutExpressionTests { } + @SuppressWarnings("serial") public static class TestException extends RuntimeException { public TestException(String string) { super(string); } - } + @Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) @Documented @@ -131,18 +150,23 @@ public class TrickyAspectJPointcutExpressionTests { public static @interface Log { } + public static interface TestService { + public String sayHello(); } + @Log public static class TestServiceImpl implements TestService { + @Override public String sayHello() { throw new TestException("TestServiceImpl"); } } + public class LogUserAdvice implements MethodBeforeAdvice, ThrowsAdvice { private int countBefore = 0; @@ -154,9 +178,9 @@ public class TrickyAspectJPointcutExpressionTests { countBefore++; } - public void afterThrowing(Exception e) throws Throwable { + public void afterThrowing(Exception ex) throws Throwable { countThrows++; - throw e; + throw ex; } public int getCountBefore() { @@ -171,7 +195,6 @@ public class TrickyAspectJPointcutExpressionTests { countThrows = 0; countBefore = 0; } - } } diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java index 3f34ff59..554be1ae 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AbstractAspectJAdvisorFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * Copyright 2002-2016 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. @@ -694,6 +694,11 @@ public abstract class AbstractAspectJAdvisorFactoryTests { } @Override + public Object getAspectCreationMutex() { + return this; + } + + @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } diff --git a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java index 4113f169..0c4304c9 100644 --- a/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java @@ -16,13 +16,13 @@ package org.springframework.aop.aspectj.annotation; +import java.io.Serializable; import java.util.Arrays; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.junit.Ignore; import org.junit.Test; import test.aop.PerThisAspect; @@ -80,7 +80,18 @@ public class AspectProxyFactoryTests { } @Test - @Ignore // InstantiationModelAwarePointcutAdvisorImpl not serializable yet + @SuppressWarnings("unchecked") + public void testSerializable() throws Exception { + AspectJProxyFactory proxyFactory = new AspectJProxyFactory(new TestBean()); + proxyFactory.addAspect(LoggingAspectOnVarargs.class); + ITestBean proxy = proxyFactory.getProxy(); + assertTrue(proxy.doWithVarargs(MyEnum.A, MyOtherEnum.C)); + ITestBean tb = (ITestBean) SerializationTestUtils.serializeAndDeserialize(proxy); + assertTrue(tb.doWithVarargs(MyEnum.A, MyOtherEnum.C)); + } + + @Test + @SuppressWarnings("unchecked") public void testWithInstance() throws Exception { MultiplyReturnValue aspect = new MultiplyReturnValue(); int multiple = 3; @@ -133,7 +144,8 @@ public class AspectProxyFactoryTests { } - public static class TestBean implements ITestBean { + @SuppressWarnings("serial") + public static class TestBean implements ITestBean, Serializable { private int age; @@ -171,7 +183,8 @@ public class AspectProxyFactoryTests { @Aspect - public static class LoggingAspectOnVarargs { + @SuppressWarnings("serial") + public static class LoggingAspectOnVarargs implements Serializable { @Around("execution(* doWithVarargs(*))") public Object doLog(ProceedingJoinPoint pjp) throws Throwable { @@ -193,11 +206,9 @@ public class AspectProxyFactoryTests { } -/** - * @author Rod Johnson - */ @Aspect -class MultiplyReturnValue { +@SuppressWarnings("serial") +class MultiplyReturnValue implements Serializable { private int multiple = 2; diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java index ad7ad9dc..42b12f66 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/AopProxyUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -16,8 +16,6 @@ package org.springframework.aop.framework; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.List; @@ -34,7 +32,7 @@ import static org.junit.Assert.*; * @author Rod Johnson * @author Chris Beams */ -public final class AopProxyUtilsTests { +public class AopProxyUtilsTests { @Test public void testCompleteProxiedInterfacesWorksWithNull() { @@ -125,15 +123,10 @@ public final class AopProxyUtilsTests { assertEquals(Comparable.class, userInterfaces[1]); } - @Test(expected=IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void testProxiedUserInterfacesWithNoInterface() { Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[0], - new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - return null; - } - }); + (proxy1, method, args) -> null); AopProxyUtils.proxiedUserInterfaces(proxy); } diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java index 7b509ba6..b01b9b80 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -16,6 +16,8 @@ package org.springframework.aop.framework; +import java.util.ArrayList; +import java.util.List; import javax.accessibility.Accessible; import javax.swing.JFrame; import javax.swing.RootPaneContainer; @@ -31,6 +33,8 @@ import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.aop.support.DelegatingIntroductionInterceptor; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.annotation.Order; import org.springframework.tests.TimeStamped; import org.springframework.tests.aop.advice.CountingBeforeAdvice; import org.springframework.tests.aop.interceptor.NopInterceptor; @@ -49,7 +53,7 @@ import static org.junit.Assert.*; * @author Chris Beams * @since 14.05.2003 */ -public final class ProxyFactoryTests { +public class ProxyFactoryTests { @Test public void testIndexOfMethods() { @@ -337,6 +341,34 @@ public final class ProxyFactoryTests { assertTrue(proxy instanceof Accessible); } + @Test + public void testInterfaceProxiesCanBeOrderedThroughAnnotations() { + Object proxy1 = new ProxyFactory(new A()).getProxy(); + Object proxy2 = new ProxyFactory(new B()).getProxy(); + List<Object> list = new ArrayList<Object>(2); + list.add(proxy1); + list.add(proxy2); + AnnotationAwareOrderComparator.sort(list); + assertSame(proxy2, list.get(0)); + assertSame(proxy1, list.get(1)); + } + + @Test + public void testTargetClassProxiesCanBeOrderedThroughAnnotations() { + ProxyFactory pf1 = new ProxyFactory(new A()); + pf1.setProxyTargetClass(true); + ProxyFactory pf2 = new ProxyFactory(new B()); + pf2.setProxyTargetClass(true); + Object proxy1 = pf1.getProxy(); + Object proxy2 = pf2.getProxy(); + List<Object> list = new ArrayList<Object>(2); + list.add(proxy1); + list.add(proxy2); + AnnotationAwareOrderComparator.sort(list); + assertSame(proxy2, list.get(0)); + assertSame(proxy1, list.get(1)); + } + @SuppressWarnings("serial") private static class TimestampIntroductionInterceptor extends DelegatingIntroductionInterceptor @@ -361,4 +393,22 @@ public final class ProxyFactoryTests { } } + + @Order(2) + public static class A implements Runnable { + + @Override + public void run() { + } + } + + + @Order(1) + public static class B implements Runnable{ + + @Override + public void run() { + } + } + } diff --git a/spring-aop/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java b/spring-aop/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java index 5096fe88..a8240839 100644 --- a/spring-aop/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/interceptor/DebugInterceptorTests.java @@ -61,7 +61,8 @@ public final class DebugInterceptorTests { try { interceptor.invoke(methodInvocation); fail("Must have propagated the IllegalArgumentException."); - } catch (IllegalArgumentException expected) { + } + catch (IllegalArgumentException expected) { } checkCallCountTotal(interceptor); diff --git a/spring-aop/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java b/spring-aop/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java index 5bdeb414..3b811b24 100644 --- a/spring-aop/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/interceptor/SimpleTraceInterceptorTests.java @@ -60,7 +60,8 @@ public final class SimpleTraceInterceptorTests { try { interceptor.invokeUnderTrace(mi, log); fail("Must have propagated the IllegalArgumentException."); - } catch (IllegalArgumentException expected) { + } + catch (IllegalArgumentException expected) { } verify(log).trace(anyString()); diff --git a/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java b/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java index e805401b..a7890cde 100644 --- a/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/target/ThreadLocalTargetSourceTests.java @@ -154,7 +154,8 @@ public class ThreadLocalTargetSourceTests { // try second time try { source.getTarget(); - } catch(NullPointerException ex) { + } + catch (NullPointerException ex) { fail("Should not throw NPE"); } } |