Skip to content

Commit fbb1fa3

Browse files
author
Keith Donald
committed
added support for Instant and MutableDateTime binding to JodaTime formatting system; allow for use of @DateTimeFormat on any ReadableInstant field
1 parent ff7f3ae commit fbb1fa3

File tree

4 files changed

+124
-15
lines changed

4 files changed

+124
-15
lines changed

org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaDateTimeFormatAnnotationFormatterFactory.java

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@
2222
import java.util.HashSet;
2323
import java.util.Set;
2424

25-
import org.joda.time.DateMidnight;
2625
import org.joda.time.DateTime;
2726
import org.joda.time.LocalDate;
2827
import org.joda.time.LocalDateTime;
2928
import org.joda.time.LocalTime;
3029
import org.joda.time.ReadableInstant;
3130
import org.joda.time.ReadablePartial;
3231
import org.joda.time.format.DateTimeFormatter;
33-
3432
import org.springframework.context.EmbeddedValueResolverAware;
3533
import org.springframework.format.AnnotationFormatterFactory;
3634
import org.springframework.format.Parser;
@@ -57,16 +55,7 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
5755

5856

5957
public JodaDateTimeFormatAnnotationFormatterFactory() {
60-
Set<Class<?>> rawFieldTypes = new HashSet<Class<?>>(8);
61-
rawFieldTypes.add(LocalDate.class);
62-
rawFieldTypes.add(LocalTime.class);
63-
rawFieldTypes.add(LocalDateTime.class);
64-
rawFieldTypes.add(DateTime.class);
65-
rawFieldTypes.add(DateMidnight.class);
66-
rawFieldTypes.add(Date.class);
67-
rawFieldTypes.add(Calendar.class);
68-
rawFieldTypes.add(Long.class);
69-
this.fieldTypes = Collections.unmodifiableSet(rawFieldTypes);
58+
this.fieldTypes = createFieldTypes();
7059
}
7160

7261
public final Set<Class<?>> getFieldTypes() {
@@ -105,7 +94,26 @@ public Parser<DateTime> getParser(DateTimeFormat annotation, Class<?> fieldType)
10594
return new DateTimeParser(configureDateTimeFormatterFrom(annotation));
10695
}
10796

108-
97+
// internal helpers
98+
99+
/**
100+
* Create the set of field types that may be annotated with @DateTimeFormat.
101+
* Note: the 3 ReadablePartial concrete types are registered explicitly since addFormatterForFieldType rules exist for each of these types
102+
* (if we did not do this, the default byType rules for LocalDate, LocalTime, and LocalDateTime would take precedence over the annotation rule, which is not what we want)
103+
* @see JodaTimeFormatterRegistrar#registerFormatters(org.springframework.format.FormatterRegistry)
104+
*/
105+
private Set<Class<?>> createFieldTypes() {
106+
Set<Class<?>> rawFieldTypes = new HashSet<Class<?>>(7);
107+
rawFieldTypes.add(ReadableInstant.class);
108+
rawFieldTypes.add(LocalDate.class);
109+
rawFieldTypes.add(LocalTime.class);
110+
rawFieldTypes.add(LocalDateTime.class);
111+
rawFieldTypes.add(Date.class);
112+
rawFieldTypes.add(Calendar.class);
113+
rawFieldTypes.add(Long.class);
114+
return Collections.unmodifiableSet(rawFieldTypes);
115+
}
116+
109117
private DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) {
110118
if (StringUtils.hasLength(annotation.pattern())) {
111119
return forPattern(resolveEmbeddedValue(annotation.pattern()));

org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaTimeConverters.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121

2222
import org.joda.time.DateMidnight;
2323
import org.joda.time.DateTime;
24+
import org.joda.time.Instant;
2425
import org.joda.time.LocalDate;
2526
import org.joda.time.LocalDateTime;
2627
import org.joda.time.LocalTime;
28+
import org.joda.time.MutableDateTime;
2729
import org.joda.time.ReadableInstant;
28-
2930
import org.springframework.core.convert.converter.Converter;
3031
import org.springframework.core.convert.converter.ConverterRegistry;
3132

@@ -46,6 +47,8 @@ public static void registerConverters(ConverterRegistry registry) {
4647
registry.addConverter(new DateTimeToLocalTimeConverter());
4748
registry.addConverter(new DateTimeToLocalDateTimeConverter());
4849
registry.addConverter(new DateTimeToDateMidnightConverter());
50+
registry.addConverter(new DateTimeToInstantConverter());
51+
registry.addConverter(new DateTimeToMutableDateTimeConverter());
4952
registry.addConverter(new DateTimeToDateConverter());
5053
registry.addConverter(new DateTimeToCalendarConverter());
5154
registry.addConverter(new DateTimeToLongConverter());
@@ -94,6 +97,26 @@ public DateMidnight convert(DateTime source) {
9497
}
9598
}
9699

100+
/**
101+
* Used when binding a parsed DateTime to an Instant field.
102+
* @see DateTimeParser
103+
*/
104+
private static class DateTimeToInstantConverter implements Converter<DateTime, Instant> {
105+
public Instant convert(DateTime source) {
106+
return source.toInstant();
107+
}
108+
}
109+
110+
/**
111+
* Used when binding a parsed DateTime to a MutableDateTime field.
112+
* @see DateTimeParser
113+
*/
114+
private static class DateTimeToMutableDateTimeConverter implements Converter<DateTime, MutableDateTime> {
115+
public MutableDateTime convert(DateTime source) {
116+
return source.toMutableDateTime();
117+
}
118+
}
119+
97120
/**
98121
* Used when binding a parsed DateTime to a java.util.Date field.
99122
* @see DateTimeParser

org.springframework.context/src/main/java/org/springframework/format/datetime/joda/JodaTimeFormatterRegistrar.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ private DateTimeFormatter getJodaDateFormatter() {
117117
}
118118
if (this.dateStyle != null) {
119119
return DateTimeFormat.forStyle(this.dateStyle + "-");
120-
121120
} else {
122121
return DateTimeFormat.shortDate();
123122
}

org.springframework.context/src/test/java/org/springframework/format/datetime/joda/JodaTimeFormattingTests.java

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626

2727
import org.joda.time.DateTime;
2828
import org.joda.time.DateTimeZone;
29+
import org.joda.time.Instant;
2930
import org.joda.time.LocalDate;
3031
import org.joda.time.LocalDateTime;
3132
import org.joda.time.LocalTime;
33+
import org.joda.time.MutableDateTime;
3234
import org.junit.After;
3335
import org.junit.Before;
3436
import org.junit.Test;
@@ -310,6 +312,41 @@ public void testBindISODateTime() {
310312
assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("isoDateTime"));
311313
}
312314

315+
@Test
316+
public void testBindInstant() {
317+
MutablePropertyValues propertyValues = new MutablePropertyValues();
318+
propertyValues.add("instant", "10/31/09 12:00 PM");
319+
binder.bind(propertyValues);
320+
assertEquals(0, binder.getBindingResult().getErrorCount());
321+
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("instant"));
322+
}
323+
324+
@Test
325+
public void testBindInstantAnnotated() {
326+
MutablePropertyValues propertyValues = new MutablePropertyValues();
327+
propertyValues.add("instantAnnotated", "2009-10-31T12:00:00.000Z");
328+
binder.bind(propertyValues);
329+
assertEquals(0, binder.getBindingResult().getErrorCount());
330+
assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("instantAnnotated"));
331+
}
332+
333+
@Test
334+
public void testBindMutableDateTime() {
335+
MutablePropertyValues propertyValues = new MutablePropertyValues();
336+
propertyValues.add("mutableDateTime", "10/31/09 12:00 PM");
337+
binder.bind(propertyValues);
338+
assertEquals(0, binder.getBindingResult().getErrorCount());
339+
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("mutableDateTime"));
340+
}
341+
342+
@Test
343+
public void testBindMutableDateTimeAnnotated() {
344+
MutablePropertyValues propertyValues = new MutablePropertyValues();
345+
propertyValues.add("mutableDateTimeAnnotated", "2009-10-31T12:00:00.000Z");
346+
binder.bind(propertyValues);
347+
assertEquals(0, binder.getBindingResult().getErrorCount());
348+
assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("mutableDateTimeAnnotated"));
349+
}
313350

314351
@SuppressWarnings("unused")
315352
private static class JodaTimeBean {
@@ -368,6 +405,16 @@ private static class JodaTimeBean {
368405
@DateTimeFormat(iso=ISO.DATE_TIME)
369406
private DateTime isoDateTime;
370407

408+
private Instant instant;
409+
410+
@DateTimeFormat(iso=ISO.DATE_TIME)
411+
private Instant instantAnnotated;
412+
413+
private MutableDateTime mutableDateTime;
414+
415+
@DateTimeFormat(iso=ISO.DATE_TIME)
416+
private Instant mutableDateTimeAnnotated;
417+
371418
private final List<JodaTimeBean> children = new ArrayList<JodaTimeBean>();
372419

373420
public LocalDate getLocalDate() {
@@ -530,6 +577,38 @@ public DateTime getIsoDateTime() {
530577
public void setIsoDateTime(DateTime isoDateTime) {
531578
this.isoDateTime = isoDateTime;
532579
}
580+
581+
public Instant getInstant() {
582+
return instant;
583+
}
584+
585+
public void setInstant(Instant instant) {
586+
this.instant = instant;
587+
}
588+
589+
public Instant getInstantAnnotated() {
590+
return instantAnnotated;
591+
}
592+
593+
public void setInstantAnnotated(Instant instantAnnotated) {
594+
this.instantAnnotated = instantAnnotated;
595+
}
596+
597+
public MutableDateTime getMutableDateTime() {
598+
return mutableDateTime;
599+
}
600+
601+
public void setMutableDateTime(MutableDateTime mutableDateTime) {
602+
this.mutableDateTime = mutableDateTime;
603+
}
604+
605+
public Instant getMutableDateTimeAnnotated() {
606+
return mutableDateTimeAnnotated;
607+
}
608+
609+
public void setMutableDateTimeAnnotated(Instant mutableDateTimeAnnotated) {
610+
this.mutableDateTimeAnnotated = mutableDateTimeAnnotated;
611+
}
533612

534613
public List<JodaTimeBean> getChildren() {
535614
return children;

0 commit comments

Comments
 (0)