53
53
import org .springframework .web .service .annotation .PostExchange ;
54
54
import org .springframework .web .service .annotation .PutExchange ;
55
55
import org .springframework .web .testfixture .http .server .reactive .MockServerHttpRequest ;
56
+ import org .springframework .web .testfixture .method .PackagePrivateMethodController ;
56
57
import org .springframework .web .testfixture .server .MockServerWebExchange ;
57
58
import org .springframework .web .util .pattern .PathPattern ;
58
59
import org .springframework .web .util .pattern .PathPatternParser ;
62
63
import static org .mockito .Mockito .mock ;
63
64
import static org .springframework .web .bind .annotation .RequestMethod .POST ;
64
65
import static org .springframework .web .reactive .result .method .RequestMappingInfo .paths ;
65
- import static org .springframework .web .testfixture .method .VisibilityTestHandler .PackagePrivateController ;
66
- import static org .springframework .web .testfixture .method .VisibilityTestHandler .ProtectedController ;
67
66
68
67
/**
69
68
* Tests for {@link RequestMappingHandlerMapping}.
@@ -414,25 +413,26 @@ void requestBodyAnnotationFromImplementationOverridesInterface() {
414
413
assertThat (matchingInfo ).isEqualTo (paths (path ).methods (POST ).consumes (mediaType .toString ()).build ());
415
414
}
416
415
417
- @ Test
416
+ @ Test // gh-35352
418
417
void privateMethodOnCglibProxyShouldThrowException () throws Exception {
419
418
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping ();
420
419
421
420
Class <?> handlerType = PrivateMethodController .class ;
422
- Method method = handlerType . getDeclaredMethod ( "privateMethod" ) ;
423
-
421
+ String methodName = "privateMethod" ;
422
+ Method method = handlerType . getDeclaredMethod ( methodName );
424
423
Class <?> proxyClass = createProxyClass (handlerType );
425
424
426
425
assertThatIllegalStateException ()
427
426
.isThrownBy (() -> mapping .getMappingForMethod (method , proxyClass ))
428
- .withMessageContainingAll (
429
- "Private method [privateMethod]" ,
430
- "cannot be used as a request handler method"
431
- );
427
+ .withMessage ("""
428
+ Private method [%s] on CGLIB proxy class [%s] cannot be used as a request \
429
+ handler method, because private methods cannot be overridden. \
430
+ Change the method to non-private visibility, or use interface-based JDK \
431
+ proxying instead.""" , methodName , proxyClass .getName ());
432
432
}
433
433
434
- @ Test
435
- void protectedMethodShouldNotThrowException () throws Exception {
434
+ @ Test // gh-35352
435
+ void protectedMethodOnCglibProxyShouldNotThrowException () throws Exception {
436
436
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping ();
437
437
438
438
Class <?> handlerType = ProtectedMethodController .class ;
@@ -444,63 +444,33 @@ void protectedMethodShouldNotThrowException() throws Exception {
444
444
assertThat (info .getPatternsCondition ().getDirectPaths ()).containsOnly ("/protected" );
445
445
}
446
446
447
- @ Test
448
- void differentPackagePackagePrivateMethodShouldThrowException () throws Exception {
447
+ @ Test // gh-35352
448
+ void differentPackagePackagePrivateMethodOnCglibProxyShouldThrowException () throws Exception {
449
449
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping ();
450
450
451
- Class <?> handlerType = ControllerWithPackagePrivateClass .class ;
452
- Method method = PackagePrivateController .class .getDeclaredMethod ("packagePrivateMethod" );
453
-
451
+ Class <?> handlerType = LocalPackagePrivateMethodControllerSubclass .class ;
452
+ Class <?> declaringClass = PackagePrivateMethodController .class ;
453
+ String methodName = "packagePrivateMethod" ;
454
+ Method method = declaringClass .getDeclaredMethod (methodName );
454
455
Class <?> proxyClass = createProxyClass (handlerType );
455
456
456
457
assertThatIllegalStateException ()
457
458
.isThrownBy (() -> mapping .getMappingForMethod (method , proxyClass ))
458
- .withMessageContainingAll (
459
- "Package-private method [packagePrivateMethod]" ,
460
- "cannot be advised when used by handler class"
461
- );
462
- }
463
-
464
- @ Test
465
- void differentPackageProtectedMethodShouldNotThrowException () throws Exception {
466
- RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping ();
467
-
468
- Class <?> handlerType = ControllerWithProtectedClass .class ;
469
- Method method = ProtectedController .class .getDeclaredMethod ("protectedMethod" );
470
-
471
- Class <?> proxyClass = createProxyClass (handlerType );
472
-
473
- RequestMappingInfo info = mapping .getMappingForMethod (method , proxyClass );
474
- assertThat (info .getPatternsCondition ().getDirectPaths ()).containsOnly ("/protected" );
459
+ .withMessage ("""
460
+ Package-private method [%s] declared in class [%s] cannot be advised by \
461
+ CGLIB-proxied handler class [%s], because it is effectively private. Either \
462
+ make the method public or protected, or use interface-based JDK proxying instead.""" ,
463
+ methodName , declaringClass .getName (), proxyClass .getName ());
475
464
}
476
465
477
466
478
- private Class <?> createProxyClass (Class <?> targetClass ) {
467
+ private static Class <?> createProxyClass (Class <?> targetClass ) {
479
468
Enhancer enhancer = new Enhancer ();
480
469
enhancer .setSuperclass (targetClass );
481
470
enhancer .setCallbackTypes (new Class []{NoOp .class });
482
-
483
471
return enhancer .createClass ();
484
472
}
485
473
486
- @ Controller
487
- static class PrivateMethodController {
488
- @ RequestMapping ("/private" )
489
- private void privateMethod () {}
490
- }
491
-
492
- @ Controller
493
- static class ProtectedMethodController {
494
- @ RequestMapping ("/protected" )
495
- protected void protectedMethod () {}
496
- }
497
-
498
- @ Controller
499
- static class ControllerWithPackagePrivateClass extends PackagePrivateController { }
500
-
501
- @ Controller
502
- static class ControllerWithProtectedClass extends ProtectedController { }
503
-
504
474
private RequestMappingInfo assertComposedAnnotationMapping (RequestMethod requestMethod ) {
505
475
String methodName = requestMethod .name ().toLowerCase ();
506
476
String path = "/" + methodName ;
@@ -705,4 +675,21 @@ public void post(@RequestBody(required = true) Foo foo) {}
705
675
@interface ExtraHttpExchange {
706
676
}
707
677
678
+ @ Controller
679
+ static class PrivateMethodController {
680
+
681
+ @ RequestMapping ("/private" )
682
+ private void privateMethod () {}
683
+ }
684
+
685
+ @ Controller
686
+ static class ProtectedMethodController {
687
+
688
+ @ RequestMapping ("/protected" )
689
+ protected void protectedMethod () {}
690
+ }
691
+
692
+ static class LocalPackagePrivateMethodControllerSubclass extends PackagePrivateMethodController {
693
+ }
694
+
708
695
}
0 commit comments