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 72ca77047f..89f24aa840 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 @@ -217,6 +217,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory // Type-based argument resolution resolvers.add(new HttpEntityArgumentResolver(getMessageReaders(), getValidator(), adapterRegistry)); resolvers.add(new ModelArgumentResolver()); + resolvers.add(new ServerWebExchangeArgumentResolver()); // Custom resolvers if (getCustomArgumentResolvers() != null) { 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 new file mode 100644 index 0000000000..7a8d09e622 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java @@ -0,0 +1,79 @@ +/* + * 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 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.ui.ModelMap; +import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebSession; + +/** + * Resolves ServerWebExchange-related method argument values of the following types: + * + * + * @author Rossen Stoyanchev + * @since 5.0 + */ +public class ServerWebExchangeArgumentResolver implements HandlerMethodArgumentResolver { + + @Override + public boolean supportsParameter(MethodParameter parameter) { + Class paramType = parameter.getParameterType(); + 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, ModelMap model, ServerWebExchange exchange) { + Class paramType = parameter.getParameterType(); + if (ServerWebExchange.class.isAssignableFrom(paramType)) { + return Mono.just(exchange); + } + else if (ServerHttpRequest.class.isAssignableFrom(paramType)) { + return Mono.just(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); + } + else if (HttpMethod.class == paramType) { + return Mono.just(exchange.getRequest().getMethod()); + } + else { + // should never happen... + return Mono.error(new UnsupportedOperationException( + "Unknown parameter type: " + paramType + " in method: " + parameter.getMethod())); + } + } + +} 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 new file mode 100644 index 0000000000..852f45315c --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java @@ -0,0 +1,108 @@ +/* + * 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.net.URI; + +import org.junit.Before; +import org.junit.Test; +import reactor.core.publisher.Mono; + +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpMethod; +import org.springframework.http.server.reactive.MockServerHttpRequest; +import org.springframework.http.server.reactive.MockServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.ui.ModelMap; +import org.springframework.web.reactive.result.ResolvableMethod; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebSession; +import org.springframework.web.server.adapter.DefaultServerWebExchange; +import org.springframework.web.server.session.WebSessionManager; + +import static junit.framework.TestCase.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Unit tests for {@link ServerWebExchangeArgumentResolver}. + * @author Rossen Stoyanchev + */ +public class ServerWebExchangeArgumentResolverTests { + + private ServerWebExchangeArgumentResolver resolver = new ServerWebExchangeArgumentResolver(); + + private ServerWebExchange exchange; + + private ResolvableMethod testMethod = ResolvableMethod.onClass(getClass()).name("handle"); + + + @Before + public void setUp() throws Exception { + ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path")); + ServerHttpResponse response = new MockServerHttpResponse(); + + WebSession session = mock(WebSession.class); + WebSessionManager sessionManager = mock(WebSessionManager.class); + when(sessionManager.getSession(any())).thenReturn(Mono.just(session)); + + this.exchange = new DefaultServerWebExchange(request, response, sessionManager); + } + + @Test + public void supportsParameter() throws Exception { + 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))); + } + + @Test + public void resolveArgument() throws Exception { + 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); + } + + private void testResolveArgument(MethodParameter parameter, Object expected) { + Mono mono = this.resolver.resolveArgument(parameter, new ModelMap(), this.exchange); + assertSame(expected, mono.block()); + } + + private MethodParameter parameter(Class parameterType) { + return this.testMethod.resolveParam(parameter -> parameterType.equals(parameter.getParameterType())); + } + + + @SuppressWarnings("unused") + public void handle( + ServerWebExchange exchange, + ServerHttpRequest request, + ServerHttpResponse response, + WebSession session, + HttpMethod httpMethod, + String s) { + } + +}