diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index 217244e8952..5abb10919e4 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -723,17 +723,20 @@ class CglibAopProxy implements AopProxy, Serializable { */ private static class CglibMethodInvocation extends ReflectiveMethodInvocation { + @Nullable private final MethodProxy methodProxy; - private final boolean publicMethod; - public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method, Object[] arguments, @Nullable Class targetClass, List interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) { super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers); - this.methodProxy = methodProxy; - this.publicMethod = Modifier.isPublic(method.getModifiers()); + + // Only use method proxy for public methods not derived from java.lang.Object + this.methodProxy = (Modifier.isPublic(method.getModifiers()) && + method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) && + !AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ? + methodProxy : null); } /** @@ -742,7 +745,7 @@ class CglibAopProxy implements AopProxy, Serializable { */ @Override protected Object invokeJoinpoint() throws Throwable { - if (this.publicMethod && getMethod().getDeclaringClass() != Object.class) { + if (this.methodProxy != null) { return this.methodProxy.invoke(this.target, this.arguments); } else { diff --git a/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java b/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java index 4c3a41dbb7f..05f91451d54 100644 --- a/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java +++ b/spring-context/src/test/java/org/springframework/aop/framework/CglibProxyTests.java @@ -74,6 +74,7 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab return true; } + @Test(expected = IllegalArgumentException.class) public void testNullConfig() { new CglibAopProxy(null); @@ -153,6 +154,20 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab assertEquals("The name property has been overwritten by the constructor", "Rob Harrop", proxy.getName()); } + @Test + public void testToStringInvocation() { + PrivateCglibTestBean bean = new PrivateCglibTestBean(); + bean.setName("Rob Harrop"); + + AdvisedSupport as = new AdvisedSupport(); + as.setTarget(bean); + as.addAdvice(new NopInterceptor()); + AopProxy aop = new CglibAopProxy(as); + + PrivateCglibTestBean proxy = (PrivateCglibTestBean) aop.getProxy(); + assertEquals("The name property has been overwritten by the constructor", "Rob Harrop", proxy.toString()); + } + @Test public void testUnadvisedProxyCreationWithCallDuringConstructor() { CglibTestBean target = new CglibTestBean(); @@ -480,6 +495,29 @@ public class CglibProxyTests extends AbstractAopProxyTests implements Serializab return this.value; } } + + + private static class PrivateCglibTestBean { + + private String name; + + public PrivateCglibTestBean() { + setName("Some Default"); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + @Override + public String toString() { + return this.name; + } + } } @@ -498,6 +536,11 @@ class CglibTestBean { public String getName() { return this.name; } + + @Override + public String toString() { + return this.name; + } }