Skip to content

Commit 4adb7e2

Browse files
committed
AOP proxies with annotation-based aspects are serializable now
Issue: SPR-6910
1 parent bb0bc3d commit 4adb7e2

16 files changed

+213
-107
lines changed

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

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.aop.aspectj;
1818

19+
import java.io.IOException;
20+
import java.io.ObjectInputStream;
21+
import java.io.Serializable;
1922
import java.lang.reflect.InvocationTargetException;
2023
import java.lang.reflect.Method;
2124
import java.lang.reflect.Type;
@@ -55,7 +58,8 @@
5558
* @author Ramnivas Laddad
5659
* @since 2.0
5760
*/
58-
public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation {
61+
@SuppressWarnings("serial")
62+
public abstract class AbstractAspectJAdvice implements Advice, AspectJPrecedenceInformation, Serializable {
5963

6064
/**
6165
* Key used in ReflectiveMethodInvocation userAtributes map for the current joinpoint.
@@ -86,10 +90,13 @@ public static JoinPoint currentJoinPoint() {
8690
}
8791

8892

89-
protected final Method aspectJAdviceMethod;
93+
private final Class<?> declaringClass;
9094

91-
/** The total number of arguments we have to populate on advice dispatch */
92-
private final int adviceInvocationArgumentCount;
95+
private final String methodName;
96+
97+
private final Class<?>[] parameterTypes;
98+
99+
protected transient Method aspectJAdviceMethod;
93100

94101
private final AspectJExpressionPointcut pointcut;
95102

@@ -135,7 +142,7 @@ public static JoinPoint currentJoinPoint() {
135142
*/
136143
private int joinPointStaticPartArgumentIndex = -1;
137144

138-
private Map<String, Integer> argumentBindings = null;
145+
private Map<String, Integer> argumentBindings;
139146

140147
private boolean argumentsIntrospected = false;
141148

@@ -154,8 +161,10 @@ public AbstractAspectJAdvice(
154161
Method aspectJAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aspectInstanceFactory) {
155162

156163
Assert.notNull(aspectJAdviceMethod, "Advice method must not be null");
164+
this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
165+
this.methodName = aspectJAdviceMethod.getName();
166+
this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
157167
this.aspectJAdviceMethod = aspectJAdviceMethod;
158-
this.adviceInvocationArgumentCount = this.aspectJAdviceMethod.getParameterTypes().length;
159168
this.pointcut = pointcut;
160169
this.aspectInstanceFactory = aspectInstanceFactory;
161170
}
@@ -250,17 +259,17 @@ public void setArgumentNamesFromStringArray(String... args) {
250259
this.argumentNames[i] + "' that is not a valid Java identifier");
251260
}
252261
}
253-
if (argumentNames != null) {
254-
if (aspectJAdviceMethod.getParameterTypes().length == argumentNames.length + 1) {
262+
if (this.argumentNames != null) {
263+
if (this.aspectJAdviceMethod.getParameterTypes().length == this.argumentNames.length + 1) {
255264
// May need to add implicit join point arg name...
256-
Class<?> firstArgType = aspectJAdviceMethod.getParameterTypes()[0];
265+
Class<?> firstArgType = this.aspectJAdviceMethod.getParameterTypes()[0];
257266
if (firstArgType == JoinPoint.class ||
258267
firstArgType == ProceedingJoinPoint.class ||
259268
firstArgType == JoinPoint.StaticPart.class) {
260-
String[] oldNames = argumentNames;
261-
argumentNames = new String[oldNames.length + 1];
262-
argumentNames[0] = "THIS_JOIN_POINT";
263-
System.arraycopy(oldNames, 0, argumentNames, 1, oldNames.length);
269+
String[] oldNames = this.argumentNames;
270+
this.argumentNames = new String[oldNames.length + 1];
271+
this.argumentNames[0] = "THIS_JOIN_POINT";
272+
System.arraycopy(oldNames, 0, this.argumentNames, 1, oldNames.length);
264273
}
265274
}
266275
}
@@ -359,11 +368,11 @@ private boolean isVariableName(String name) {
359368
*/
360369
public synchronized final void calculateArgumentBindings() {
361370
// The simple case... nothing to bind.
362-
if (this.argumentsIntrospected || this.adviceInvocationArgumentCount == 0) {
371+
if (this.argumentsIntrospected || this.parameterTypes.length == 0) {
363372
return;
364373
}
365374

366-
int numUnboundArgs = this.adviceInvocationArgumentCount;
375+
int numUnboundArgs = this.parameterTypes.length;
367376
Class<?>[] parameterTypes = this.aspectJAdviceMethod.getParameterTypes();
368377
if (maybeBindJoinPoint(parameterTypes[0]) || maybeBindProceedingJoinPoint(parameterTypes[0])) {
369378
numUnboundArgs--;
@@ -456,13 +465,13 @@ private void bindExplicitArguments(int numArgumentsLeftToBind) {
456465

457466
int numExpectedArgumentNames = this.aspectJAdviceMethod.getParameterTypes().length;
458467
if (this.argumentNames.length != numExpectedArgumentNames) {
459-
throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames
460-
+ " arguments to bind by name in advice, but actually found " +
468+
throw new IllegalStateException("Expecting to find " + numExpectedArgumentNames +
469+
" arguments to bind by name in advice, but actually found " +
461470
this.argumentNames.length + " arguments.");
462471
}
463472

464473
// So we match in number...
465-
int argumentIndexOffset = this.adviceInvocationArgumentCount - numArgumentsLeftToBind;
474+
int argumentIndexOffset = this.parameterTypes.length - numArgumentsLeftToBind;
466475
for (int i = argumentIndexOffset; i < this.argumentNames.length; i++) {
467476
this.argumentBindings.put(this.argumentNames[i], i);
468477
}
@@ -471,8 +480,8 @@ private void bindExplicitArguments(int numArgumentsLeftToBind) {
471480
// specified, and find the discovered argument types.
472481
if (this.returningName != null) {
473482
if (!this.argumentBindings.containsKey(this.returningName)) {
474-
throw new IllegalStateException("Returning argument name '"
475-
+ this.returningName + "' was not bound in advice arguments");
483+
throw new IllegalStateException("Returning argument name '" + this.returningName +
484+
"' was not bound in advice arguments");
476485
}
477486
else {
478487
Integer index = this.argumentBindings.get(this.returningName);
@@ -482,8 +491,8 @@ private void bindExplicitArguments(int numArgumentsLeftToBind) {
482491
}
483492
if (this.throwingName != null) {
484493
if (!this.argumentBindings.containsKey(this.throwingName)) {
485-
throw new IllegalStateException("Throwing argument name '"
486-
+ this.throwingName + "' was not bound in advice arguments");
494+
throw new IllegalStateException("Throwing argument name '" + this.throwingName +
495+
"' was not bound in advice arguments");
487496
}
488497
else {
489498
Integer index = this.argumentBindings.get(this.throwingName);
@@ -543,7 +552,7 @@ protected Object[] argBinding(JoinPoint jp, JoinPointMatch jpMatch, Object retur
543552
calculateArgumentBindings();
544553

545554
// AMC start
546-
Object[] adviceInvocationArgs = new Object[this.adviceInvocationArgumentCount];
555+
Object[] adviceInvocationArgs = new Object[this.parameterTypes.length];
547556
int numBound = 0;
548557

549558
if (this.joinPointArgumentIndex != -1) {
@@ -580,11 +589,10 @@ else if (this.joinPointStaticPartArgumentIndex != -1) {
580589
}
581590
}
582591

583-
if (numBound != this.adviceInvocationArgumentCount) {
584-
throw new IllegalStateException("Required to bind " + this.adviceInvocationArgumentCount
585-
+ " arguments, but only bound " + numBound + " (JoinPointMatch " +
586-
(jpMatch == null ? "was NOT" : "WAS") +
587-
" bound in invocation)");
592+
if (numBound != this.parameterTypes.length) {
593+
throw new IllegalStateException("Required to bind " + this.parameterTypes.length +
594+
" arguments, but only bound " + numBound + " (JoinPointMatch " +
595+
(jpMatch == null ? "was NOT" : "WAS") + " bound in invocation)");
588596
}
589597

590598
return adviceInvocationArgs;
@@ -665,6 +673,16 @@ public String toString() {
665673
"aspect name '" + this.aspectName + "'";
666674
}
667675

676+
private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
677+
inputStream.defaultReadObject();
678+
try {
679+
this.aspectJAdviceMethod = this.declaringClass.getMethod(this.methodName, this.parameterTypes);
680+
}
681+
catch (NoSuchMethodException ex) {
682+
throw new IllegalStateException("Failed to find advice method on deserialization", ex);
683+
}
684+
}
685+
668686

669687
/**
670688
* MethodMatcher that excludes the specified advice method.

spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterAdvice.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.aop.aspectj;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Method;
2021

2122
import org.aopalliance.intercept.MethodInterceptor;
@@ -29,14 +30,17 @@
2930
* @author Rod Johnson
3031
* @since 2.0
3132
*/
32-
public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {
33+
@SuppressWarnings("serial")
34+
public class AspectJAfterAdvice extends AbstractAspectJAdvice
35+
implements MethodInterceptor, AfterAdvice, Serializable {
3336

3437
public AspectJAfterAdvice(
3538
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
3639

3740
super(aspectJBeforeAdviceMethod, pointcut, aif);
3841
}
3942

43+
4044
@Override
4145
public Object invoke(MethodInvocation mi) throws Throwable {
4246
try {

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.aop.aspectj;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Method;
2021
import java.lang.reflect.Type;
2122

@@ -32,14 +33,17 @@
3233
* @author Ramnivas Laddad
3334
* @since 2.0
3435
*/
35-
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice implements AfterReturningAdvice, AfterAdvice {
36+
@SuppressWarnings("serial")
37+
public class AspectJAfterReturningAdvice extends AbstractAspectJAdvice
38+
implements AfterReturningAdvice, AfterAdvice, Serializable {
3639

3740
public AspectJAfterReturningAdvice(
3841
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
3942

4043
super(aspectJBeforeAdviceMethod, pointcut, aif);
4144
}
4245

46+
4347
@Override
4448
public boolean isBeforeAdvice() {
4549
return false;
@@ -62,6 +66,7 @@ public void afterReturning(Object returnValue, Method method, Object[] args, Obj
6266
}
6367
}
6468

69+
6570
/**
6671
* Following AspectJ semantics, if a returning clause was specified, then the
6772
* advice is only invoked if the returned value is an instance of the given

spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAfterThrowingAdvice.java

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.aop.aspectj;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Method;
2021

2122
import org.aopalliance.intercept.MethodInterceptor;
@@ -29,14 +30,17 @@
2930
* @author Rod Johnson
3031
* @since 2.0
3132
*/
32-
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice {
33+
@SuppressWarnings("serial")
34+
public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice
35+
implements MethodInterceptor, AfterAdvice, Serializable {
3336

3437
public AspectJAfterThrowingAdvice(
3538
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
3639

3740
super(aspectJBeforeAdviceMethod, pointcut, aif);
3841
}
3942

43+
4044
@Override
4145
public boolean isBeforeAdvice() {
4246
return false;
@@ -57,20 +61,20 @@ public Object invoke(MethodInvocation mi) throws Throwable {
5761
try {
5862
return mi.proceed();
5963
}
60-
catch (Throwable t) {
61-
if (shouldInvokeOnThrowing(t)) {
62-
invokeAdviceMethod(getJoinPointMatch(), null, t);
64+
catch (Throwable ex) {
65+
if (shouldInvokeOnThrowing(ex)) {
66+
invokeAdviceMethod(getJoinPointMatch(), null, ex);
6367
}
64-
throw t;
68+
throw ex;
6569
}
6670
}
6771

6872
/**
6973
* In AspectJ semantics, after throwing advice that specifies a throwing clause
7074
* is only invoked if the thrown exception is a subtype of the given throwing type.
7175
*/
72-
private boolean shouldInvokeOnThrowing(Throwable t) {
73-
return getDiscoveredThrowingType().isAssignableFrom(t.getClass());
76+
private boolean shouldInvokeOnThrowing(Throwable ex) {
77+
return getDiscoveredThrowingType().isAssignableFrom(ex.getClass());
7478
}
7579

7680
}

spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJAroundAdvice.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.aop.aspectj;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Method;
2021

2122
import org.aopalliance.intercept.MethodInterceptor;
@@ -33,14 +34,16 @@
3334
* @author Juergen Hoeller
3435
* @since 2.0
3536
*/
36-
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor {
37+
@SuppressWarnings("serial")
38+
public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable {
3739

3840
public AspectJAroundAdvice(
3941
Method aspectJAroundAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
4042

4143
super(aspectJAroundAdviceMethod, pointcut, aif);
4244
}
4345

46+
4447
@Override
4548
public boolean isBeforeAdvice() {
4649
return false;
@@ -56,7 +59,6 @@ protected boolean supportsProceedingJoinPoint() {
5659
return true;
5760
}
5861

59-
6062
@Override
6163
public Object invoke(MethodInvocation mi) throws Throwable {
6264
if (!(mi instanceof ProxyMethodInvocation)) {

spring-aop/src/main/java/org/springframework/aop/aspectj/AspectJMethodBeforeAdvice.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.aop.aspectj;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Method;
2021

2122
import org.springframework.aop.MethodBeforeAdvice;
@@ -27,14 +28,16 @@
2728
* @author Adrian Colyer
2829
* @since 2.0
2930
*/
30-
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice {
31+
@SuppressWarnings("serial")
32+
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
3133

3234
public AspectJMethodBeforeAdvice(
3335
Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
3436

3537
super(aspectJBeforeAdviceMethod, pointcut, aif);
3638
}
3739

40+
3841
@Override
3942
public void before(Method method, Object[] args, Object target) throws Throwable {
4043
invokeAdviceMethod(getJoinPointMatch(), null, null);

0 commit comments

Comments
 (0)