Skip to content

Commit 3600644

Browse files
committed
Require type-level @controller annotation
Closes gh-22154
1 parent 2db6795 commit 3600644

File tree

6 files changed

+53
-16
lines changed

6 files changed

+53
-16
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,7 @@ public void afterPropertiesSet() {
133133
*/
134134
@Override
135135
protected boolean isHandler(Class<?> beanType) {
136-
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
137-
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
136+
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
138137
}
139138

140139
/**

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,7 @@ public RequestMappingInfo.BuilderConfiguration getBuilderConfiguration() {
266266
*/
267267
@Override
268268
protected boolean isHandler(Class<?> beanType) {
269-
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
270-
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
269+
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
271270
}
272271

273272
/**

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ static Object[][] handlerTypes() {
7878
// { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, true }, // CGLIB proxy
7979
// { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, false },
8080

81-
{ InterfaceController.class, true }, // JDK dynamic proxy
81+
// { InterfaceController.class, true }, // JDK dynamic proxy (gh-22154: no longer supported))
8282
{ InterfaceController.class, false },
8383

8484
{ ParameterizedInterfaceController.class, false }, // no AOP
@@ -250,6 +250,7 @@ interface MappingInterface {
250250
* <p>JDK Dynamic proxy: All annotations must be on the interface.
251251
* <p>Without AOP: Annotations can be on interface methods except parameter annotations.
252252
*/
253+
@Controller
253254
static class InterfaceController implements MappingInterface {
254255

255256
@Override
@@ -443,6 +444,7 @@ interface MappingGenericInterface<A, B, C> {
443444
* <p>All annotations can be on interface except parameter annotations.
444445
* <p>Cannot be used as JDK dynamic proxy since parameterized interface does not contain type information.
445446
*/
447+
@Controller
446448
static class ParameterizedInterfaceController implements MappingGenericInterface<String, Date, Date> {
447449

448450
@Override

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
* @author Rossen Stoyanchev
7878
* @author Sam Brannen
7979
*/
80+
@SuppressWarnings("unused")
8081
public class MvcUriComponentsBuilderTests {
8182

8283
private final MockHttpServletRequest request = new MockHttpServletRequest();
@@ -455,7 +456,8 @@ public void fromControllerWithPrefix() {
455456
this.request.setServerPort(9999);
456457
this.request.setContextPath("/base");
457458

458-
assertThat(fromController(PersonsAddressesController.class).buildAndExpand("123").toString()).isEqualTo("https://example.org:9999/base/api/people/123/addresses");
459+
assertThat(fromController(PersonsAddressesController.class).buildAndExpand("123").toString())
460+
.isEqualTo("https://example.org:9999/base/api/people/123/addresses");
459461
}
460462

461463
@Test
@@ -468,8 +470,12 @@ public void fromMethodWithPrefix() {
468470
this.request.setServerPort(9999);
469471
this.request.setContextPath("/base");
470472

471-
assertThat(fromMethodCall(on(PersonsAddressesController.class).getAddressesForCountry("DE"))
472-
.buildAndExpand("123").toString()).isEqualTo("https://example.org:9999/base/api/people/123/addresses/DE");
473+
String url = fromMethodCall(on(PersonsAddressesController.class)
474+
.getAddressesForCountry("DE"))
475+
.buildAndExpand("123")
476+
.toString();
477+
478+
assertThat(url).isEqualTo("https://example.org:9999/base/api/people/123/addresses/DE");
473479
}
474480

475481
private void initWebApplicationContext(Class<?> configClass) {
@@ -500,6 +506,7 @@ static class PersonControllerImpl implements PersonController {
500506
}
501507

502508

509+
@Controller
503510
@RequestMapping("/people/{id}/addresses")
504511
static class PersonsAddressesController {
505512

@@ -509,6 +516,7 @@ HttpEntity<Void> getAddressesForCountry(@PathVariable String country) {
509516
}
510517
}
511518

519+
@Controller
512520
@RequestMapping({"people"})
513521
static class PathWithoutLeadingSlashController {
514522

src/docs/asciidoc/web/webflux.adoc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,29 @@ directly to the response body versus view resolution and rendering with an HTML
13481348

13491349

13501350

1351+
[[webflux-ann-requestmapping-proxying]]
1352+
==== AOP Proxies
1353+
[.small]#<<web.adoc#mvc-ann-requestmapping-proxying, Web MVC>>#
1354+
1355+
In some cases, you may need to decorate a controller with an AOP proxy at runtime.
1356+
One example is if you choose to have `@Transactional` annotations directly on the
1357+
controller. When this is the case, for controllers specifically, we recommend
1358+
using class-based proxying. This is automatically the case with such annotations
1359+
directly on the controller.
1360+
1361+
If the controller implements an interface, and needs AOP proxying, you may need to
1362+
explicitly configure class-based proxying. For example, with `@EnableTransactionManagement`
1363+
you can change to `@EnableTransactionManagement(proxyTargetClass = true)`, and with
1364+
`<tx:annotation-driven/>` you can change to `<tx:annotation-driven proxy-target-class="true"/>`.
1365+
1366+
NOTE: Keep in mind that as of 6.0, with interface proxying, Spring MVC no longer detects
1367+
controllers based solely on a type-level `@RequestMapping` annotation on the interface.
1368+
Please, enable class based proxying, or otherwise the interface must also have an
1369+
`@Controller` annotation.
1370+
1371+
1372+
1373+
13511374
[[webflux-ann-requestmapping]]
13521375
=== Request Mapping
13531376
[.small]#<<web.adoc#mvc-ann-requestmapping, Web MVC>>#

src/docs/asciidoc/web/webmvc.adoc

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,17 +1512,23 @@ directly to the response body versus view resolution and rendering with an HTML
15121512

15131513
[[mvc-ann-requestmapping-proxying]]
15141514
==== AOP Proxies
1515+
[.small]#<<web-reactive.adoc#webflux-ann-requestmapping-proxying, WebFlux>>#
15151516

15161517
In some cases, you may need to decorate a controller with an AOP proxy at runtime.
15171518
One example is if you choose to have `@Transactional` annotations directly on the
15181519
controller. When this is the case, for controllers specifically, we recommend
1519-
using class-based proxying. This is typically the default choice with controllers.
1520-
However, if a controller must implement an interface that is not a Spring Context
1521-
callback (such as `InitializingBean`, `*Aware`, and others), you may need to explicitly
1522-
configure class-based proxying. For example, with `<tx:annotation-driven/>` you can
1523-
change to `<tx:annotation-driven proxy-target-class="true"/>`, and with
1524-
`@EnableTransactionManagement` you can change to
1525-
`@EnableTransactionManagement(proxyTargetClass = true)`.
1520+
using class-based proxying. This is automatically the case with such annotations
1521+
directly on the controller.
1522+
1523+
If the controller implements an interface, and needs AOP proxying, you may need to
1524+
explicitly configure class-based proxying. For example, with `@EnableTransactionManagement`
1525+
you can change to `@EnableTransactionManagement(proxyTargetClass = true)`, and with
1526+
`<tx:annotation-driven/>` you can change to `<tx:annotation-driven proxy-target-class="true"/>`.
1527+
1528+
NOTE: Keep in mind that as of 6.0, with interface proxying, Spring MVC no longer detects
1529+
controllers based solely on a type-level `@RequestMapping` annotation on the interface.
1530+
Please, enable class based proxying, or otherwise the interface must also have an
1531+
`@Controller` annotation.
15261532

15271533

15281534

0 commit comments

Comments
 (0)