From 69b51cd64d774ee0c08d5f8e2db3f6aa9e3a3aa8 Mon Sep 17 00:00:00 2001 From: Daniel Knittl-Frank Date: Mon, 28 Oct 2019 21:27:32 +0100 Subject: [PATCH] Enable users to provide custom time and datetime formats Extend WebFlux and WebMvc properties with timeFormat and dateTimeFormat properties to allow users to customize format of LocalTime and LocalDateTime instances. See gh-18772 --- .../web/format/WebConversionService.java | 36 +++++++++++++++++-- .../reactive/WebFluxAutoConfiguration.java | 3 +- .../web/reactive/WebFluxProperties.java | 26 ++++++++++++++ .../web/servlet/WebMvcAutoConfiguration.java | 3 +- .../web/servlet/WebMvcProperties.java | 26 ++++++++++++++ .../web/format/WebConversionServiceTests.java | 20 +++++++++++ 6 files changed, 110 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java index cb737da3b7c..cd82405b05c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java @@ -48,15 +48,32 @@ public class WebConversionService extends DefaultFormattingConversionService { private final String dateFormat; + private final String timeFormat; + + private final String dateTimeFormat; + /** * Create a new WebConversionService that configures formatters with the provided date * format, or register the default ones if no custom format is provided. * @param dateFormat the custom date format to use for date conversions */ public WebConversionService(String dateFormat) { + this(dateFormat, null, null); + } + + /** + * Create a new WebConversionService that configures formatters with the provided date + * and time formats, or register the default ones if no custom formats are provided. + * @param dateFormat the custom date format to use for date conversions + * @param timeFormat the custom time format to use for time conversions + * @param dateTimeFormat the custom datetime format to use for datetime conversions + */ + public WebConversionService(String dateFormat, String timeFormat, String dateTimeFormat) { super(false); - this.dateFormat = StringUtils.hasText(dateFormat) ? dateFormat : null; - if (this.dateFormat != null) { + this.dateFormat = getNonEmptyFormat(dateFormat); + this.timeFormat = getNonEmptyFormat(timeFormat); + this.dateTimeFormat = getNonEmptyFormat(dateTimeFormat); + if (this.dateFormat != null || this.timeFormat != null || this.dateTimeFormat != null) { addFormatters(); } else { @@ -81,6 +98,17 @@ public class WebConversionService extends DefaultFormattingConversionService { dateTime.setDateFormatter( DateTimeFormatter.ofPattern(this.dateFormat).withResolverStyle(ResolverStyle.SMART)); } + + if (this.timeFormat != null) { + dateTime.setTimeFormatter( + DateTimeFormatter.ofPattern(this.timeFormat).withResolverStyle(ResolverStyle.SMART)); + } + + if (this.dateTimeFormat != null) { + dateTime.setDateTimeFormatter( + DateTimeFormatter.ofPattern(this.dateTimeFormat).withResolverStyle(ResolverStyle.SMART)); + } + dateTime.registerFormatters(this); } @@ -93,4 +121,8 @@ public class WebConversionService extends DefaultFormattingConversionService { dateFormatterRegistrar.registerFormatters(this); } + private static String getNonEmptyFormat(final String format) { + return StringUtils.hasText(format) ? format : null; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java index 18a25fc81ef..dab1d88e0da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxAutoConfiguration.java @@ -203,7 +203,8 @@ public class WebFluxAutoConfiguration { @Bean @Override public FormattingConversionService webFluxConversionService() { - WebConversionService conversionService = new WebConversionService(this.webFluxProperties.getDateFormat()); + WebConversionService conversionService = new WebConversionService(this.webFluxProperties.getDateFormat(), + this.webFluxProperties.getTimeFormat(), this.webFluxProperties.getDateTimeFormat()); addFormatters(conversionService); return conversionService; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java index bb4293f61f0..88bd706e973 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/WebFluxProperties.java @@ -38,6 +38,16 @@ public class WebFluxProperties { */ private String dateFormat; + /** + * Time format to use. For instance, `HH:mm:ss`. + */ + private String timeFormat; + + /** + * Datetime format to use. For instance, `yyyy-MM-dd HH:mm:ss`. + */ + private String dateTimeFormat; + /** * Path pattern used for static resources. */ @@ -72,6 +82,22 @@ public class WebFluxProperties { this.dateFormat = dateFormat; } + public String getTimeFormat() { + return this.timeFormat; + } + + public void setTimeFormat(final String timeFormat) { + this.timeFormat = timeFormat; + } + + public String getDateTimeFormat() { + return this.dateTimeFormat; + } + + public void setDateTimeFormat(final String dateTimeFormat) { + this.dateTimeFormat = dateTimeFormat; + } + public String getStaticPathPattern() { return this.staticPathPattern; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java index 1275b25e974..bb9e29a2687 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.java @@ -427,7 +427,8 @@ public class WebMvcAutoConfiguration { @Bean @Override public FormattingConversionService mvcConversionService() { - WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat()); + WebConversionService conversionService = new WebConversionService(this.mvcProperties.getDateFormat(), + this.mvcProperties.getTimeFormat(), this.mvcProperties.getDateTimeFormat()); addFormatters(conversionService); return conversionService; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java index 5e4581ac683..db7f55ebfe5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/WebMvcProperties.java @@ -61,6 +61,16 @@ public class WebMvcProperties { */ private String dateFormat; + /** + * Time format to use. For instance, `HH:mm:ss`. + */ + private String timeFormat; + + /** + * Datetime format to use. For instance, `yyyy-MM-dd HH:mm:ss`. + */ + private String dateTimeFormat; + /** * Whether to dispatch TRACE requests to the FrameworkServlet doService method. */ @@ -147,6 +157,22 @@ public class WebMvcProperties { this.dateFormat = dateFormat; } + public String getTimeFormat() { + return this.timeFormat; + } + + public void setTimeFormat(final String timeFormat) { + this.timeFormat = timeFormat; + } + + public String getDateTimeFormat() { + return this.dateTimeFormat; + } + + public void setDateTimeFormat(final String dateTimeFormat) { + this.dateTimeFormat = dateTimeFormat; + } + public boolean isIgnoreDefaultModelOnRedirect() { return this.ignoreDefaultModelOnRedirect; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/format/WebConversionServiceTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/format/WebConversionServiceTests.java index dde2a4e7b12..e72f575b934 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/format/WebConversionServiceTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/format/WebConversionServiceTests.java @@ -42,11 +42,31 @@ class WebConversionServiceTests { customDateFormat(java.time.LocalDate.of(2018, 1, 1)); } + @Test + void customTimeFormatWithJavaTime() { + customTimeFormat(java.time.LocalTime.of(13, 37, 42)); + } + + @Test + void customDateTimeFormatWithJavaTime() { + customDateTimeFormat(java.time.LocalDateTime.of(2019, 10, 28, 13, 37, 42)); + } + private void customDateFormat(Object input) { WebConversionService conversionService = new WebConversionService("dd*MM*yyyy"); assertThat(conversionService.convert(input, String.class)).isEqualTo("01*01*2018"); } + private void customTimeFormat(Object input) { + WebConversionService conversionService = new WebConversionService(null, "HH*mm*ss", null); + assertThat(conversionService.convert(input, String.class)).isEqualTo("13*37*42"); + } + + private void customDateTimeFormat(Object input) { + WebConversionService conversionService = new WebConversionService(null, null, "dd*MM*yyyy HH*mm*ss"); + assertThat(conversionService.convert(input, String.class)).isEqualTo("28*10*2019 13*37*42"); + } + @Test void convertFromStringToDate() { WebConversionService conversionService = new WebConversionService("yyyy-MM-dd");