|
17 | 17 | package org.springframework.web.reactive.result.view; |
18 | 18 |
|
19 | 19 | import java.util.ArrayList; |
| 20 | +import java.util.Collection; |
20 | 21 | import java.util.Collections; |
21 | 22 | import java.util.List; |
22 | 23 | import java.util.Locale; |
|
38 | 39 | import org.springframework.ui.Model; |
39 | 40 | import org.springframework.util.ClassUtils; |
40 | 41 | import org.springframework.util.StringUtils; |
| 42 | +import org.springframework.validation.BindingResult; |
| 43 | +import org.springframework.web.bind.WebExchangeDataBinder; |
41 | 44 | import org.springframework.web.bind.annotation.ModelAttribute; |
42 | 45 | import org.springframework.web.reactive.HandlerResult; |
43 | 46 | import org.springframework.web.reactive.HandlerResultHandler; |
44 | 47 | import org.springframework.web.reactive.accept.RequestedContentTypeResolver; |
45 | 48 | import org.springframework.web.reactive.result.AbstractHandlerResultHandler; |
| 49 | +import org.springframework.web.reactive.result.method.BindingContext; |
46 | 50 | import org.springframework.web.server.NotAcceptableStatusException; |
47 | 51 | import org.springframework.web.server.ServerWebExchange; |
48 | 52 | import org.springframework.web.util.HttpRequestPathHelper; |
@@ -241,6 +245,7 @@ else if (CharSequence.class.isAssignableFrom(clazz) && !hasModelAttributeAnnotat |
241 | 245 | } |
242 | 246 |
|
243 | 247 | return resolveAsyncAttributes(model.asMap()) |
| 248 | + .doOnSuccess(aVoid -> addBindingResult(result, exchange)) |
244 | 249 | .then(viewsMono) |
245 | 250 | .then(views -> render(views, model.asMap(), exchange)); |
246 | 251 | }); |
@@ -322,6 +327,24 @@ private Mono<Void> resolveAsyncAttributes(Map<String, Object> model) { |
322 | 327 | .then(); |
323 | 328 | } |
324 | 329 |
|
| 330 | + private void addBindingResult(HandlerResult result, ServerWebExchange exchange) { |
| 331 | + BindingContext context = result.getBindingContext(); |
| 332 | + Map<String, Object> model = context.getModel().asMap(); |
| 333 | + model.keySet().stream() |
| 334 | + .filter(name -> isBindingCandidate(name, model.get(name))) |
| 335 | + .filter(name -> !model.containsKey(BindingResult.MODEL_KEY_PREFIX + name)) |
| 336 | + .forEach(name -> { |
| 337 | + WebExchangeDataBinder binder = context.createDataBinder(exchange, model.get(name), name); |
| 338 | + model.put(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); |
| 339 | + }); |
| 340 | + } |
| 341 | + |
| 342 | + private boolean isBindingCandidate(String name, Object value) { |
| 343 | + return !name.startsWith(BindingResult.MODEL_KEY_PREFIX) && value != null && |
| 344 | + !value.getClass().isArray() && !(value instanceof Collection) && |
| 345 | + !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass()); |
| 346 | + } |
| 347 | + |
325 | 348 | private Mono<? extends Void> render(List<View> views, Map<String, Object> model, |
326 | 349 | ServerWebExchange exchange) { |
327 | 350 |
|
|
0 commit comments