Skip to content

Commit

Permalink
Support name attribute in @ModelAttribute in WebFlux
Browse files Browse the repository at this point in the history
Prior to this commit, the `name` attribute in @ModelAttribute was not
supported when using WebFlux. This is because MethodParameter was used
instead of SynthesizingMethodParameter when retrieving the
@ModelAttribute annotation. In other words, @AliasFor was not honored
because the annotation was not synthesized. Consequently, only the
`value` attribute was supported in WebFlux when specifying a custom name
via @ModelAttribute.

This commit fixes this by using SynthesizingMethodParameter to retrieve
the @ModelAttribute annotation.

Closes gh-28423
  • Loading branch information
sbrannen committed May 7, 2022
1 parent 64c96c5 commit 7dd622b
Show file tree
Hide file tree
Showing 2 changed files with 6 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
Expand All @@ -38,6 +39,7 @@
* model attribute in the method signature.
*
* @author Rossen Stoyanchev
* @author Sam Brannen
* @since 5.0
*/
public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverSupport {
Expand Down Expand Up @@ -79,7 +81,7 @@ private Object getErrors(MethodParameter parameter, BindingContext context) {
"Errors argument must be declared immediately after a model attribute argument");

int index = parameter.getParameterIndex() - 1;
MethodParameter attributeParam = MethodParameter.forExecutable(parameter.getExecutable(), index);
MethodParameter attributeParam = SynthesizingMethodParameter.forExecutable(parameter.getExecutable(), index);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(attributeParam.getParameterType());

Assert.state(adapter == null, "An @ModelAttribute and an Errors/BindingResult argument " +
Expand All @@ -88,8 +90,8 @@ private Object getErrors(MethodParameter parameter, BindingContext context) {
"handle a WebExchangeBindException error signal through the async type.");

ModelAttribute ann = attributeParam.getParameterAnnotation(ModelAttribute.class);
String name = (ann != null && StringUtils.hasText(ann.value()) ?
ann.value() : Conventions.getVariableNameForParameter(attributeParam));
String name = (ann != null && StringUtils.hasText(ann.name()) ? ann.name() :
Conventions.getVariableNameForParameter(attributeParam));
Object errors = context.getModel().asMap().get(BindingResult.MODEL_KEY_PREFIX + name);

Assert.state(errors != null, () -> "An Errors/BindingResult argument is expected " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ void handle(

@SuppressWarnings("unused")
void handleWithCustomModelAttributeName(
@ModelAttribute("custom") Foo foo,
@ModelAttribute(name = "custom") Foo foo,
Errors errors,
@ModelAttribute Mono<Foo> fooMono,
BindingResult bindingResult,
Expand Down

0 comments on commit 7dd622b

Please sign in to comment.