diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java index 28abd49dfd..7f6a1dea9f 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,7 +33,8 @@ import org.springframework.web.server.ServerWebExchange; /** * Resolve {@link Errors} or {@link BindingResult} method arguments. - * An {@code Errors} argument is expected to appear immediately after the + * + *

An {@code Errors} argument is expected to appear immediately after the * model attribute in the method signature. * * @author Rossen Stoyanchev @@ -86,7 +87,7 @@ public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverS "Either declare the @ModelAttribute without an async wrapper type or " + "handle a WebExchangeBindException error signal through the async type."); - ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class); + ModelAttribute ann = attributeParam.getParameterAnnotation(ModelAttribute.class); String name = (ann != null && StringUtils.hasText(ann.value()) ? ann.value() : Conventions.getVariableNameForParameter(attributeParam)); Object errors = context.getModel().asMap().get(BindingResult.MODEL_KEY_PREFIX + name); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolverTests.java index 38467b7107..499a5b85da 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolverTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,6 +81,20 @@ class ErrorsMethodArgumentResolverTests { assertThat(actual).isSameAs(bindingResult); } + @Test + void resolveOnBindingResultAndModelAttributeWithCustomName() { + BindingResult bindingResult = createBindingResult(new Foo(), "custom"); + this.bindingContext.getModel().asMap().put(BindingResult.MODEL_KEY_PREFIX + "custom", bindingResult); + + ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handleWithCustomModelAttributeName").build(); + + MethodParameter parameter = testMethod.arg(Errors.class); + Object actual = this.resolver.resolveArgument(parameter, this.bindingContext, this.exchange) + .block(Duration.ofMillis(5000)); + + assertThat(actual).isSameAs(bindingResult); + } + private BindingResult createBindingResult(Foo target, String name) { DataBinder binder = this.bindingContext.createDataBinder(this.exchange, target, name); return binder.getBindingResult(); @@ -98,6 +112,20 @@ class ErrorsMethodArgumentResolverTests { assertThat(actual).isSameAs(bindingResult); } + @Test + void resolveWithMonoOnBindingResultAndModelAttributeWithCustomName() { + BindingResult bindingResult = createBindingResult(new Foo(), "custom"); + this.bindingContext.getModel().asMap().put(BindingResult.MODEL_KEY_PREFIX + "custom", Mono.just(bindingResult)); + + ResolvableMethod testMethod = ResolvableMethod.on(getClass()).named("handleWithCustomModelAttributeName").build(); + + MethodParameter parameter = testMethod.arg(Errors.class); + Object actual = this.resolver.resolveArgument(parameter, this.bindingContext, this.exchange) + .block(Duration.ofMillis(5000)); + + assertThat(actual).isSameAs(bindingResult); + } + @Test void resolveWithMonoOnBindingResultAndModelAttribute() { MethodParameter parameter = this.testMethod.arg(BindingResult.class); @@ -150,4 +178,14 @@ class ErrorsMethodArgumentResolverTests { String string) { } + @SuppressWarnings("unused") + void handleWithCustomModelAttributeName( + @ModelAttribute("custom") Foo foo, + Errors errors, + @ModelAttribute Mono fooMono, + BindingResult bindingResult, + Mono errorsMono, + String string) { + } + }