Further refactoring of ReactiveAdapter/Registry

Simplify getAdapterFrom/To into a single getAdapter method that looks
for an exact match by type first and then isAssignableFrom.

Also expose shortcut methods in ReactiveAdapter to minimize the need
for access to the ReactiveTypeDescriptor.

Issue: SPR-14902
This commit is contained in:
Rossen Stoyanchev
2016-11-28 12:43:22 -05:00
parent adb80f4099
commit 5651c2180e
11 changed files with 136 additions and 99 deletions

View File

@@ -112,7 +112,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
BindingContext bindingContext, ServerWebExchange exchange) {
ResolvableType bodyType = ResolvableType.forMethodParameter(bodyParameter);
ReactiveAdapter adapter = getAdapterRegistry().getAdapterTo(bodyType.resolve());
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(bodyType.resolve());
ResolvableType elementType = ResolvableType.forMethodParameter(bodyParameter);
if (adapter != null) {
@@ -130,7 +130,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
if (reader.canRead(elementType, mediaType)) {
Map<String, Object> readHints = Collections.emptyMap();
if (adapter != null && adapter.getDescriptor().isMultiValue()) {
if (adapter != null && adapter.isMultiValue()) {
Flux<?> flux;
if (reader instanceof ServerHttpMessageReader) {
ServerHttpMessageReader<?> serverReader = ((ServerHttpMessageReader<?>) reader);
@@ -186,7 +186,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
}
protected boolean checkRequired(ReactiveAdapter adapter, boolean isBodyRequired) {
return adapter != null && !adapter.getDescriptor().supportsEmpty() || isBodyRequired;
return adapter != null && !adapter.supportsEmpty() || isBodyRequired;
}
protected ServerWebInputException getRequiredBodyError(MethodParameter parameter) {

View File

@@ -95,19 +95,19 @@ public abstract class AbstractMessageWriterResultHandler extends AbstractHandler
ResolvableType valueType = ResolvableType.forMethodParameter(bodyParameter);
Class<?> valueClass = valueType.resolve();
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(valueClass, body);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(valueClass, body);
Publisher<?> publisher;
ResolvableType elementType;
if (adapter != null) {
publisher = adapter.toPublisher(body);
elementType = adapter.getDescriptor().isNoValue() ?
ResolvableType.forClass(Void.class) :
valueType.getGeneric(0);
elementType = adapter.isNoValue() ?
ResolvableType.forClass(Void.class) : valueType.getGeneric(0);
}
else {
publisher = Mono.justOrEmpty(body);
elementType = (valueClass == null && body != null ? ResolvableType.forInstance(body) : valueType);
elementType = (valueClass == null && body != null ?
ResolvableType.forInstance(body) : valueType);
}
if (void.class == elementType.getRawClass() || Void.class == elementType.getRawClass()) {

View File

@@ -145,7 +145,7 @@ class BindingContextFactory {
}
ResolvableType type = result.getReturnType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(type.getRawClass(), value);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.getRawClass(), value);
Class<?> valueType = (adapter != null ? type.resolveGeneric(0) : type.resolve());
if (Void.class.equals(valueType) || void.class.equals(valueType)) {

View File

@@ -102,9 +102,9 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
Class<?> attributeType = attributeParam.getParameterType();
ResolvableType type = ResolvableType.forMethodParameter(attributeParam);
ReactiveAdapter adapterTo = getAdapterRegistry().getAdapterTo(type.resolve());
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.resolve());
Assert.isNull(adapterTo, "Errors/BindingResult cannot be used with an async model attribute. " +
Assert.isNull(adapter, "Errors/BindingResult cannot be used with an async model attribute. " +
"Either declare the model attribute without the async wrapper type " +
"or handle WebExchangeBindException through the async type.");

View File

@@ -105,10 +105,9 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
}
if (this.useDefaultResolution) {
Class<?> clazz = parameter.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(clazz);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(clazz);
if (adapter != null) {
ReactiveTypeDescriptor descriptor = adapter.getDescriptor();
if (descriptor.isNoValue() || descriptor.isMultiValue()) {
if (adapter.isNoValue() || adapter.isMultiValue()) {
return false;
}
clazz = ResolvableType.forMethodParameter(parameter).getGeneric(0).getRawClass();
@@ -123,8 +122,8 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
ServerWebExchange exchange) {
ResolvableType type = ResolvableType.forMethodParameter(parameter);
ReactiveAdapter adapterTo = getAdapterRegistry().getAdapterTo(type.resolve());
Class<?> valueType = (adapterTo != null ? type.resolveGeneric(0) : parameter.getParameterType());
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type.resolve());
Class<?> valueType = (adapter != null ? type.resolveGeneric(0) : parameter.getParameterType());
String name = getAttributeName(valueType, parameter);
Mono<?> valueMono = getAttributeMono(name, valueType, parameter, context, exchange);
@@ -145,8 +144,8 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
})
.then(Mono.fromCallable(() -> {
BindingResult errors = binder.getBindingResult();
if (adapterTo != null) {
return adapterTo.fromPublisher(errors.hasErrors() ?
if (adapter != null) {
return adapter.fromPublisher(errors.hasErrors() ?
Mono.error(new WebExchangeBindException(parameter, errors)) :
Mono.just(value));
}
@@ -177,10 +176,9 @@ public class ModelAttributeMethodArgumentResolver implements HandlerMethodArgume
attribute = createAttribute(attributeName, attributeType, param, context, exchange);
}
if (attribute != null) {
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapterFrom(null, attribute);
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapter(null, attribute);
if (adapterFrom != null) {
ReactiveTypeDescriptor descriptor = adapterFrom.getDescriptor();
Assert.isTrue(!descriptor.isMultiValue(), "Data binding supports single-value async types.");
Assert.isTrue(!adapterFrom.isMultiValue(), "Data binding supports single-value async types.");
return Mono.from(adapterFrom.toPublisher(attribute));
}
}

View File

@@ -17,7 +17,6 @@
package org.springframework.web.reactive.result.method.annotation;
import java.util.List;
import java.util.Optional;
import reactor.core.publisher.Mono;
@@ -103,8 +102,8 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
return true;
}
else {
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(rawClass, result.getReturnValue());
if (adapter != null && !adapter.getDescriptor().isNoValue()) {
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(rawClass, result.getReturnValue());
if (adapter != null && !adapter.isNoValue()) {
ResolvableType genericType = result.getReturnType().getGeneric(0);
if (HttpEntity.class.isAssignableFrom(genericType.getRawClass())) {
return true;

View File

@@ -25,7 +25,6 @@ import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ReactiveTypeDescriptor;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -91,11 +90,8 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
return true;
}
else {
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(returnType, result.getReturnValue());
if (adapter != null &&
!adapter.getDescriptor().isMultiValue() &&
!adapter.getDescriptor().isNoValue()) {
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(returnType, result.getReturnValue());
if (adapter != null && !adapter.isMultiValue() && !adapter.isNoValue()) {
ResolvableType genericType = result.getReturnType().getGeneric(0);
return isSupportedType(genericType.getRawClass());
}
@@ -118,11 +114,10 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
Optional<Object> optionalValue = result.getReturnValue();
Class<?> rawClass = returnType.getRawClass();
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(rawClass, optionalValue);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(rawClass, optionalValue);
if (adapter != null) {
ReactiveTypeDescriptor descriptor = adapter.getDescriptor();
Assert.isTrue(!descriptor.isMultiValue(), "Only a single ResponseEntity supported.");
Assert.isTrue(!adapter.isMultiValue(), "Only a single ResponseEntity supported.");
returnValueMono = Mono.from(adapter.toPublisher(optionalValue));
bodyType = new MethodParameter(result.getReturnTypeSource());
bodyType.increaseNestingLevel();

View File

@@ -33,7 +33,6 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.Ordered;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ReactiveTypeDescriptor;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.MediaType;
@@ -154,9 +153,9 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
return true;
}
Optional<Object> optional = result.getReturnValue();
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(clazz, optional);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(clazz, optional);
if (adapter != null) {
if (adapter.getDescriptor().isNoValue()) {
if (adapter.isNoValue()) {
return true;
}
else {
@@ -190,15 +189,14 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
ResolvableType parameterType = result.getReturnType();
Optional<Object> optional = result.getReturnValue();
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(parameterType.getRawClass(), optional);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameterType.getRawClass(), optional);
if (adapter != null) {
ReactiveTypeDescriptor descriptor = adapter.getDescriptor();
Assert.isTrue(!descriptor.isMultiValue(), "Only single-value async return type supported.");
Assert.isTrue(!adapter.isMultiValue(), "Only single-value async return type supported.");
returnValueMono = optional
.map(value -> Mono.from(adapter.toPublisher(value)))
.orElse(Mono.empty());
elementType = !adapter.getDescriptor().isNoValue() ?
elementType = !adapter.isNoValue() ?
parameterType.getGeneric(0) : ResolvableType.forClass(Void.class);
}
else {
@@ -301,10 +299,10 @@ public class ViewResolutionResultHandler extends AbstractHandlerResultHandler
List<Mono<?>> valueMonos = new ArrayList<>();
for (Map.Entry<String, ?> entry : model.entrySet()) {
ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(null, entry.getValue());
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(null, entry.getValue());
if (adapter != null) {
names.add(entry.getKey());
if (adapter.getDescriptor().isMultiValue()) {
if (adapter.isMultiValue()) {
Flux<Object> value = Flux.from(adapter.toPublisher(entry.getValue()));
valueMonos.add(value.collectList().defaultIfEmpty(Collections.emptyList()));
}