Throw on advise returning null for primitive type

Throw an AopInvocationException when an AOP advisor returns null on
a method that should return a primitive type.

Issue: SPR-4675
This commit is contained in:
Dave Syer
2012-10-30 15:54:57 -07:00
committed by Phillip Webb
parent 39682b7d3f
commit 3e296974c4
3 changed files with 113 additions and 10 deletions

View File

@@ -41,6 +41,7 @@ import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.AopInvocationException;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.RawTargetAccess;
import org.springframework.aop.TargetSource;
@@ -72,6 +73,7 @@ import org.springframework.util.ObjectUtils;
* @author Juergen Hoeller
* @author Ramnivas Laddad
* @author Chris Beams
* @author Dave Syer
* @see org.springframework.cglib.proxy.Enhancer
* @see AdvisedSupport#setProxyTargetClass
* @see DefaultAopProxyFactory
@@ -330,9 +332,10 @@ final class CglibAopProxy implements AopProxy, Serializable {
}
/**
* Wrap a return of this if necessary to be the proxy
* Process a return value. Wraps a return of {@code this} if necessary to be the
* {@code proxy} and also verifies that {@code null} is not returned as a primitive.
*/
private static Object massageReturnTypeIfNecessary(Object proxy, Object target, Method method, Object retVal) {
private static Object processReturnType(Object proxy, Object target, Method method, Object retVal) {
// Massage return value if necessary
if (retVal != null && retVal == target &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
@@ -341,6 +344,10 @@ final class CglibAopProxy implements AopProxy, Serializable {
// to itself in another returned object.
retVal = proxy;
}
Class<?> returnType = method.getReturnType();
if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
@@ -381,7 +388,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object retVal = methodProxy.invoke(this.target, args);
return massageReturnTypeIfNecessary(proxy, this.target, method, retVal);
return processReturnType(proxy, this.target, method, retVal);
}
}
@@ -403,7 +410,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(this.target, args);
return massageReturnTypeIfNecessary(proxy, this.target, method, retVal);
return processReturnType(proxy, this.target, method, retVal);
}
finally {
AopContext.setCurrentProxy(oldProxy);
@@ -429,7 +436,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
Object target = this.targetSource.getTarget();
try {
Object retVal = methodProxy.invoke(target, args);
return massageReturnTypeIfNecessary(proxy, target, method, retVal);
return processReturnType(proxy, target, method, retVal);
}
finally {
this.targetSource.releaseTarget(target);
@@ -455,7 +462,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
try {
oldProxy = AopContext.setCurrentProxy(proxy);
Object retVal = methodProxy.invoke(target, args);
return massageReturnTypeIfNecessary(proxy, target, method, retVal);
return processReturnType(proxy, target, method, retVal);
}
finally {
AopContext.setCurrentProxy(oldProxy);
@@ -573,7 +580,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
this.targetClass, this.adviceChain, methodProxy);
// If we get here, we need to create a MethodInvocation.
Object retVal = invocation.proceed();
retVal = massageReturnTypeIfNecessary(proxy, this.target, method, retVal);
retVal = processReturnType(proxy, this.target, method, retVal);
return retVal;
}
}
@@ -623,7 +630,7 @@ final class CglibAopProxy implements AopProxy, Serializable {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = massageReturnTypeIfNecessary(proxy, target, method, retVal);
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 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.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AopInvocationException;
import org.springframework.aop.RawTargetAccess;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
@@ -53,6 +54,7 @@ import org.springframework.util.ClassUtils;
* @author Rod Johnson
* @author Juergen Hoeller
* @author Rob Harrop
* @author Dave Syer
* @see java.lang.reflect.Proxy
* @see AdvisedSupport
* @see ProxyFactory
@@ -203,12 +205,15 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa
}
// Massage return value if necessary.
if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
} else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}