From b55ab1119ea16f75b6a9873275c1fd9294cdc70a Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 31 Oct 2016 12:23:53 +0200 Subject: [PATCH] Sync argument resolution and HandlerMethod invocation HandlerMethodArgumentResolver is a non-blocking contract, however only implementations that read the request body require blocking. This commit introduces SyncMethodArgumentResolver as an extension of the non-blocking contract that allows synchronous implementations to use synchronous argument resolution. There is also a SyncInvocableHandlerMethod extension that uses only sync argument resolvers and allows a synchronous invocation. Issue: SPR-14543 --- .../result/method/InvocableHandlerMethod.java | 2 +- .../SyncHandlerMethodArgumentResolver.java | 54 ++++++++++++++ .../method/SyncInvocableHandlerMethod.java | 69 ++++++++++++++++++ ...> AbstractNamedValueArgumentResolver.java} | 4 +- ...bstractNamedValueSyncArgumentResolver.java | 73 +++++++++++++++++++ .../CookieValueMethodArgumentResolver.java | 17 +++-- ...ExpressionValueMethodArgumentResolver.java | 10 ++- .../annotation/ModelArgumentResolver.java | 10 +-- ...PathVariableMapMethodArgumentResolver.java | 12 ++- .../PathVariableMethodArgumentResolver.java | 16 ++-- ...equestAttributeMethodArgumentResolver.java | 10 ++- ...equestHeaderMapMethodArgumentResolver.java | 22 +++--- .../RequestHeaderMethodArgumentResolver.java | 12 +-- .../RequestMappingHandlerAdapter.java | 5 +- ...RequestParamMapMethodArgumentResolver.java | 24 +++--- .../RequestParamMethodArgumentResolver.java | 9 ++- .../ServerWebExchangeArgumentResolver.java | 31 ++++---- ...essionAttributeMethodArgumentResolver.java | 12 ++- .../WebSessionArgumentResolver.java | 61 ++++++++++++++++ .../method/InvocableHandlerMethodTests.java | 14 ++-- ...RequestMappingInfoHandlerMappingTests.java | 2 +- ...erverWebExchangeArgumentResolverTests.java | 2 - 22 files changed, 367 insertions(+), 104 deletions(-) create mode 100644 spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java create mode 100644 spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java rename spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/{AbstractNamedValueMethodArgumentResolver.java => AbstractNamedValueArgumentResolver.java} (98%) create mode 100644 spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java create mode 100644 spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java index 5d8337aeec..202264fb5b 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java @@ -87,7 +87,7 @@ public class InvocableHandlerMethod extends HandlerMethod { * @return Publisher that produces a single HandlerResult or an error signal; * never throws an exception */ - public Mono invokeForRequest(ServerWebExchange exchange, + public Mono invoke(ServerWebExchange exchange, BindingContext bindingContext, Object... providedArgs) { return resolveArguments(exchange, bindingContext, providedArgs).then(args -> { diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java new file mode 100644 index 0000000000..2a2df9c737 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncHandlerMethodArgumentResolver.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2015 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.reactive.result.method; + +import java.util.Optional; + +import reactor.core.publisher.Mono; + +import org.springframework.core.MethodParameter; +import org.springframework.web.server.ServerWebExchange; + + +/** + * An extension of {@link HandlerMethodArgumentResolver} for implementations + * that are synchronous in nature and do not block to resolve values. + * + * @author Rossen Stoyanchev + * @since 5.0 + */ +public interface SyncHandlerMethodArgumentResolver extends HandlerMethodArgumentResolver { + + @Override + default Mono resolveArgument(MethodParameter parameter, BindingContext context, + ServerWebExchange exchange) { + + Optional value = resolveArgumentValue(parameter, context, exchange); + return Mono.justOrEmpty(value); + } + + /** + * Resolve the method argument value synchronously returning an optional value. + * @param parameter the method parameter + * @param bindingContext the binding context to use + * @param exchange the current exchange + * @return the resolved value if any + */ + Optional resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, + ServerWebExchange exchange); + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java new file mode 100644 index 0000000000..c82ae7486d --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/SyncInvocableHandlerMethod.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.web.reactive.result.method; + +import java.lang.reflect.Method; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.reactive.HandlerResult; +import org.springframework.web.server.ServerWebExchange; + +/** + * An extension of {@code InvocableHandlerMethod} for use with + * {@link SyncHandlerMethodArgumentResolver}s which in turn enables synchronous + * handler method invocation via {@link #invokeForHandlerResult}. + * + * @author Rossen Stoyanchev + * @since 5.0 + */ +public class SyncInvocableHandlerMethod extends InvocableHandlerMethod { + + + public SyncInvocableHandlerMethod(HandlerMethod handlerMethod) { + super(handlerMethod); + } + + public SyncInvocableHandlerMethod(Object bean, Method method) { + super(bean, method); + } + + + /** + * Overloaded variant of the same setter from the base class that ensures + * all resolvers are {@link SyncHandlerMethodArgumentResolver}. + */ + @Override + public void setHandlerMethodArgumentResolvers(List resolvers) { + resolvers.forEach(resolver -> + Assert.isInstanceOf(SyncHandlerMethodArgumentResolver.class, resolver, + "Expected sync argument resolver: " + resolver.getClass().getName())); + super.setHandlerMethodArgumentResolvers(resolvers); + } + + /** + * Delegate to the base class {@link #invoke} and also wait for the result. + * Since all argument resolvers are synchronous this won't actually block. + */ + public HandlerResult invokeForHandlerResult(ServerWebExchange exchange, + BindingContext bindingContext, Object... providedArgs) { + + // This will not block + return super.invoke(exchange, bindingContext, providedArgs).block(); + } + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java similarity index 98% rename from spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java rename to spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java index d1e2a48eb4..50577e8639 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java @@ -53,7 +53,7 @@ import org.springframework.web.server.ServerWebInputException; * @author Rossen Stoyanchev * @since 5.0 */ -public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver { +public abstract class AbstractNamedValueArgumentResolver implements HandlerMethodArgumentResolver { private final ConfigurableBeanFactory configurableBeanFactory; @@ -67,7 +67,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle * and #{...} SpEL expressions in default values, or {@code null} if default * values are not expected to contain expressions */ - public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { + public AbstractNamedValueArgumentResolver(ConfigurableBeanFactory beanFactory) { this.configurableBeanFactory = beanFactory; this.expressionContext = (beanFactory != null ? new BeanExpressionContext(beanFactory, null) : null); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java new file mode 100644 index 0000000000..4933fd3fcb --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueSyncArgumentResolver.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.reactive.result.method.annotation; + +import java.util.Optional; + +import reactor.core.publisher.Mono; + +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.core.MethodParameter; +import org.springframework.web.reactive.result.method.BindingContext; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; +import org.springframework.web.server.ServerWebExchange; + +/** + * An extension of {@link AbstractNamedValueArgumentResolver} for named value + * resolvers that are synchronous and yet non-blocking. Sub-classes implement + * the synchronous {@link #resolveNamedValue} to which the asynchronous + * {@link #resolveName} delegates to by default. + * + * @author Rossen Stoyanchev + * @since 5.0 + */ +public abstract class AbstractNamedValueSyncArgumentResolver extends AbstractNamedValueArgumentResolver + implements SyncHandlerMethodArgumentResolver { + + + public AbstractNamedValueSyncArgumentResolver(ConfigurableBeanFactory beanFactory) { + super(beanFactory); + } + + + @Override + public Optional resolveArgumentValue(MethodParameter parameter, + BindingContext bindingContext, ServerWebExchange exchange) { + + // This will not block + Object value = resolveArgument(parameter, bindingContext, exchange).block(); + return Optional.ofNullable(value); + } + + @Override + protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) { + return Mono.justOrEmpty(resolveNamedValue(name, parameter, exchange)); + } + + /** + * An abstract method for synchronous resolution of method argument values + * that sub-classes must implement. + * @param name the name of the value being resolved + * @param parameter the method parameter to resolve to an argument value + * (pre-nested in case of a {@link java.util.Optional} declaration) + * @param exchange the current exchange + * @return the resolved argument value, if any + */ + protected abstract Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange); + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java index 5aa8c70dba..008d73de6a 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/CookieValueMethodArgumentResolver.java @@ -16,7 +16,7 @@ package org.springframework.web.reactive.result.method.annotation; -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; @@ -35,7 +35,7 @@ import org.springframework.web.server.ServerWebInputException; * @author Rossen Stoyanchev * @since 5.0 */ -public class CookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class CookieValueMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver { /** @@ -60,16 +60,19 @@ public class CookieValueMethodArgumentResolver extends AbstractNamedValueMethodA } @Override - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) { + protected Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange) { + HttpCookie cookie = exchange.getRequest().getCookies().getFirst(name); - if (HttpCookie.class.isAssignableFrom(parameter.getNestedParameterType())) { - return Mono.justOrEmpty(cookie); + Class paramType = parameter.getNestedParameterType(); + if (HttpCookie.class.isAssignableFrom(paramType)) { + return Optional.ofNullable(cookie); } else if (cookie != null) { - return Mono.justOrEmpty(cookie.getValue()); + return Optional.ofNullable(cookie.getValue()); } else { - return Mono.empty(); + return Optional.empty(); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java index 07985bc9f7..bd36f972a1 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ExpressionValueMethodArgumentResolver.java @@ -16,7 +16,7 @@ package org.springframework.web.reactive.result.method.annotation; -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.ConfigurableBeanFactory; @@ -33,7 +33,7 @@ import org.springframework.web.server.ServerWebExchange; * @author Rossen Stoyanchev * @since 5.0 */ -public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver { /** @@ -58,9 +58,11 @@ public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMet } @Override - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) { + protected Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange) { + // No name to resolve - return Mono.empty(); + return Optional.empty(); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java index 04da21cd7e..c964f8bb47 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelArgumentResolver.java @@ -15,12 +15,12 @@ */ package org.springframework.web.reactive.result.method.annotation; -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.core.MethodParameter; import org.springframework.ui.Model; import org.springframework.web.reactive.result.method.BindingContext; -import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; /** @@ -29,7 +29,7 @@ import org.springframework.web.server.ServerWebExchange; * @author Rossen Stoyanchev * @since 5.0 */ -public class ModelArgumentResolver implements HandlerMethodArgumentResolver { +public class ModelArgumentResolver implements SyncHandlerMethodArgumentResolver { @Override @@ -38,10 +38,10 @@ public class ModelArgumentResolver implements HandlerMethodArgumentResolver { } @Override - public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext, + public Optional resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { - return Mono.just(bindingContext.getModel()); + return Optional.of(bindingContext.getModel()); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java index db7cbcf84a..1953787523 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMapMethodArgumentResolver.java @@ -20,14 +20,12 @@ import java.util.Collections; import java.util.Map; import java.util.Optional; -import reactor.core.publisher.Mono; - import org.springframework.core.MethodParameter; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.reactive.result.method.BindingContext; -import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; /** @@ -40,7 +38,7 @@ import org.springframework.web.server.ServerWebExchange; * @since 5.0 * @see PathVariableMethodArgumentResolver */ -public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgumentResolver { +public class PathVariableMapMethodArgumentResolver implements SyncHandlerMethodArgumentResolver { @Override @@ -54,12 +52,12 @@ public class PathVariableMapMethodArgumentResolver implements HandlerMethodArgum * Return a Map with all URI template variables or an empty map. */ @Override - public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext, + public Optional resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) { String name = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; - Optional value = exchange.getAttribute(name); - return (value.isPresent() ? Mono.just(value.get()) : Mono.just(Collections.emptyMap())); + Object value = exchange.getAttribute(name).orElse(Collections.emptyMap()); + return Optional.of(value); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java index 274e2a6c61..edc497f4d8 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/PathVariableMethodArgumentResolver.java @@ -19,8 +19,6 @@ package org.springframework.web.reactive.result.method.annotation; import java.util.Map; import java.util.Optional; -import reactor.core.publisher.Mono; - import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; import org.springframework.core.convert.converter.Converter; @@ -51,7 +49,7 @@ import org.springframework.web.server.ServerWebExchange; * @since 5.0 * @see PathVariableMapMethodArgumentResolver */ -public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class PathVariableMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver { public PathVariableMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { @@ -79,14 +77,12 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod @Override @SuppressWarnings("unchecked") - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) { + protected Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange) { + String attributeName = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; - Optional optional = exchange.getAttribute(attributeName); - Object value = null; - if (optional.isPresent()) { - value = ((Map) optional.get()).get(name); - } - return Mono.justOrEmpty(value); + return exchange.getAttribute(attributeName) + .map(value -> ((Map) value).get(name)); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java index 670cb628a6..3b5b86f141 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestAttributeMethodArgumentResolver.java @@ -15,7 +15,7 @@ */ package org.springframework.web.reactive.result.method.annotation; -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; @@ -31,7 +31,7 @@ import org.springframework.web.server.ServerWebInputException; * @since 5.0 * @see SessionAttributeMethodArgumentResolver */ -public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver { public RequestAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { @@ -52,8 +52,10 @@ public class RequestAttributeMethodArgumentResolver extends AbstractNamedValueMe } @Override - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange){ - return Mono.justOrEmpty(exchange.getAttribute(name)); + protected Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange) { + + return exchange.getAttribute(name); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java index de0a387157..40ea3d7ecd 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMapMethodArgumentResolver.java @@ -17,15 +17,14 @@ package org.springframework.web.reactive.result.method.annotation; import java.util.Map; - -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.core.MethodParameter; import org.springframework.http.HttpHeaders; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.reactive.result.method.BindingContext; -import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; /** @@ -41,7 +40,7 @@ import org.springframework.web.server.ServerWebExchange; * @since 5.0 * @see RequestHeaderMethodArgumentResolver */ -public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgumentResolver { +public class RequestHeaderMapMethodArgumentResolver implements SyncHandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { @@ -50,16 +49,17 @@ public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgu } @Override - public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext, + public Optional resolveArgumentValue(MethodParameter parameter, BindingContext context, ServerWebExchange exchange) { HttpHeaders headers = exchange.getRequest().getHeaders(); - if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) { - return Mono.just(headers); - } - else { - return Mono.just(headers.toSingleValueMap()); - } + Object value = (isMultiValueMap(parameter) ? headers : headers.toSingleValueMap()); + return Optional.of(value); + } + + private boolean isMultiValueMap(MethodParameter parameter) { + Class paramType = parameter.getParameterType(); + return MultiValueMap.class.isAssignableFrom(paramType); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java index 6256a11c0f..5db034549d 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestHeaderMethodArgumentResolver.java @@ -18,8 +18,7 @@ package org.springframework.web.reactive.result.method.annotation; import java.util.List; import java.util.Map; - -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.core.MethodParameter; @@ -44,8 +43,7 @@ import org.springframework.web.server.ServerWebInputException; * @since 5.0 * @see RequestHeaderMapMethodArgumentResolver */ -public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - +public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver { /** * @param beanFactory a bean factory to use for resolving ${...} @@ -70,13 +68,15 @@ public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMetho } @Override - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) { + protected Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange) { + List headerValues = exchange.getRequest().getHeaders().get(name); Object result = null; if (headerValues != null) { result = (headerValues.size() == 1 ? headerValues.get(0) : headerValues); } - return Mono.justOrEmpty(result); + return Optional.ofNullable(result); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java index a346cdd3b5..572a931a60 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java @@ -192,6 +192,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory resolvers.add(new HttpEntityArgumentResolver(getMessageReaders(), adapterRegistry)); resolvers.add(new ModelArgumentResolver()); resolvers.add(new ServerWebExchangeArgumentResolver()); + resolvers.add(new WebSessionArgumentResolver()); // Custom resolvers if (getCustomArgumentResolvers() != null) { @@ -214,7 +215,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod); invocable.setHandlerMethodArgumentResolvers(getArgumentResolvers()); BindingContext bindingContext = new BindingContext(getWebBindingInitializer()); - return invocable.invokeForRequest(exchange, bindingContext) + return invocable.invoke(exchange, bindingContext) .map(result -> result.setExceptionHandler( ex -> handleException(ex, handlerMethod, bindingContext, exchange))) .otherwise(ex -> handleException( @@ -232,7 +233,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory } invocable.setHandlerMethodArgumentResolvers(getArgumentResolvers()); bindingContext.getModel().clear(); - return invocable.invokeForRequest(exchange, bindingContext, ex); + return invocable.invoke(exchange, bindingContext, ex); } catch (Throwable invocationEx) { if (logger.isWarnEnabled()) { diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java index d93490e701..d92602ac54 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java @@ -17,15 +17,14 @@ package org.springframework.web.reactive.result.method.annotation; import java.util.Map; - -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.core.MethodParameter; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.reactive.result.method.BindingContext; -import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; /** @@ -43,7 +42,7 @@ import org.springframework.web.server.ServerWebExchange; * @since 5.0 * @see RequestParamMethodArgumentResolver */ -public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver { +public class RequestParamMapMethodArgumentResolver implements SyncHandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { @@ -57,16 +56,17 @@ public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgum } @Override - public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext, + public Optional resolveArgumentValue(MethodParameter parameter, BindingContext context, ServerWebExchange exchange) { - Class paramType = parameter.getParameterType(); MultiValueMap queryParams = exchange.getRequest().getQueryParams(); - if (MultiValueMap.class.isAssignableFrom(paramType)) { - return Mono.just(queryParams); - } - else { - return Mono.just(queryParams.toSingleValueMap()); - } + Object value = (isMultiValueMap(parameter) ? queryParams : queryParams.toSingleValueMap()); + return Optional.of(value); } + + private boolean isMultiValueMap(MethodParameter parameter) { + Class paramType = parameter.getParameterType(); + return MultiValueMap.class.isAssignableFrom(paramType); + } + } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java index b15e94fbf2..368f52ffb1 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java @@ -18,6 +18,7 @@ package org.springframework.web.reactive.result.method.annotation; import java.util.List; import java.util.Map; +import java.util.Optional; import reactor.core.publisher.Mono; @@ -50,7 +51,7 @@ import org.springframework.web.server.ServerWebInputException; * @since 5.0 * @see RequestParamMapMethodArgumentResolver */ -public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncArgumentResolver { private final boolean useDefaultResolution; @@ -91,13 +92,15 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod } @Override - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange) { + protected Optional resolveNamedValue(String name, MethodParameter parameter, + ServerWebExchange exchange) { + List paramValues = exchange.getRequest().getQueryParams().get(name); Object result = null; if (paramValues != null) { result = (paramValues.size() == 1 ? paramValues.get(0) : paramValues); } - return Mono.justOrEmpty(result); + return Optional.ofNullable(result); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java index d600af0935..6a47cd35df 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java @@ -15,31 +15,32 @@ */ package org.springframework.web.reactive.result.method.annotation; -import reactor.core.publisher.Mono; +import java.util.Optional; import org.springframework.core.MethodParameter; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.reactive.result.method.BindingContext; -import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebSession; /** * Resolves ServerWebExchange-related method argument values of the following types: *
    *
  • {@link ServerWebExchange} *
  • {@link ServerHttpRequest} - *
  • {@link WebSession} *
  • {@link HttpMethod} *
  • {@link ServerHttpResponse} *
* + *

For the {@code WebSession} see {@link WebSessionArgumentResolver}. + * * @author Rossen Stoyanchev * @since 5.0 + * @see WebSessionArgumentResolver */ -public class ServerWebExchangeArgumentResolver implements HandlerMethodArgumentResolver { +public class ServerWebExchangeArgumentResolver implements SyncHandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { @@ -47,35 +48,33 @@ public class ServerWebExchangeArgumentResolver implements HandlerMethodArgumentR return (ServerWebExchange.class.isAssignableFrom(paramType) || ServerHttpRequest.class.isAssignableFrom(paramType) || ServerHttpResponse.class.isAssignableFrom(paramType) || - WebSession.class.isAssignableFrom(paramType) || HttpMethod.class == paramType); } @Override - public Mono resolveArgument(MethodParameter parameter, BindingContext bindingContext, + public Optional resolveArgumentValue(MethodParameter parameter, BindingContext context, ServerWebExchange exchange) { Class paramType = parameter.getParameterType(); + Object value; if (ServerWebExchange.class.isAssignableFrom(paramType)) { - return Mono.just(exchange); + value = exchange; } else if (ServerHttpRequest.class.isAssignableFrom(paramType)) { - return Mono.just(exchange.getRequest()); + value = exchange.getRequest(); } else if (ServerHttpResponse.class.isAssignableFrom(paramType)) { - return Mono.just(exchange.getResponse()); - } - else if (WebSession.class.isAssignableFrom(paramType)) { - return exchange.getSession().cast(Object.class); + value = exchange.getResponse(); } else if (HttpMethod.class == paramType) { - return Mono.just(exchange.getRequest().getMethod()); + value = exchange.getRequest().getMethod(); } else { // should never happen... - return Mono.error(new UnsupportedOperationException( - "Unknown parameter type: " + paramType + " in method: " + parameter.getMethod())); + throw new IllegalArgumentException( + "Unknown parameter type: " + paramType + " in method: " + parameter.getMethod()); } + return Optional.of(value); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java index 4fa1cd8771..27e5881865 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/SessionAttributeMethodArgumentResolver.java @@ -33,7 +33,7 @@ import org.springframework.web.server.ServerWebInputException; * @since 5.0 * @see RequestAttributeMethodArgumentResolver */ -public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueArgumentResolver { public SessionAttributeMethodArgumentResolver(ConfigurableBeanFactory beanFactory) { @@ -53,9 +53,13 @@ public class SessionAttributeMethodArgumentResolver extends AbstractNamedValueMe } @Override - protected Mono resolveName(String name, MethodParameter parameter, ServerWebExchange exchange){ - return exchange.getSession().map(session -> session.getAttribute(name)) - .filter(Optional::isPresent).map(Optional::get); + protected Mono resolveName(String name, MethodParameter parameter, + ServerWebExchange exchange) { + + return exchange.getSession() + .map(session -> session.getAttribute(name)) + .filter(Optional::isPresent) + .map(Optional::get); } @Override diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java new file mode 100644 index 0000000000..22e38a5281 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/WebSessionArgumentResolver.java @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.web.reactive.result.method.annotation; + +import java.util.Optional; + +import reactor.core.publisher.Mono; + +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.reactive.result.method.BindingContext; +import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebSession; + +/** + * Resolves method argument value of type {@link WebSession}. + * + * @author Rossen Stoyanchev + * @since 5.0 + * @see ServerWebExchangeArgumentResolver + */ +public class WebSessionArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return (WebSession.class.isAssignableFrom(parameter.getParameterType())); + } + + @Override + public Mono resolveArgument(MethodParameter parameter, BindingContext context, + ServerWebExchange exchange) { + + Class paramType = parameter.getParameterType(); + if (WebSession.class.isAssignableFrom(paramType)) { + return exchange.getSession().cast(Object.class); + } + else { + // should never happen... + throw new IllegalArgumentException( + "Unknown parameter type: " + paramType + " in method: " + parameter.getMethod()); + } + } + +} diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/InvocableHandlerMethodTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/InvocableHandlerMethodTests.java index d554707027..91f817ef36 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/InvocableHandlerMethodTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/InvocableHandlerMethodTests.java @@ -64,7 +64,7 @@ public class InvocableHandlerMethodTests { @Test public void invokeMethodWithNoArguments() throws Exception { InvocableHandlerMethod hm = handlerMethod("noArgs"); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); assertHandlerResultValue(mono, "success"); } @@ -73,7 +73,7 @@ public class InvocableHandlerMethodTests { public void invokeMethodWithNoValue() throws Exception { InvocableHandlerMethod hm = handlerMethod("singleArg"); addResolver(hm, Mono.empty()); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); assertHandlerResultValue(mono, "success:null"); } @@ -82,7 +82,7 @@ public class InvocableHandlerMethodTests { public void invokeMethodWithValue() throws Exception { InvocableHandlerMethod hm = handlerMethod("singleArg"); addResolver(hm, Mono.just("value1")); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); assertHandlerResultValue(mono, "success:value1"); } @@ -90,7 +90,7 @@ public class InvocableHandlerMethodTests { @Test public void noMatchingResolver() throws Exception { InvocableHandlerMethod hm = handlerMethod("singleArg"); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); ScriptedSubscriber.create().expectNextCount(0) .consumeErrorWith(error -> { @@ -105,7 +105,7 @@ public class InvocableHandlerMethodTests { public void resolverThrowsException() throws Exception { InvocableHandlerMethod hm = handlerMethod("singleArg"); addResolver(hm, Mono.error(new UnsupportedMediaTypeStatusException("boo"))); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); ScriptedSubscriber.create().expectNextCount(0) .consumeErrorWith(error -> { @@ -119,7 +119,7 @@ public class InvocableHandlerMethodTests { public void illegalArgumentExceptionIsWrappedWithInvocationDetails() throws Exception { InvocableHandlerMethod hm = handlerMethod("singleArg"); addResolver(hm, Mono.just(1)); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); ScriptedSubscriber.create().expectNextCount(0) .consumeErrorWith(error -> { @@ -134,7 +134,7 @@ public class InvocableHandlerMethodTests { @Test public void invocationTargetExceptionIsUnwrapped() throws Exception { InvocableHandlerMethod hm = handlerMethod("exceptionMethod"); - Mono mono = hm.invokeForRequest(this.exchange, new BindingContext()); + Mono mono = hm.invoke(this.exchange, new BindingContext()); ScriptedSubscriber.create().expectNextCount(0) .consumeErrorWith(error -> { diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMappingTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMappingTests.java index b0d464b4db..f9ea46c4e9 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMappingTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMappingTests.java @@ -380,7 +380,7 @@ public class RequestMappingInfoHandlerMappingTests { BindingContext bindingContext = new BindingContext(); InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod); - Mono mono = invocable.invokeForRequest(exchange, bindingContext); + Mono mono = invocable.invoke(exchange, bindingContext); HandlerResult result = mono.block(); assertNotNull(result); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java index 14a996a463..7d83767782 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java @@ -69,7 +69,6 @@ public class ServerWebExchangeArgumentResolverTests { assertTrue(this.resolver.supportsParameter(parameter(ServerWebExchange.class))); assertTrue(this.resolver.supportsParameter(parameter(ServerHttpRequest.class))); assertTrue(this.resolver.supportsParameter(parameter(ServerHttpResponse.class))); - assertTrue(this.resolver.supportsParameter(parameter(WebSession.class))); assertTrue(this.resolver.supportsParameter(parameter(HttpMethod.class))); assertFalse(this.resolver.supportsParameter(parameter(String.class))); } @@ -79,7 +78,6 @@ public class ServerWebExchangeArgumentResolverTests { testResolveArgument(parameter(ServerWebExchange.class), this.exchange); testResolveArgument(parameter(ServerHttpRequest.class), this.exchange.getRequest()); testResolveArgument(parameter(ServerHttpResponse.class), this.exchange.getResponse()); - testResolveArgument(parameter(WebSession.class), this.exchange.getSession().block()); testResolveArgument(parameter(HttpMethod.class), HttpMethod.GET); }