diff --git a/org.springframework.context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java b/org.springframework.context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java
index 01280a07b5..e216d82fce 100644
--- a/org.springframework.context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java
+++ b/org.springframework.context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java
@@ -22,18 +22,22 @@ import java.lang.annotation.Target;
/**
* Declares that a field should be formatted as a date time.
- * Supports formatting by style pattern or by format pattern string.
+ * Supports formatting by style pattern, custom format pattern string, or ISO date time pattern.
* Can be applied to java.util.Date, java.util.Calendar, java.long.Long, or Joda Time fields.
*
- * For style-based formatting, set the style attribute to be the style pattern.
- * The first character is the date style, and the second character is the time style.
+ * For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
+ * The first character of the code is the date style, and the second character is the time style.
* Specify a character of 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full.
* A date or time may be omitted by specifying the style character '-'.
*
- * For pattern-based formatting, set the pattern attribute to be the DateTime pattern, such as yyyy/mm/dd h:mm:ss a.
- * If the pattern attribute is specified, it takes precedence over the style attribute.
+ * For pattern-based formatting, set the {@link #pattern()} attribute to be the DateTime pattern, such as yyyy/mm/dd h:mm:ss a.
*
- * If no annotation attributes are specified, the default format applied is style-based with a style code of 'SS' (short date, short time).
+ * For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format, such as {@link ISO#DATE}.
+ *
+ * Each attribute is mutually exclusive, so only set one attribute per annotation instance (the one most convenient one for your formatting needs).
+ * When the pattern attribute is specified, it takes precedence over both the style and ISO attribute.
+ * When the iso attribute is specified, if takes precedence over the style attribute.
+ * When no annotation attributes are specified, the default format applied is style-based with a style code of 'SS' (short date, short time).
*
* @author Keith Donald
* @since 3.0
@@ -50,9 +54,44 @@ public @interface DateTimeFormat {
String style() default "SS";
/**
- * A pattern String to apply to format the field.
* Set this attribute or the style attribute, not both.
*/
String pattern() default "";
+
+ /**
+ * A ISO pattern to apply to format the field.
+ * The possible ISO patterns are defined in the {@link ISO} enum.
+ * Defaults to ISO.NONE, indicating this attribute should be ignored.
+ */
+ ISO iso() default ISO.NONE;
+
+ /**
+ * Common ISO date time format patterns.
+ * @author Keith Donald
+ * @since 3.0
+ */
+ public enum ISO {
+ /**
+ * The most common ISO Date Format yyyy-MM-dd e.g. 2000-10-31.
+ */
+ DATE,
+
+ /**
+ * The most common ISO Time Format hh:mm:ss.SSSZ e.g. 01:30:00.000-05:00.
+ */
+ TIME,
+
+ /**
+ * The most common ISO DateTime Format yyyy-MM-dd'T'hh:mm:ss.SSSZ e.g. 2000-10-31 01:30:00.000-05:00.
+ * The default if no annotation value is specified.
+ */
+ DATE_TIME,
+
+ /**
+ * Indicates that no ISO-based format pattern should be applied.
+ */
+ NONE
+
+ }
}
diff --git a/org.springframework.context/src/main/java/org/springframework/format/annotation/ISODateTimeFormat.java b/org.springframework.context/src/main/java/org/springframework/format/annotation/ISODateTimeFormat.java
deleted file mode 100644
index 02e9207018..0000000000
--- a/org.springframework.context/src/main/java/org/springframework/format/annotation/ISODateTimeFormat.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2002-2009 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.format.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Declares that a field should be formatted as a ISO date time.
- * Can be applied to java.util.Date, java.util.Calendar, java.long.Long, or Joda Time fields.
- * @author Keith Donald
- * @since 3.0
- */
-@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ISODateTimeFormat {
-
- /**
- * The ISO style to use to format the date time.
- * Defaults to {@link ISO#DATE_TIME}.
- */
- ISO value() default ISO.DATE_TIME;
-
- public enum ISO {
-
- /**
- * The most common ISO Date Format yyyy-MM-dd e.g. 2000-10-31.
- */
- DATE,
-
- /**
- * The most common ISO Time Format hh:mm:ss.SSSZ e.g. 01:30:00.000-05:00.
- */
- TIME,
-
- /**
- * The most common ISO DateTime Format yyyy-MM-dd'T'hh:mm:ss.SSSZ e.g. 2000-10-31 01:30:00.000-05:00.
- * The default if no annotation value is specified.
- */
- DATE_TIME
- }
-
-}
diff --git a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/AbstractDateTimeAnnotationFormatterFactory.java b/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/AbstractDateTimeAnnotationFormatterFactory.java
deleted file mode 100644
index e2f3ead18e..0000000000
--- a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/AbstractDateTimeAnnotationFormatterFactory.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2002-2009 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.format.datetime.joda;
-
-import java.lang.annotation.Annotation;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.joda.time.DateMidnight;
-import org.joda.time.DateTime;
-import org.joda.time.LocalDate;
-import org.joda.time.LocalDateTime;
-import org.joda.time.LocalTime;
-import org.joda.time.ReadableInstant;
-import org.joda.time.ReadablePartial;
-import org.joda.time.format.DateTimeFormatter;
-import org.springframework.format.AnnotationFormatterFactory;
-import org.springframework.format.Parser;
-import org.springframework.format.Printer;
-
-/**
- * Base class for annotation-based Joda DateTime formatters.
- * Can format any Joda {@link ReadableInstant} or {@link ReadablePartial} property, as well as standard {@link Date}, {@link Calendar}, and Long properties.
- * @author Keith Donald
- * @since 3.0
- * @param the format annotation parameter type to be declared by subclasses
- */
-abstract class AbstractDateTimeAnnotationFormatterFactory implements AnnotationFormatterFactory {
-
- private final Set> fieldTypes;
-
- public AbstractDateTimeAnnotationFormatterFactory() {
- this.fieldTypes = Collections.unmodifiableSet(createFieldTypes());
- }
-
- public Set> getFieldTypes() {
- return this.fieldTypes;
- }
-
- public Printer> getPrinter(A annotation, Class> fieldType) {
- DateTimeFormatter formatter = configureDateTimeFormatterFrom(annotation);
- if (ReadableInstant.class.isAssignableFrom(fieldType)) {
- return new ReadableInstantPrinter(formatter);
- } else if (ReadablePartial.class.isAssignableFrom(fieldType)) {
- return new ReadablePartialPrinter(formatter);
- } else if (Calendar.class.isAssignableFrom(fieldType)) {
- // assumes Calendar->ReadableInstant converter is registered
- return new ReadableInstantPrinter(formatter);
- } else {
- // assumes Date->Long converter is registered
- return new MillisecondInstantPrinter(formatter);
- }
- }
-
- public Parser getParser(A annotation, Class> propertyType) {
- return new DateTimeParser(configureDateTimeFormatterFrom(annotation));
- }
-
- /**
- * Hook method subclasses should override to configure the Joda {@link DateTimeFormatter} from the annotation values.
- * @param annotation the annotation containing formatter configuration rules
- * @return the configured date time formatter
- */
- protected abstract DateTimeFormatter configureDateTimeFormatterFrom(A annotation);
-
- // internal helpers
-
- private Set> createFieldTypes() {
- Set> fieldTypes = new HashSet>(8);
- fieldTypes.add(LocalDate.class);
- fieldTypes.add(LocalTime.class);
- fieldTypes.add(LocalDateTime.class);
- fieldTypes.add(DateTime.class);
- fieldTypes.add(DateMidnight.class);
- fieldTypes.add(Date.class);
- fieldTypes.add(Calendar.class);
- fieldTypes.add(Long.class);
- return fieldTypes;
- }
-
-}
diff --git a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatAnnotationFormatterFactory.java b/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatAnnotationFormatterFactory.java
index 3e6b42b738..4c12e8f787 100644
--- a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatAnnotationFormatterFactory.java
+++ b/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatAnnotationFormatterFactory.java
@@ -15,8 +15,25 @@
*/
package org.springframework.format.datetime.joda;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.joda.time.DateMidnight;
+import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.joda.time.LocalDateTime;
+import org.joda.time.LocalTime;
+import org.joda.time.ReadableInstant;
+import org.joda.time.ReadablePartial;
import org.joda.time.format.DateTimeFormatter;
+import org.springframework.format.AnnotationFormatterFactory;
+import org.springframework.format.Parser;
+import org.springframework.format.Printer;
import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.format.annotation.DateTimeFormat.ISO;
/**
* Formats fields annotated with the {@link DateTimeFormat} annotation.
@@ -24,12 +41,57 @@ import org.springframework.format.annotation.DateTimeFormat;
* @since 3.0
* @see DateTimeFormat
*/
-public final class DateTimeFormatAnnotationFormatterFactory extends AbstractDateTimeAnnotationFormatterFactory {
+public final class DateTimeFormatAnnotationFormatterFactory implements AnnotationFormatterFactory {
- protected DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) {
- String pattern = annotation.pattern();
- if (!pattern.isEmpty()) {
- return forPattern(pattern);
+ private final Set> fieldTypes;
+
+ public DateTimeFormatAnnotationFormatterFactory() {
+ this.fieldTypes = Collections.unmodifiableSet(createFieldTypes());
+ }
+
+ public Set> getFieldTypes() {
+ return this.fieldTypes;
+ }
+
+ public Printer> getPrinter(DateTimeFormat annotation, Class> fieldType) {
+ DateTimeFormatter formatter = configureDateTimeFormatterFrom(annotation);
+ if (ReadableInstant.class.isAssignableFrom(fieldType)) {
+ return new ReadableInstantPrinter(formatter);
+ } else if (ReadablePartial.class.isAssignableFrom(fieldType)) {
+ return new ReadablePartialPrinter(formatter);
+ } else if (Calendar.class.isAssignableFrom(fieldType)) {
+ // assumes Calendar->ReadableInstant converter is registered
+ return new ReadableInstantPrinter(formatter);
+ } else {
+ // assumes Date->Long converter is registered
+ return new MillisecondInstantPrinter(formatter);
+ }
+ }
+
+ public Parser getParser(DateTimeFormat annotation, Class> fieldType) {
+ return new DateTimeParser(configureDateTimeFormatterFrom(annotation));
+ }
+
+ // internal helpers
+
+ private Set> createFieldTypes() {
+ Set> fieldTypes = new HashSet>(8);
+ fieldTypes.add(LocalDate.class);
+ fieldTypes.add(LocalTime.class);
+ fieldTypes.add(LocalDateTime.class);
+ fieldTypes.add(DateTime.class);
+ fieldTypes.add(DateMidnight.class);
+ fieldTypes.add(Date.class);
+ fieldTypes.add(Calendar.class);
+ fieldTypes.add(Long.class);
+ return fieldTypes;
+ }
+
+ private DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) {
+ if (!annotation.pattern().isEmpty()) {
+ return forPattern(annotation.pattern());
+ } else if (annotation.iso() != ISO.NONE) {
+ return forISO(annotation.iso());
} else {
return forStyle(annotation.style());
}
@@ -38,6 +100,16 @@ public final class DateTimeFormatAnnotationFormatterFactory extends AbstractDate
private DateTimeFormatter forPattern(String pattern) {
return org.joda.time.format.DateTimeFormat.forPattern(pattern);
}
+
+ private DateTimeFormatter forISO(ISO iso) {
+ if (iso == ISO.DATE) {
+ return org.joda.time.format.ISODateTimeFormat.date();
+ } else if (iso == ISO.TIME) {
+ return org.joda.time.format.ISODateTimeFormat.time();
+ } else {
+ return org.joda.time.format.ISODateTimeFormat.dateTime();
+ }
+ }
private DateTimeFormatter forStyle(String style) {
return org.joda.time.format.DateTimeFormat.forStyle(style);
diff --git a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/ISODateTimeFormatAnnotationFormatterFactory.java b/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/ISODateTimeFormatAnnotationFormatterFactory.java
deleted file mode 100644
index afc4804554..0000000000
--- a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/ISODateTimeFormatAnnotationFormatterFactory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2002-2009 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.format.datetime.joda;
-
-import org.joda.time.format.DateTimeFormatter;
-import org.springframework.format.annotation.ISODateTimeFormat;
-import org.springframework.format.annotation.ISODateTimeFormat.ISO;
-
-/**
- * Formats fields annotated with the {@link ISODateTimeFormat} annotation.
- * @author Keith Donald
- * @since 3.0
- * @see ISODateTimeFormat
- */
-public final class ISODateTimeFormatAnnotationFormatterFactory extends AbstractDateTimeAnnotationFormatterFactory {
-
- protected DateTimeFormatter configureDateTimeFormatterFrom(ISODateTimeFormat annotation) {
- ISO format = annotation.value();
- if (format == ISO.DATE) {
- return org.joda.time.format.ISODateTimeFormat.date();
- } else if (format == ISO.TIME) {
- return org.joda.time.format.ISODateTimeFormat.time();
- } else {
- return org.joda.time.format.ISODateTimeFormat.dateTime();
- }
- }
-
-}
\ No newline at end of file
diff --git a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormattingConfigurer.java b/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormattingConfigurer.java
index be534611eb..9e698e3cc8 100644
--- a/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormattingConfigurer.java
+++ b/org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormattingConfigurer.java
@@ -109,7 +109,6 @@ public class JodaTimeFormattingConfigurer {
formatterRegistry.addFormatterForFieldType(Date.class, new MillisecondInstantPrinter(jodaDateTimeFormatter), dateTimeParser);
formatterRegistry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
- formatterRegistry.addFormatterForFieldAnnotation(new ISODateTimeFormatAnnotationFormatterFactory());
}
// internal helpers
diff --git a/org.springframework.context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java b/org.springframework.context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java
index 634995904b..a72f825c60 100644
--- a/org.springframework.context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java
+++ b/org.springframework.context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java
@@ -17,8 +17,7 @@ import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.format.annotation.DateTimeFormat;
-import org.springframework.format.annotation.ISODateTimeFormat;
-import org.springframework.format.annotation.ISODateTimeFormat.ISO;
+import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.validation.DataBinder;
@@ -137,6 +136,15 @@ public class JodaTimeFormattingTests {
assertEquals("Oct 31, 2009 12:00 PM", binder.getBindingResult().getFieldValue("dateTimeAnnotated"));
}
+ @Test
+ public void testBindDateTimeAnnotatedPattern() {
+ MutablePropertyValues propertyValues = new MutablePropertyValues();
+ propertyValues.addPropertyValue("dateTimeAnnotatedPattern", "10/31/09 12:00 PM");
+ binder.bind(propertyValues);
+ assertEquals(0, binder.getBindingResult().getErrorCount());
+ assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("dateTimeAnnotatedPattern"));
+ }
+
@Test
public void testBindDateTimeAnnotatedDefault() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
@@ -227,15 +235,6 @@ public class JodaTimeFormattingTests {
assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("isoDateTime"));
}
- @Test
- public void testBindISODateTimeDefault() {
- MutablePropertyValues propertyValues = new MutablePropertyValues();
- propertyValues.addPropertyValue("isoDateTimeDefault", "2009-10-31T12:00:00.000Z");
- binder.bind(propertyValues);
- assertEquals(0, binder.getBindingResult().getErrorCount());
- assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("isoDateTimeDefault"));
- }
-
public static class JodaTimeBean {
private LocalDate localDate;
@@ -258,9 +257,6 @@ public class JodaTimeFormattingTests {
@DateTimeFormat(style="MS")
private DateTime dateTimeAnnotated;
- @DateTimeFormat
- private DateTime dateTimeAnnotatedDefault;
-
private Date date;
@DateTimeFormat(style="S-")
@@ -273,21 +269,24 @@ public class JodaTimeFormattingTests {
private Long millis;
+ @DateTimeFormat
+ private DateTime dateTimeAnnotatedDefault;
+
@DateTimeFormat(style="S-")
private Long millisAnnotated;
- @ISODateTimeFormat(ISO.DATE)
+ @DateTimeFormat(pattern="M/d/yy h:mm a")
+ private DateTime dateTimeAnnotatedPattern;
+
+ @DateTimeFormat(iso=ISO.DATE)
private LocalDate isoDate;
- @ISODateTimeFormat(ISO.TIME)
+ @DateTimeFormat(iso=ISO.TIME)
private LocalTime isoTime;
- @ISODateTimeFormat(ISO.DATE_TIME)
+ @DateTimeFormat(iso=ISO.DATE_TIME)
private DateTime isoDateTime;
- @ISODateTimeFormat
- private DateTime isoDateTimeDefault;
-
public LocalDate getLocalDate() {
return localDate;
}
@@ -352,6 +351,14 @@ public class JodaTimeFormattingTests {
this.dateTimeAnnotated = dateTimeAnnotated;
}
+ public DateTime getDateTimeAnnotatedPattern() {
+ return dateTimeAnnotatedPattern;
+ }
+
+ public void setDateTimeAnnotatedPattern(DateTime dateTimeAnnotatedPattern) {
+ this.dateTimeAnnotatedPattern = dateTimeAnnotatedPattern;
+ }
+
public DateTime getDateTimeAnnotatedDefault() {
return dateTimeAnnotatedDefault;
}
@@ -431,14 +438,6 @@ public class JodaTimeFormattingTests {
public void setIsoDateTime(DateTime isoDateTime) {
this.isoDateTime = isoDateTime;
}
-
- public DateTime getIsoDateTimeDefault() {
- return isoDateTimeDefault;
- }
-
- public void setIsoDateTimeDefault(DateTime isoDateTimeDefault) {
- this.isoDateTimeDefault = isoDateTimeDefault;
- }
-
+
}
}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
index 0268f5f24a..68db7132d2 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
@@ -11,8 +11,8 @@ import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.io.ClassPathResource;
-import org.springframework.format.annotation.ISODateTimeFormat;
-import org.springframework.format.annotation.ISODateTimeFormat.ISO;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
@@ -58,7 +58,7 @@ public class MvcNamespaceTests {
public static class TestController {
@RequestMapping
- public void testBind(@RequestParam @ISODateTimeFormat(ISO.DATE) Date date) {
+ public void testBind(@RequestParam @DateTimeFormat(iso=ISO.DATE) Date date) {
}
}