提交 172afb51 编写于 作者: R Rossen Stoyanchev

Polish AbstractView in WebFlux

上级 ffd7cffa
...@@ -20,9 +20,9 @@ import java.nio.charset.Charset; ...@@ -20,9 +20,9 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
...@@ -211,30 +211,27 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo ...@@ -211,30 +211,27 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo
* <p>The default implementation creates a combined output Map that includes * <p>The default implementation creates a combined output Map that includes
* model as well as static attributes with the former taking precedence. * model as well as static attributes with the former taking precedence.
*/ */
protected Mono<Map<String, Object>> getModelAttributes(@Nullable Map<String, ?> model, protected Mono<Map<String, Object>> getModelAttributes(
ServerWebExchange exchange) { @Nullable Map<String, ?> model, ServerWebExchange exchange) {
int size = (model != null ? model.size() : 0); int size = (model != null ? model.size() : 0);
Map<String, Object> attributes = new ConcurrentHashMap<>(size);
Map<String, Object> attributes = new LinkedHashMap<>(size);
if (model != null) { if (model != null) {
attributes.putAll(model); attributes.putAll(model);
} }
return resolveAsyncAttributes(attributes).thenReturn(attributes);
return resolveAsyncAttributes(attributes).then(Mono.just(attributes));
} }
/** /**
* By default, resolve async attributes supported by the * Use the configured {@link ReactiveAdapterRegistry} to adapt asynchronous
* {@link ReactiveAdapterRegistry} to their blocking counterparts. * model attributes to {@code Mono<T>} or {@code Mono<List<T>>} and resolve
* <p>View implementations capable of taking advantage of reactive types * them to actual values via {@link Mono#zip(Mono, Mono)}, so that when
* can override this method if needed. * the returned result {@code Mono} completes, the model has its asynchronous
* @return {@code Mono} for the completion of async attributes resolution * attributes replaced with synchronous values.
* @return result {@code Mono} that completes when the model is ready
*/ */
protected Mono<Void> resolveAsyncAttributes(Map<String, Object> model) { protected Mono<Void> resolveAsyncAttributes(Map<String, Object> model) {
List<String> names = new ArrayList<>(); List<Mono<?>> asyncAttributes = null;
List<Mono<?>> valueMonos = new ArrayList<>();
for (Map.Entry<String, ?> entry : model.entrySet()) { for (Map.Entry<String, ?> entry : model.entrySet()) {
Object value = entry.getValue(); Object value = entry.getValue();
if (value == null) { if (value == null) {
...@@ -242,35 +239,34 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo ...@@ -242,35 +239,34 @@ public abstract class AbstractView implements View, BeanNameAware, ApplicationCo
} }
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(null, value); ReactiveAdapter adapter = this.adapterRegistry.getAdapter(null, value);
if (adapter != null) { if (adapter != null) {
names.add(entry.getKey()); if (asyncAttributes == null) {
asyncAttributes = new ArrayList<>();
}
String name = entry.getKey();
if (adapter.isMultiValue()) { if (adapter.isMultiValue()) {
Flux<Object> fluxValue = Flux.from(adapter.toPublisher(value)); asyncAttributes.add(
valueMonos.add(fluxValue.collectList().defaultIfEmpty(Collections.emptyList())); Flux.from(adapter.toPublisher(value))
.collectList()
.doOnSuccess(result -> {
result = result != null ? result : Collections.emptyList();
model.put(name, result);
}));
} }
else { else {
Mono<Object> monoValue = Mono.from(adapter.toPublisher(value)); asyncAttributes.add(
valueMonos.add(monoValue.defaultIfEmpty(NO_VALUE)); Mono.from(adapter.toPublisher(value))
} .doOnSuccess(result -> {
if (result != null) {
model.put(name, result);
} }
else {
model.remove(name);
} }
}));
if (names.isEmpty()) {
return Mono.empty();
} }
return Mono.zip(valueMonos,
values -> {
for (int i=0; i < values.length; i++) {
if (values[i] != NO_VALUE) {
model.put(names.get(i), values[i]);
}
else {
model.remove(names.get(i));
} }
} }
return NO_VALUE; return asyncAttributes != null ? Mono.when(asyncAttributes) : Mono.empty();
})
.then();
} }
/** /**
......
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2019 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package org.springframework.web.reactive.result.view; package org.springframework.web.reactive.result.view;
import java.time.Duration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -54,8 +55,8 @@ public class AbstractViewTests { ...@@ -54,8 +55,8 @@ public class AbstractViewTests {
TestBean testBean1 = new TestBean("Bean1"); TestBean testBean1 = new TestBean("Bean1");
TestBean testBean2 = new TestBean("Bean2"); TestBean testBean2 = new TestBean("Bean2");
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put("attr1", Mono.just(testBean1)); attributes.put("attr1", Mono.just(testBean1).delayElement(Duration.ofMillis(10)));
attributes.put("attr2", Flux.just(testBean1, testBean2)); attributes.put("attr2", Flux.just(testBean1, testBean2).delayElements(Duration.ofMillis(10)));
attributes.put("attr3", Single.just(testBean2)); attributes.put("attr3", Single.just(testBean2));
attributes.put("attr4", Observable.just(testBean1, testBean2)); attributes.put("attr4", Observable.just(testBean1, testBean2));
attributes.put("attr5", Mono.empty()); attributes.put("attr5", Mono.empty());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册