Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
Expand All @@ -35,6 +36,7 @@
import reactor.core.publisher.Mono;
import reactor.core.publisher.SynchronousSink;

import org.springframework.aop.support.AopUtils;
import org.springframework.context.MessageSource;
import org.springframework.core.CoroutinesUtils;
import org.springframework.core.DefaultParameterNameDiscoverer;
Expand All @@ -58,6 +60,7 @@
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @author Sebastien Deleuze
* @author Yongjun Hong
* @since 3.1
*/
public class InvocableHandlerMethod extends HandlerMethod {
Expand Down Expand Up @@ -246,6 +249,16 @@ public void setMethodValidator(@Nullable MethodValidator methodValidator) {
*/
protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception {
Method method = getBridgedMethod();
Object bean = getBean();

if (AopUtils.isCglibProxy(bean) && Modifier.isPrivate(method.getModifiers())) {
throw new IllegalStateException(
"Cannot invoke private method [" + method.getName() + "] on a CGLIB proxy. " +
"Handler methods on proxied components must be public or protected. " +
"Change method visibility or use interface-based JDK proxies if applicable."
);
}

try {
if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
if (KotlinDetector.isSuspendingFunction(method)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
Expand All @@ -42,6 +43,7 @@
* Tests for {@link InvocableHandlerMethod}.
*
* @author Rossen Stoyanchev
* @author Yongjun Hong
*/
class InvocableHandlerMethodTests {

Expand Down Expand Up @@ -168,6 +170,21 @@ public void invocationErrorMessage() {
.withMessageContaining("Illegal argument");
}

@Test
void testPrivateMethodOnCglibProxyThrowsException() throws Exception {
TestController target = new TestController();
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.setProxyTargetClass(true);
Object proxy = proxyFactory.getProxy();

Method privateMethod = TestController.class.getDeclaredMethod("privateMethod");
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(proxy, privateMethod);

assertThatIllegalStateException()
.isThrownBy(() -> handlerMethod.invokeForRequest(null, null))
.withMessageContaining("Cannot invoke private method [privateMethod] on a CGLIB proxy");
}

private InvocableHandlerMethod getInvocable(Class<?>... argTypes) {
Method method = ResolvableMethod.on(Handler.class).argTypes(argTypes).resolveMethod();
InvocableHandlerMethod handlerMethod = new InvocableHandlerMethod(new Handler(), method);
Expand Down Expand Up @@ -216,4 +233,12 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m
}
}

private static class TestController {
public TestController() {
// Default constructor for proxy creation
}

private void privateMethod() { }
}

}