Reject ModelMap argument types in WebFlux

Prior to this commit, if ModelMap was used as an argument type in a
WebFlux controller method, the user encountered an exception similar to
the following.

java.lang.IllegalStateException: argument type mismatch
  Controller [example.SampleController]
  Method [java.lang.String example.SampleController.index(org.springframework.ui.ModelMap)] with argument values:
  [0] [type=org.springframework.validation.support.BindingAwareConcurrentModel] [value={}]

However, the above error message is a bit cryptic since the error
occurs while attempting to invoke the controller method with an
instance of BindingAwareConcurrentModel which is not compatible with
ModelMap. More importantly, this error message does not explicitly
convey to the user that a ModelMap is not supported.

This commit improve the diagnostics for the user in such scenarios by
rejecting the use of ModelMap upfront in WebFlux.

Consequently, for the same use case as above, the user now encounters
an exception similar to the following.

java.lang.IllegalStateException:
  Could not resolve parameter [0] in
  java.lang.String example.SampleController.index(org.springframework.ui.ModelMap):
  No suitable resolver

Closes gh-33109
This commit is contained in:
Sam Brannen
2024-06-27 16:16:48 +02:00
parent 053af5f75b
commit d902bd7696
3 changed files with 32 additions and 16 deletions

View File

@@ -32,12 +32,14 @@ import org.springframework.web.testfixture.method.ResolvableMethod;
import org.springframework.web.testfixture.server.MockServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest.get;
/**
* Tests for {@link ModelMethodArgumentResolver}.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
*/
class ModelMethodArgumentResolverTests {
@@ -52,11 +54,11 @@ class ModelMethodArgumentResolverTests {
@Test
void supportsParameter() {
assertThat(this.resolver.supportsParameter(this.resolvable.arg(Model.class))).isTrue();
assertThat(this.resolver.supportsParameter(this.resolvable.arg(ModelMap.class))).isTrue();
assertThat(this.resolver.supportsParameter(
this.resolvable.annotNotPresent().arg(Map.class, String.class, Object.class))).isTrue();
assertThat(this.resolver.supportsParameter(this.resolvable.arg(Object.class))).isFalse();
assertThat(this.resolver.supportsParameter(this.resolvable.arg(ModelMap.class))).isFalse();
assertThat(this.resolver.supportsParameter(
this.resolvable.annotPresent(RequestBody.class).arg(Map.class, String.class, Object.class))).isFalse();
}
@@ -65,7 +67,13 @@ class ModelMethodArgumentResolverTests {
void resolveArgument() {
testResolveArgument(this.resolvable.arg(Model.class));
testResolveArgument(this.resolvable.annotNotPresent().arg(Map.class, String.class, Object.class));
testResolveArgument(this.resolvable.arg(ModelMap.class));
assertThatIllegalStateException()
.isThrownBy(() -> testResolveArgument(this.resolvable.arg(Object.class)))
.withMessage("Unexpected method parameter type: " + Object.class.getName());
assertThatIllegalStateException()
.isThrownBy(() -> testResolveArgument(this.resolvable.arg(ModelMap.class)))
.withMessage("Unexpected method parameter type: " + ModelMap.class.getName());
}
private void testResolveArgument(MethodParameter parameter) {