Browse Source

AOP proxies with annotation-based aspects are serializable now

Issue: SPR-6910
pull/912/merge
Juergen Hoeller 10 years ago
parent
commit
4adb7e2500
  1. 74
      spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java
  2. 8
      spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.java
  3. 7
      spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java
  4. 20
      spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.java
  5. 8
      spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.java
  6. 7
      spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java
  7. 7
      spring-aop/src/main/java/org/springframework/aop/aspectj/SingletonAspectInstanceFactory.java
  8. 43
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java
  9. 7
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java
  10. 55
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.java
  11. 7
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.java
  12. 11
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/PrototypeAspectInstanceFactory.java
  13. 6
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.java
  14. 7
      spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/SingletonMetadataAwareAspectInstanceFactory.java
  15. 16
      spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java
  16. 27
      spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java

74
spring-aop/src/main/java/org/springframework/aop/aspectj/AbstractAspectJAdvice.java

@ -16,6 +16,9 @@
package org.springframework.aop.aspectj; 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.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -55,7 +58,8 @@ import org.springframework.util.StringUtils;
* @author Ramnivas Laddad * @author Ramnivas Laddad
* @since 2.0 * @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. * 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 String methodName;
private final int adviceInvocationArgumentCount;
private final Class<?>[] parameterTypes;
protected transient Method aspectJAdviceMethod;
private final AspectJExpressionPointcut pointcut; private final AspectJExpressionPointcut pointcut;
@ -135,7 +142,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
*/ */
private int joinPointStaticPartArgumentIndex = -1; private int joinPointStaticPartArgumentIndex = -1;
private Map<String, Integer> argumentBindings = null; private Map<String, Integer> argumentBindings;
private boolean argumentsIntrospected = false; private boolean argumentsIntrospected = false;
@ -154,8 +161,10 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) { Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
Assert.notNull(aspectJAdviceMethod, "Advice method must not be null"); 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.aspectJAdviceMethod = aspectJAdviceMethod;
this.adviceInvocationArgumentCount = this.aspectJAdviceMethod.getParameterTypes().length;
this.pointcut = pointcut; this.pointcut = pointcut;
this.aspectInstanceFactory = aspectInstanceFactory; this.aspectInstanceFactory = aspectInstanceFactory;
} }
@ -250,17 +259,17 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
this.argumentNames[i] + "' that is not a valid Java identifier"); this.argumentNames[i] + "' that is not a valid Java identifier");
} }
} }
if (argumentNames != null) { if (this.argumentNames != null) {
if (aspectJAdviceMethod.getParameterTypes().length == argumentNames.length + 1) { if (this.aspectJAdviceMethod.getParameterTypes().length == this.argumentNames.length + 1) {
// May need to add implicit join point arg name... // May need to add implicit join point arg name...
Class<?> firstArgType = aspectJAdviceMethod.getParameterTypes()[0]; Class<?> firstArgType = this.aspectJAdviceMethod.getParameterTypes()[0];
if (firstArgType == JoinPoint.class || if (firstArgType == JoinPoint.class ||
firstArgType == ProceedingJoinPoint.class || firstArgType == ProceedingJoinPoint.class ||
firstArgType == JoinPoint.StaticPart.class) { firstArgType == JoinPoint.StaticPart.class) {
String[] oldNames = argumentNames; String[] oldNames = this.argumentNames;
argumentNames = new String[oldNames.length + 1]; this.argumentNames = new String[oldNames.length + 1];
argumentNames[0] = "THIS_JOIN_POINT"; this.argumentNames[0] = "THIS_JOIN_POINT";
System.arraycopy(oldNames, 0, argumentNames, 1, oldNames.length); System.arraycopy(oldNames, 0, this.argumentNames, 1, oldNames.length);
} }
} }
} }
@ -359,11 +368,11 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
*/ */
public synchronized final void calculateArgumentBindings() { public synchronized final void calculateArgumentBindings() {
// The simple case... nothing to bind. // The simple case... nothing to bind.
if (this.argumentsIntrospected || this.adviceInvocationArgumentCount == 0) { if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
return; return;
} }
int numUnboundArgs = this.adviceInvocationArgumentCount; int numUnboundArgs = this.parameterTypes.length;
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes(); Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) { if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
numUnboundArgs--; numUnboundArgs--;
@ -456,13 +465,13 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length; int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length;
if (this.argumentNames.length != numExpectedArgumentNames) { if (this.argumentNames.length != numExpectedArgumentNames) {
throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames +
+ " arguments to bind by name in advice, but actually found " + " arguments to bind by name in advice, but actually found " +
this.argumentNames.length + " arguments."); this.argumentNames.length + " arguments.");
} }
// So we match in number... // 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++) { for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
this.argumentBindings.put(this.argumentNames[i], i); this.argumentBindings.put(this.argumentNames[i], i);
} }
@ -471,8 +480,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
// specified, and find the discovered argument types. // specified, and find the discovered argument types.
if (this.returningName != null) { if (this.returningName != null) {
if (!this.argumentBindings.containsKey(this.returningName)) { if (!this.argumentBindings.containsKey(this.returningName)) {
throw new IllegalStateException("Returning argument name '" throw new IllegalStateException("Returning argument name '" + this.returningName +
+ this.returningName + "' was not bound in advice arguments"); "' was not bound in advice arguments");
} }
else { else {
Integer index = this.argumentBindings.get(this.returningName); Integer index = this.argumentBindings.get(this.returningName);
@ -482,8 +491,8 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
} }
if (this.throwingName != null) { if (this.throwingName != null) {
if (!this.argumentBindings.containsKey(this.throwingName)) { if (!this.argumentBindings.containsKey(this.throwingName)) {
throw new IllegalStateException("Throwing argument name '" throw new IllegalStateException("Throwing argument name '" + this.throwingName +
+ this.throwingName + "' was not bound in advice arguments"); "' was not bound in advice arguments");
} }
else { else {
Integer index = this.argumentBindings.get(this.throwingName); Integer index = this.argumentBindings.get(this.throwingName);
@ -543,7 +552,7 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
calculateArgumentBindings(); calculateArgumentBindings();
// AMC start // AMC start
Object[] adviceInvocationArgs = new Object[this.adviceInvocationArgumentCount]; Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
int numBound = 0; int numBound = 0;
if (this.joinPointArgumentIndex != -1) { if (this.joinPointArgumentIndex != -1) {
@ -580,11 +589,10 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
} }
} }
if (numBound != this.adviceInvocationArgumentCount) { if (numBound != this.parameterTypes.length) {
throw new IllegalStateException("Required to bind " + this.adviceInvocationArgumentCount throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
+ " arguments, but only bound " + numBound + " (JoinPointMatch " + " arguments, but only bound " + numBound + " (JoinPointMatch " +
(jpMatch == null ? "was NOT" : "WAS") + (jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
" bound in invocation)");
} }
return adviceInvocationArgs; return adviceInvocationArgs;
@ -665,6 +673,16 @@ public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedence
"aspect name '" + this.aspectName + "'"; "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. * MethodMatcher that excludes the specified advice method.

8
spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
@ -29,7 +30,9 @@ import org.springframework.aop.AfterAdvice;
* @author Rod Johnson * @author Rod Johnson
* @since 2.0 * @since 2.0
*/ */
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice { @SuppressWarnings("serial")
public class AspectJAfterAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterAdvice( public AspectJAfterAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
@ -37,6 +40,7 @@ public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodI
super(aspectJBeforeAdviceMethod, pointcut, aif); super(aspectJBeforeAdviceMethod, pointcut, aif);
} }
@Override @Override
public Object invoke(MethodInvocation mi) throws Throwable { public Object invoke(MethodInvocation mi) throws Throwable {
try { try {

7
spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterReturningAdvice.java

@ -16,6 +16,7 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -32,7 +33,9 @@ import org.springframework.util.TypeUtils;
* @author Ramnivas Laddad * @author Ramnivas Laddad
* @since 2.0 * @since 2.0
*/ */
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implements AfterReturningAdvice, AfterAdvice { @SuppressWarnings("serial")
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
implements AfterReturningAdvice, AfterAdvice, Serializable {
public AspectJAfterReturningAdvice( public AspectJAfterReturningAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
@ -40,6 +43,7 @@ public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implement
super(aspectJBeforeAdviceMethod, pointcut, aif); super(aspectJBeforeAdviceMethod, pointcut, aif);
} }
@Override @Override
public boolean isBeforeAdvice() { public boolean isBeforeAdvice() {
return false; return false;
@ -62,6 +66,7 @@ public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implement
} }
} }
/** /**
* Following AspectJ semantics, if a returning clause was specified, then the * Following AspectJ semantics, if a returning clause was specified, then the
* advice is only invoked if the returned value is an instance of the given * advice is only invoked if the returned value is an instance of the given

20
spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
@ -29,7 +30,9 @@ import org.springframework.aop.AfterAdvice;
* @author Rod Johnson * @author Rod Johnson
* @since 2.0 * @since 2.0
*/ */
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice { @SuppressWarnings("serial")
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
implements MethodInterceptor, AfterAdvice, Serializable {
public AspectJAfterThrowingAdvice( public AspectJAfterThrowingAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
@ -37,6 +40,7 @@ public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements
super(aspectJBeforeAdviceMethod, pointcut, aif); super(aspectJBeforeAdviceMethod, pointcut, aif);
} }
@Override @Override
public boolean isBeforeAdvice() { public boolean isBeforeAdvice() {
return false; return false;
@ -57,11 +61,11 @@ public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements
try { try {
return mi.proceed(); return mi.proceed();
} }
catch (Throwable t) { catch (Throwable ex) {
if (shouldInvokeOnThrowing(t)) { if (shouldInvokeOnThrowing(ex)) {
invokeAdviceMethod(getJoinPointMatch(), null, t); invokeAdviceMethod(getJoinPointMatch(), null, ex);
} }
throw t; throw ex;
} }
} }
@ -69,8 +73,8 @@ public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements
* In AspectJ semantics, after throwing advice that specifies a throwing clause * In AspectJ semantics, after throwing advice that specifies a throwing clause
* is only invoked if the thrown exception is a subtype of the given throwing type. * is only invoked if the thrown exception is a subtype of the given throwing type.
*/ */
private boolean shouldInvokeOnThrowing(Throwable t) { private boolean shouldInvokeOnThrowing(Throwable ex) {
return getDiscoveredThrowingType().isAssignableFrom(t.getClass()); return getDiscoveredThrowingType().isAssignableFrom(ex.getClass());
} }
} }

8
spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
@ -33,7 +34,8 @@ import org.springframework.aop.ProxyMethodInvocation;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @since 2.0
*/ */
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor { @SuppressWarnings("serial")
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {
public AspectJAroundAdvice( public AspectJAroundAdvice(
Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
@ -41,6 +43,7 @@ public class AspectJAroundAdvice extends AbstractAspectJAdvice implements Method
super(aspectJAroundAdviceMethod, pointcut, aif); super(aspectJAroundAdviceMethod, pointcut, aif);
} }
@Override @Override
public boolean isBeforeAdvice() { public boolean isBeforeAdvice() {
return false; return false;
@ -56,7 +59,6 @@ public class AspectJAroundAdvice extends AbstractAspectJAdvice implements Method
return true; return true;
} }
@Override @Override
public Object invoke(MethodInvocation mi) throws Throwable { public Object invoke(MethodInvocation mi) throws Throwable {
if (!(mi instanceof ProxyMethodInvocation)) { if (!(mi instanceof ProxyMethodInvocation)) {

7
spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.MethodBeforeAdvice;
@ -27,7 +28,8 @@ import org.springframework.aop.MethodBeforeAdvice;
* @author Adrian Colyer * @author Adrian Colyer
* @since 2.0 * @since 2.0
*/ */
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice { @SuppressWarnings("serial")
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public AspectJMethodBeforeAdvice( public AspectJMethodBeforeAdvice(
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) { Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
@ -35,6 +37,7 @@ public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements
super(aspectJBeforeAdviceMethod, pointcut, aif); super(aspectJBeforeAdviceMethod, pointcut, aif);
} }
@Override @Override
public void before(Method method, Object[] args, Object target) throws Throwable { public void before(Method method, Object[] args, Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null); invokeAdviceMethod(getJoinPointMatch(), null, null);

7
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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package org.springframework.aop.aspectj; package org.springframework.aop.aspectj;
import java.io.Serializable;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -29,7 +31,8 @@ import org.springframework.util.Assert;
* @since 2.0 * @since 2.0
* @see SimpleAspectInstanceFactory * @see SimpleAspectInstanceFactory
*/ */
public class SingletonAspectInstanceFactory implements AspectInstanceFactory { @SuppressWarnings("serial")
public class SingletonAspectInstanceFactory implements AspectInstanceFactory, Serializable {
private final Object aspectInstance; private final Object aspectInstance;

43
spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/AspectMetadata.java

@ -16,6 +16,10 @@
package org.springframework.aop.aspectj.annotation; 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.annotation.Aspect;
import org.aspectj.lang.reflect.AjType; import org.aspectj.lang.reflect.AjType;
import org.aspectj.lang.reflect.AjTypeSystem; import org.aspectj.lang.reflect.AjTypeSystem;
@ -40,12 +44,27 @@ import org.springframework.aop.support.ComposablePointcut;
* @since 2.0 * @since 2.0
* @see org.springframework.aop.aspectj.AspectJExpressionPointcut * @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) -
* allows us to determine if two pieces of advice come from the
* same aspect and hence their relative precedence.
*/
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). * 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 * Spring AOP pointcut corresponding to the per clause of the
@ -54,13 +73,6 @@ public class AspectMetadata {
*/ */
private final Pointcut perClausePointcut; private final Pointcut perClausePointcut;
/**
* The name of this aspect as defined to Spring (the bean name) -
* allows us to determine if two pieces of advice come from the
* same aspect and hence their relative precedence.
*/
private String aspectName;
/** /**
* Create a new AspectMetadata instance for the given aspect class. * Create a new AspectMetadata instance for the given aspect class.
@ -83,10 +95,11 @@ public class AspectMetadata {
if (ajType == null) { if (ajType == null) {
throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect"); throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");
} }
this.ajType = ajType; if (ajType.getDeclarePrecedence().length > 0) {
if (this.ajType.getDeclarePrecedence().length > 0) {
throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP"); throw new IllegalArgumentException("DeclarePrecendence not presently supported in Spring AOP");
} }
this.aspectClass = ajType.getJavaClass();
this.ajType = ajType;
switch (this.ajType.getPerClause().getKind()) { switch (this.ajType.getPerClause().getKind()) {
case SINGLETON : case SINGLETON :
@ -132,7 +145,7 @@ public class AspectMetadata {
* Return the aspect class. * Return the aspect class.
*/ */
public Class<?> getAspectClass() { public Class<?> getAspectClass() {
return this.ajType.getJavaClass(); return this.aspectClass;
} }
/** /**
@ -173,4 +186,10 @@ public class AspectMetadata {
return (isPerThisOrPerTarget() || isPerTypeWithin()); return (isPerThisOrPerTarget() || isPerTypeWithin());
} }
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
inputStream.defaultReadObject();
this.ajType = AjTypeSystem.getAjType(this.aspectClass);
}
} }

7
spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/BeanFactoryAspectInstanceFactory.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.Serializable;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -37,7 +39,8 @@ import org.springframework.util.ClassUtils;
* @see org.springframework.beans.factory.BeanFactory * @see org.springframework.beans.factory.BeanFactory
* @see LazySingletonAspectInstanceFactoryDecorator * @see LazySingletonAspectInstanceFactoryDecorator
*/ */
public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory { @SuppressWarnings("serial")
public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable {
private final BeanFactory beanFactory; private final BeanFactory beanFactory;

55
spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/InstantiationModelAwarePointcutAdvisorImpl.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,9 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.aopalliance.aop.Advice; import org.aopalliance.aop.Advice;
@ -37,26 +40,33 @@ import org.springframework.aop.support.Pointcuts;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @since 2.0
*/ */
@SuppressWarnings("serial")
class InstantiationModelAwarePointcutAdvisorImpl class InstantiationModelAwarePointcutAdvisorImpl
implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation { implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable {
private final AspectJExpressionPointcut declaredPointcut; private final AspectJExpressionPointcut declaredPointcut;
private Pointcut pointcut; private final Class<?> declaringClass;
private final MetadataAwareAspectInstanceFactory aspectInstanceFactory; private final String methodName;
private final Method method; private final Class<?>[] parameterTypes;
private final boolean lazy; private transient Method aspectJAdviceMethod;
private final AspectJAdvisorFactory atAspectJAdvisorFactory; private final AspectJAdvisorFactory atAspectJAdvisorFactory;
private Advice instantiatedAdvice; private final MetadataAwareAspectInstanceFactory aspectInstanceFactory;
private int declarationOrder; private final int declarationOrder;
private String aspectName; private final String aspectName;
private final Pointcut pointcut;
private final boolean lazy;
private Advice instantiatedAdvice;
private Boolean isBeforeAdvice; private Boolean isBeforeAdvice;
@ -67,7 +77,10 @@ class InstantiationModelAwarePointcutAdvisorImpl
MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) { MetadataAwareAspectInstanceFactory aif, Method method, int declarationOrderInAspect, String aspectName) {
this.declaredPointcut = ajexp; this.declaredPointcut = ajexp;
this.method = method; this.declaringClass = method.getDeclaringClass();
this.methodName = method.getName();
this.parameterTypes = method.getParameterTypes();
this.aspectJAdviceMethod = method;
this.atAspectJAdvisorFactory = af; this.atAspectJAdvisorFactory = af;
this.aspectInstanceFactory = aif; this.aspectInstanceFactory = aif;
this.declarationOrder = declarationOrderInAspect; this.declarationOrder = declarationOrderInAspect;
@ -86,9 +99,9 @@ class InstantiationModelAwarePointcutAdvisorImpl
} }
else { else {
// A singleton aspect. // A singleton aspect.
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); this.pointcut = this.declaredPointcut;
this.pointcut = declaredPointcut;
this.lazy = false; this.lazy = false;
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
} }
} }
@ -142,8 +155,8 @@ class InstantiationModelAwarePointcutAdvisorImpl
private Advice instantiateAdvice(AspectJExpressionPointcut pcut) { private Advice instantiateAdvice(AspectJExpressionPointcut pcut) {
return this.atAspectJAdvisorFactory.getAdvice( return this.atAspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pcut,
this.method, pcut, this.aspectInstanceFactory, this.declarationOrder, this.aspectName); this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
} }
public MetadataAwareAspectInstanceFactory getAspectInstanceFactory() { public MetadataAwareAspectInstanceFactory getAspectInstanceFactory() {
@ -191,7 +204,7 @@ class InstantiationModelAwarePointcutAdvisorImpl
*/ */
private void determineAdviceType() { private void determineAdviceType() {
AspectJAnnotation<?> aspectJAnnotation = AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.method); AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(this.aspectJAdviceMethod);
if (aspectJAnnotation == null) { if (aspectJAnnotation == null) {
this.isBeforeAdvice = false; this.isBeforeAdvice = false;
this.isAfterAdvice = false; this.isAfterAdvice = false;
@ -220,11 +233,21 @@ class InstantiationModelAwarePointcutAdvisorImpl
@Override @Override
public String toString() { public String toString() {
return "InstantiationModelAwarePointcutAdvisor: expression [" + getDeclaredPointcut().getExpression() + return "InstantiationModelAwarePointcutAdvisor: expression [" + getDeclaredPointcut().getExpression() +
"]; advice method [" + this.method + "]; perClauseKind=" + "]; advice method [" + this.aspectJAdviceMethod + "]; perClauseKind=" +
this.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind(); this.aspectInstanceFactory.getAspectMetadata().getAjType().getPerClause().getKind();
} }
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. * Pointcut implementation that changes its behaviour when the advice is instantiated.

7
spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/LazySingletonAspectInstanceFactoryDecorator.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.Serializable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -25,7 +27,8 @@ import org.springframework.util.Assert;
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.0 * @since 2.0
*/ */
public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwareAspectInstanceFactory { @SuppressWarnings("serial")
public class LazySingletonAspectInstanceFactoryDecorator implements MetadataAwareAspectInstanceFactory, Serializable {
private final MetadataAwareAspectInstanceFactory maaif; private final MetadataAwareAspectInstanceFactory maaif;

11
spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/PrototypeAspectInstanceFactory.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2007 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,11 +16,13 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.Serializable;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
/** /**
* AspectInstanceFactory backed by a BeanFactory-provided prototype, * {@link org.springframework.aop.aspectj.AspectInstanceFactory} backed by a
* enforcing prototype semantics. * {@link BeanFactory}-provided prototype, enforcing prototype semantics.
* *
* <p>Note that this may instantiate multiple times, which probably won't give the * <p>Note that this may instantiate multiple times, which probably won't give the
* semantics you expect. Use a {@link LazySingletonAspectInstanceFactoryDecorator} * semantics you expect. Use a {@link LazySingletonAspectInstanceFactoryDecorator}
@ -32,7 +34,8 @@ import org.springframework.beans.factory.BeanFactory;
* @see org.springframework.beans.factory.BeanFactory * @see org.springframework.beans.factory.BeanFactory
* @see LazySingletonAspectInstanceFactoryDecorator * @see LazySingletonAspectInstanceFactoryDecorator
*/ */
public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory { @SuppressWarnings("serial")
public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory implements Serializable {
/** /**
* Create a PrototypeAspectInstanceFactory. AspectJ will be called to * Create a PrototypeAspectInstanceFactory. AspectJ will be called to

6
spring-aop/src/main/java/org/springframework/aop/aspectj/annotation/ReflectiveAspectJAdvisorFactory.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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.Serializable;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -65,7 +66,8 @@ import org.springframework.util.comparator.InstanceComparator;
* @author Phillip Webb * @author Phillip Webb
* @since 2.0 * @since 2.0
*/ */
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory { @SuppressWarnings("serial")
public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFactory implements Serializable {
private static final Comparator<Method> METHOD_COMPARATOR; private static final Comparator<Method> METHOD_COMPARATOR;

7
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-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,8 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.Serializable;
import org.springframework.aop.aspectj.SingletonAspectInstanceFactory; import org.springframework.aop.aspectj.SingletonAspectInstanceFactory;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.OrderUtils; import org.springframework.core.annotation.OrderUtils;
@ -30,8 +32,9 @@ import org.springframework.core.annotation.OrderUtils;
* @since 2.0 * @since 2.0
* @see SimpleMetadataAwareAspectInstanceFactory * @see SimpleMetadataAwareAspectInstanceFactory
*/ */
@SuppressWarnings("serial")
public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspectInstanceFactory public class SingletonMetadataAwareAspectInstanceFactory extends SingletonAspectInstanceFactory
implements MetadataAwareAspectInstanceFactory { implements MetadataAwareAspectInstanceFactory, Serializable {
private final AspectMetadata metadata; private final AspectMetadata metadata;

16
spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectJPointcutAdvisorTests.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,9 +31,10 @@ import static org.junit.Assert.*;
* @author Rod Johnson * @author Rod Johnson
* @author Chris Beams * @author Chris Beams
*/ */
public final class AspectJPointcutAdvisorTests { public class AspectJPointcutAdvisorTests {
private final AspectJAdvisorFactory af = new ReflectiveAspectJAdvisorFactory();
private AspectJAdvisorFactory af = new ReflectiveAspectJAdvisorFactory();
@Test @Test
public void testSingleton() throws SecurityException, NoSuchMethodException { public void testSingleton() throws SecurityException, NoSuchMethodException {
@ -53,19 +54,18 @@ public final class AspectJPointcutAdvisorTests {
ajexp.setExpression(AspectJExpressionPointcutTests.MATCH_ALL_METHODS); ajexp.setExpression(AspectJExpressionPointcutTests.MATCH_ALL_METHODS);
InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(af, ajexp, InstantiationModelAwarePointcutAdvisorImpl ajpa = new InstantiationModelAwarePointcutAdvisorImpl(af, ajexp,
new SingletonMetadataAwareAspectInstanceFactory(new PerTargetAspect(),"someBean"), null, 1, "someBean"); new SingletonMetadataAwareAspectInstanceFactory(new PerTargetAspect(),"someBean"),
TestBean.class.getMethod("getAge", (Class[]) null), 1, "someBean");
assertNotSame(Pointcut.TRUE, ajpa.getAspectMetadata().getPerClausePointcut()); assertNotSame(Pointcut.TRUE, ajpa.getAspectMetadata().getPerClausePointcut());
assertTrue(ajpa.getAspectMetadata().getPerClausePointcut() instanceof AspectJExpressionPointcut); assertTrue(ajpa.getAspectMetadata().getPerClausePointcut() instanceof AspectJExpressionPointcut);
assertTrue(ajpa.isPerInstance()); assertTrue(ajpa.isPerInstance());
assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getClassFilter().matches(TestBean.class)); assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getClassFilter().matches(TestBean.class));
assertFalse(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches( assertFalse(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(
TestBean.class.getMethod("getAge", (Class[]) null), TestBean.class.getMethod("getAge", (Class[]) null), TestBean.class));
TestBean.class));
assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches( assertTrue(ajpa.getAspectMetadata().getPerClausePointcut().getMethodMatcher().matches(
TestBean.class.getMethod("getSpouse", (Class[]) null), TestBean.class.getMethod("getSpouse", (Class[]) null), TestBean.class));
TestBean.class));
} }
@Test(expected = AopConfigException.class) @Test(expected = AopConfigException.class)

27
spring-aop/src/test/java/org/springframework/aop/aspectj/annotation/AspectProxyFactoryTests.java

@ -16,13 +16,13 @@
package org.springframework.aop.aspectj.annotation; package org.springframework.aop.aspectj.annotation;
import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import test.aop.PerThisAspect; import test.aop.PerThisAspect;
@ -80,7 +80,18 @@ public class AspectProxyFactoryTests {
} }
@Test @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 { public void testWithInstance() throws Exception {
MultiplyReturnValue aspect = new MultiplyReturnValue(); MultiplyReturnValue aspect = new MultiplyReturnValue();
int multiple = 3; 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; private int age;
@ -171,7 +183,8 @@ public class AspectProxyFactoryTests {
@Aspect @Aspect
public static class LoggingAspectOnVarargs { @SuppressWarnings("serial")
public static class LoggingAspectOnVarargs implements Serializable {
@Around("execution(* doWithVarargs(*))") @Around("execution(* doWithVarargs(*))")
public Object doLog(ProceedingJoinPoint pjp) throws Throwable { public Object doLog(ProceedingJoinPoint pjp) throws Throwable {
@ -193,11 +206,9 @@ public class AspectProxyFactoryTests {
} }
/**
* @author Rod Johnson
*/
@Aspect @Aspect
class MultiplyReturnValue { @SuppressWarnings("serial")
class MultiplyReturnValue implements Serializable {
private int multiple = 2; private int multiple = 2;

Loading…
Cancel
Save