TargetSource.getTarget() is nullable again (for compatibility with MethodInvocation.getThis)

Issue: SPR-15651
This commit is contained in:
Juergen Hoeller
2017-06-12 22:54:18 +02:00
parent 233c15b80e
commit 47ec966757
8 changed files with 67 additions and 47 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.aop;
import org.springframework.lang.Nullable;
/**
* A {@code TargetSource} is used to obtain the current "target" of
* an AOP invocation, which will be invoked via reflection if no around
@@ -54,14 +56,16 @@ public interface TargetSource extends TargetClassAware {
/**
* Return a target instance. Invoked immediately before the
* AOP framework calls the "target" of an AOP method invocation.
* @return the target object, which contains the joinpoint
* @return the target object which contains the joinpoint,
* or {@code null} if there is no actual target instance
* @throws Exception if the target object can't be resolved
*/
@Nullable
Object getTarget() throws Exception;
/**
* Release the given target object obtained from the
* {@link #getTarget()} method.
* {@link #getTarget()} method, if any.
* @param target object obtained from a call to {@link #getTarget()}
* @throws Exception if the object can't be released
*/

View File

@@ -326,12 +326,8 @@ class CglibAopProxy implements AopProxy, Serializable {
// TODO: small memory optimization here (can skip creation for methods with no advice)
for (int x = 0; x < methods.length; x++) {
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);
Object target = this.advised.getTargetSource().getTarget();
Class<?> targetClass = this.advised.getTargetClass();
if (targetClass == null) {
targetClass = target.getClass();
}
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(chain, target, targetClass);
fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
this.fixedInterceptorMap.put(methods[x].toString(), x);
}
@@ -378,20 +374,22 @@ class CglibAopProxy implements AopProxy, Serializable {
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
*/
@Nullable
private static Object processReturnType(Object proxy, Object target, Method method, @Nullable Object retVal) {
private static Object processReturnType(
Object proxy, @Nullable Object target, Method method, @Nullable Object returnValue) {
// Massage return value if necessary
if (retVal != null && retVal == target &&
if (returnValue != null && returnValue == target &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this". Note that we can't help
// if the target sets a reference to itself in another returned object.
retVal = proxy;
returnValue = proxy;
}
Class<?> returnType = method.getReturnType();
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
if (returnValue == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
return returnValue;
}
@@ -413,7 +411,7 @@ class CglibAopProxy implements AopProxy, Serializable {
private final Object target;
public StaticUnadvisedInterceptor(Object target) {
public StaticUnadvisedInterceptor(@Nullable Object target) {
this.target = target;
}
@@ -434,7 +432,7 @@ class CglibAopProxy implements AopProxy, Serializable {
private final Object target;
public StaticUnadvisedExposedInterceptor(Object target) {
public StaticUnadvisedExposedInterceptor(@Nullable Object target) {
this.target = target;
}
@@ -476,7 +474,9 @@ class CglibAopProxy implements AopProxy, Serializable {
return processReturnType(proxy, target, method, retVal);
}
finally {
this.targetSource.releaseTarget(target);
if (target != null) {
this.targetSource.releaseTarget(target);
}
}
}
}
@@ -505,7 +505,9 @@ class CglibAopProxy implements AopProxy, Serializable {
}
finally {
AopContext.setCurrentProxy(oldProxy);
this.targetSource.releaseTarget(target);
if (target != null) {
this.targetSource.releaseTarget(target);
}
}
}
}
@@ -612,7 +614,9 @@ class CglibAopProxy implements AopProxy, Serializable {
private final Class<?> targetClass;
public FixedChainStaticTargetInterceptor(List<Object> adviceChain, Object target, Class<?> targetClass) {
public FixedChainStaticTargetInterceptor(
List<Object> adviceChain, @Nullable Object target, @Nullable Class<?> targetClass) {
this.adviceChain = adviceChain;
this.target = target;
this.targetClass = targetClass;
@@ -649,6 +653,7 @@ class CglibAopProxy implements AopProxy, Serializable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
@@ -656,8 +661,8 @@ class CglibAopProxy implements AopProxy, Serializable {
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = getTarget();
Class<?> targetClass = target.getClass();
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
@@ -678,8 +683,8 @@ class CglibAopProxy implements AopProxy, Serializable {
return retVal;
}
finally {
if (target != null) {
releaseTarget(target);
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
@@ -702,14 +707,6 @@ class CglibAopProxy implements AopProxy, Serializable {
public int hashCode() {
return this.advised.hashCode();
}
protected Object getTarget() throws Exception {
return this.advised.getTargetSource().getTarget();
}
protected void releaseTarget(Object target) throws Exception {
this.advised.getTargetSource().releaseTarget(target);
}
}
@@ -722,8 +719,9 @@ class CglibAopProxy implements AopProxy, Serializable {
private final boolean publicMethod;
public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
Object[] arguments, @Nullable Class<?> targetClass,
List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
this.methodProxy = methodProxy;

View File

@@ -191,7 +191,7 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = target.getClass();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

View File

@@ -103,8 +103,8 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
* but would complicate the code. And it would work only for static pointcuts.
*/
protected ReflectiveMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
Object proxy, @Nullable Object target, Method method, Object[] arguments,
@Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
@@ -121,6 +121,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
}
@Override
@Nullable
public final Object getThis() {
return this.target;
}

View File

@@ -329,7 +329,7 @@ public abstract class AopUtils {
* @throws org.springframework.aop.AopInvocationException in case of a reflection error
*/
@Nullable
public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
throws Throwable {
// Use reflection to invoke the method.

View File

@@ -32,13 +32,6 @@ import org.springframework.util.ObjectUtils;
*/
public class EmptyTargetSource implements TargetSource, Serializable {
/**
* The canonical (Singleton) instance of this {@link EmptyTargetSource}.
*/
public static final EmptyTargetSource INSTANCE = new EmptyTargetSource(null, true);
private static final Object EMPTY_TARGET = new Object();
/** use serialVersionUID from Spring 1.2 for interoperability */
private static final long serialVersionUID = 3680494563553489691L;
@@ -47,6 +40,12 @@ public class EmptyTargetSource implements TargetSource, Serializable {
// Static factory methods
//---------------------------------------------------------------------
/**
* The canonical (Singleton) instance of this {@link EmptyTargetSource}.
*/
public static final EmptyTargetSource INSTANCE = new EmptyTargetSource(null, true);
/**
* Return an EmptyTargetSource for the given target Class.
* @param targetClass the target Class (may be {@code null})
@@ -106,11 +105,11 @@ public class EmptyTargetSource implements TargetSource, Serializable {
}
/**
* Always returns {@code DUMMY_TARGET}.
* Always returns {@code null}.
*/
@Override
public Object getTarget() {
return EMPTY_TARGET;
return null;
}
/**