From 66ae626f91e0b2bbfcf9b9059cb06b07883d9b0b Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Tue, 12 Feb 2013 11:02:30 -0800 Subject: [PATCH] Only register Date converters with global format Change JodaTimeFormatterRegistrar and DateFormatterRegistrar to only register converters for the Date and Calendar types when a global format has been defined. This means that the ObjectToObject converter will handle String->Date conversion using the deprecated Date(String) constructor (as was the case with Spring 3.1). Issue: SPR-10105 --- .../datetime/DateFormatterRegistrar.java | 16 ++++--- .../joda/JodaTimeFormatterRegistrar.java | 11 ++++- .../format/datetime/DateFormattingTests.java | 47 +++++++++++++++++-- .../joda/JodaTimeFormattingTests.java | 37 +++++++++++++-- 4 files changed, 97 insertions(+), 14 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java index 5e45fedee3..b74b53262b 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java @@ -40,20 +40,24 @@ import org.springframework.util.Assert; public class DateFormatterRegistrar implements FormatterRegistrar { - private DateFormatter dateFormatter = new DateFormatter(); + private DateFormatter dateFormatter; public void registerFormatters(FormatterRegistry registry) { addDateConverters(registry); - registry.addFormatter(this.dateFormatter); - registry.addFormatterForFieldType(Calendar.class, this.dateFormatter); registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory()); + + // In order to retain back compatibility we only register Date/Calendar + // types when a user defined formatter is specified (see SPR-10105) + if(this.dateFormatter != null) { + registry.addFormatter(this.dateFormatter); + registry.addFormatterForFieldType(Calendar.class, this.dateFormatter); + } } /** - * Set the date formatter to register. If not specified the default {@link DateFormatter} - * will be used. This method can be used if additional formatter configuration is - * required. + * Set the date formatter to register. If not specified no formatter is registered. + * This method can be used if global formatter configuration is required. * @param dateFormatter the date formatter */ public void setFormatter(DateFormatter dateFormatter) { diff --git a/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormatterRegistrar.java b/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormatterRegistrar.java index 2035b68b85..7ad1a4e62e 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormatterRegistrar.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormatterRegistrar.java @@ -174,7 +174,16 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar { addFormatterForFields(registry, new ReadableInstantPrinter(dateTimeFormatter), new DateTimeParser(dateTimeFormatter), - ReadableInstant.class, Date.class, Calendar.class); + ReadableInstant.class); + + // In order to retain back compatibility we only register Date/Calendar + // types when a user defined formatter is specified (see SPR-10105) + if(this.formatters.containsKey(Type.DATE_TIME)) { + addFormatterForFields(registry, + new ReadableInstantPrinter(dateTimeFormatter), + new DateTimeParser(dateTimeFormatter), + Date.class, Calendar.class); + } registry.addFormatterForFieldAnnotation( new JodaDateTimeFormatAnnotationFormatterFactory()); diff --git a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java index 5698ed0651..2803f0dc9f 100644 --- a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java +++ b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java @@ -16,7 +16,10 @@ package org.springframework.format.datetime; +import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import java.util.ArrayList; import java.util.Calendar; @@ -50,9 +53,12 @@ public class DateFormattingTests { @Before public void setUp() { - DefaultConversionService.addDefaultConverters(conversionService); - DateFormatterRegistrar registrar = new DateFormatterRegistrar(); + setUp(registrar); + } + + private void setUp(DateFormatterRegistrar registrar) { + DefaultConversionService.addDefaultConverters(conversionService); registrar.registerFormatters(conversionService); SimpleDateBean bean = new SimpleDateBean(); @@ -187,13 +193,48 @@ public class DateFormattingTests { } @Test - public void dateToString() throws Exception { + public void dateToStringWithoutGlobalFormat() throws Exception { + Date date = new Date(); + Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class)); + String expected = date.toString(); + assertEquals(expected, actual); + } + + @Test + public void dateToStringWithGlobalFormat() throws Exception { + DateFormatterRegistrar registrar = new DateFormatterRegistrar(); + registrar.setFormatter(new DateFormatter()); + setUp(registrar); Date date = new Date(); Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class)); String expected = new DateFormatter().print(date, Locale.US); assertEquals(expected, actual); } + @Test + @SuppressWarnings("deprecation") + public void stringToDateWithoutGlobalFormat() throws Exception { + // SPR-10105 + String string = "Sat, 12 Aug 1995 13:30:00 GM"; + Date date = this.conversionService.convert(string, Date.class); + assertThat(date, equalTo(new Date(string))); + } + + @Test + public void stringToDateWithGlobalFormat() throws Exception { + // SPR-10105 + DateFormatterRegistrar registrar = new DateFormatterRegistrar(); + DateFormatter dateFormatter = new DateFormatter(); + dateFormatter.setIso(ISO.DATE_TIME); + registrar.setFormatter(dateFormatter); + setUp(registrar); + // This is a format that cannot be parsed by new Date(String) + String string = "2009-06-01T14:23:05.003+0000"; + Date date = this.conversionService.convert(string, Date.class); + assertNotNull(date); + } + + @SuppressWarnings("unused") private static class SimpleDateBean { diff --git a/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java index 237df0509f..c2aaf8d36a 100644 --- a/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java +++ b/spring-context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java @@ -16,6 +16,11 @@ package org.springframework.format.datetime.joda; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; + import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -32,7 +37,6 @@ import org.joda.time.MutableDateTime; import org.junit.After; import org.junit.Before; import org.junit.Test; - import org.springframework.beans.MutablePropertyValues; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.convert.TypeDescriptor; @@ -42,8 +46,6 @@ import org.springframework.format.annotation.DateTimeFormat.ISO; import org.springframework.format.support.FormattingConversionService; import org.springframework.validation.DataBinder; -import static org.junit.Assert.*; - /** * @author Keith Donald * @author Juergen Hoeller @@ -459,13 +461,40 @@ public class JodaTimeFormattingTests { } @Test - public void dateToString() throws Exception { + public void dateToStringWithFormat() throws Exception { + JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar(); + registrar.setDateTimeFormatter(org.joda.time.format.DateTimeFormat.shortDateTime()); + setUp(registrar); Date date = new Date(); Object actual = this.conversionService.convert(date, TypeDescriptor.valueOf(Date.class), TypeDescriptor.valueOf(String.class)); String expected = JodaTimeContextHolder.getFormatter(org.joda.time.format.DateTimeFormat.shortDateTime(), Locale.US).print(new DateTime(date)); assertEquals(expected, actual); } + @Test + @SuppressWarnings("deprecation") + public void stringToDateWithoutGlobalFormat() throws Exception { + // SPR-10105 + String string = "Sat, 12 Aug 1995 13:30:00 GM"; + Date date = this.conversionService.convert(string, Date.class); + assertThat(date, equalTo(new Date(string))); + } + + @Test + public void stringToDateWithGlobalFormat() throws Exception { + // SPR-10105 + JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar(); + DateTimeFormatterFactory factory = new DateTimeFormatterFactory(); + factory.setIso(ISO.DATE_TIME); + registrar.setDateTimeFormatter(factory.createDateTimeFormatter()); + setUp(registrar); + // This is a format that cannot be parsed by new Date(String) + String string = "2009-10-31T07:00:00.000-05:00"; + Date date = this.conversionService.convert(string, Date.class); + assertNotNull(date); + } + + @SuppressWarnings("unused") private static class JodaTimeBean {