diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java index 24b3d90d02..c9e8433bcb 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolver.java @@ -16,12 +16,19 @@ package org.springframework.web.reactive.result.method.annotation; +import java.time.ZoneId; +import java.util.Locale; +import java.util.TimeZone; + +import org.springframework.context.i18n.LocaleContext; +import org.springframework.context.i18n.TimeZoneAwareLocaleContext; import org.springframework.core.MethodParameter; import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.lang.Nullable; import org.springframework.web.reactive.BindingContext; import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport; import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; @@ -36,6 +43,9 @@ import org.springframework.web.util.UriComponentsBuilder; *
  • {@link ServerHttpRequest} *
  • {@link ServerHttpResponse} *
  • {@link HttpMethod} + *
  • {@link Locale} + *
  • {@link TimeZone} + *
  • {@link ZoneId} *
  • {@link UriBuilder} or {@link UriComponentsBuilder} -- for building URL's * relative to the current request * @@ -63,6 +73,9 @@ public class ServerWebExchangeArgumentResolver extends HandlerMethodArgumentReso ServerHttpRequest.class.isAssignableFrom(type) || ServerHttpResponse.class.isAssignableFrom(type) || HttpMethod.class == type || + Locale.class == type || + TimeZone.class == type || + ZoneId.class == type || UriBuilder.class == type || UriComponentsBuilder.class == type); } @@ -83,6 +96,19 @@ public class ServerWebExchangeArgumentResolver extends HandlerMethodArgumentReso else if (HttpMethod.class == paramType) { return exchange.getRequest().getMethod(); } + else if (Locale.class == paramType) { + return exchange.getLocaleContext().getLocale(); + } + else if (TimeZone.class == paramType) { + LocaleContext localeContext = exchange.getLocaleContext(); + TimeZone timeZone = getTimeZone(localeContext); + return timeZone != null ? timeZone : TimeZone.getDefault(); + } + else if (ZoneId.class == paramType) { + LocaleContext localeContext = exchange.getLocaleContext(); + TimeZone timeZone = getTimeZone(localeContext); + return timeZone != null ? timeZone.toZoneId() : ZoneId.systemDefault(); + } else if (UriBuilder.class == paramType || UriComponentsBuilder.class == paramType) { return UriComponentsBuilder.fromHttpRequest(exchange.getRequest()); } @@ -93,4 +119,13 @@ public class ServerWebExchangeArgumentResolver extends HandlerMethodArgumentReso } } + @Nullable + private TimeZone getTimeZone(LocaleContext localeContext) { + TimeZone timeZone = null; + if (localeContext instanceof TimeZoneAwareLocaleContext) { + timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone(); + } + return timeZone; + } + } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java index 4edfa5b265..5ba3f13136 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ServerWebExchangeArgumentResolverTests.java @@ -16,6 +16,10 @@ package org.springframework.web.reactive.result.method.annotation; +import java.time.ZoneId; +import java.util.Locale; +import java.util.TimeZone; + import org.junit.Test; import reactor.core.publisher.Mono; @@ -60,6 +64,9 @@ public class ServerWebExchangeArgumentResolverTests { assertTrue(this.resolver.supportsParameter(this.testMethod.arg(ServerHttpRequest.class))); assertTrue(this.resolver.supportsParameter(this.testMethod.arg(ServerHttpResponse.class))); assertTrue(this.resolver.supportsParameter(this.testMethod.arg(HttpMethod.class))); + assertTrue(this.resolver.supportsParameter(this.testMethod.arg(Locale.class))); + assertTrue(this.resolver.supportsParameter(this.testMethod.arg(TimeZone.class))); + assertTrue(this.resolver.supportsParameter(this.testMethod.arg(ZoneId.class))); assertTrue(this.resolver.supportsParameter(this.testMethod.arg(UriComponentsBuilder.class))); assertTrue(this.resolver.supportsParameter(this.testMethod.arg(UriBuilder.class))); @@ -81,6 +88,13 @@ public class ServerWebExchangeArgumentResolverTests { testResolveArgument(this.testMethod.arg(ServerHttpRequest.class), this.exchange.getRequest()); testResolveArgument(this.testMethod.arg(ServerHttpResponse.class), this.exchange.getResponse()); testResolveArgument(this.testMethod.arg(HttpMethod.class), HttpMethod.GET); + testResolveArgument(this.testMethod.arg(TimeZone.class), TimeZone.getDefault()); + testResolveArgument(this.testMethod.arg(ZoneId.class), ZoneId.systemDefault()); + } + + private void testResolveArgument(MethodParameter parameter, Object expected) { + Mono mono = this.resolver.resolveArgument(parameter, new BindingContext(), this.exchange); + assertEquals(expected, mono.block()); } @Test @@ -93,10 +107,6 @@ public class ServerWebExchangeArgumentResolverTests { assertEquals("/path/next", ((UriComponentsBuilder) value).path("/next").build().toUriString()); } - private void testResolveArgument(MethodParameter parameter, Object expected) { - Mono mono = this.resolver.resolveArgument(parameter, new BindingContext(), this.exchange); - assertSame(expected, mono.block()); - } @SuppressWarnings("unused") @@ -106,6 +116,9 @@ public class ServerWebExchangeArgumentResolverTests { ServerHttpResponse response, WebSession session, HttpMethod httpMethod, + Locale locale, + TimeZone timeZone, + ZoneId zoneId, UriComponentsBuilder uriComponentsBuilder, UriBuilder uriBuilder, String s, diff --git a/src/docs/asciidoc/web/webflux.adoc b/src/docs/asciidoc/web/webflux.adoc index bba75eb32f..8e0ef3e69b 100644 --- a/src/docs/asciidoc/web/webflux.adoc +++ b/src/docs/asciidoc/web/webflux.adoc @@ -873,15 +873,13 @@ Supports reactive types. |`org.springframework.http.HttpMethod` |The HTTP method of the request. -// TODO: not supported -// |`java.util.Locale` -// |The current request locale, determined by the most specific `LocaleResolver` available, in -// effect, the configured `LocaleResolver`/`LocaleContextResolver`. - -// TODO: not supported -//|Java 6+: `java.util.TimeZone` + -//Java 8+: `java.time.ZoneId` -//|The time zone associated with the current request, as determined by a `LocaleContextResolver`. + |`java.util.Locale` + |The current request locale, determined by the most specific `LocaleResolver` available, in + effect, the configured `LocaleResolver`/`LocaleContextResolver`. + +|Java 6+: `java.util.TimeZone` + +Java 8+: `java.time.ZoneId` +|The time zone associated with the current request, as determined by a `LocaleContextResolver`. |`@PathVariable` |For access to URI template variables.