added support for Instant and MutableDateTime binding to JodaTime formatting system; allow for use of @DateTimeFormat on any ReadableInstant field
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3941 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
2c0cb96fbf
commit
ded88e3a7b
|
|
@ -22,7 +22,6 @@ import java.util.Date;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.joda.time.DateMidnight;
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.joda.time.LocalDateTime;
|
import org.joda.time.LocalDateTime;
|
||||||
|
|
@ -30,7 +29,6 @@ import org.joda.time.LocalTime;
|
||||||
import org.joda.time.ReadableInstant;
|
import org.joda.time.ReadableInstant;
|
||||||
import org.joda.time.ReadablePartial;
|
import org.joda.time.ReadablePartial;
|
||||||
import org.joda.time.format.DateTimeFormatter;
|
import org.joda.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
import org.springframework.context.EmbeddedValueResolverAware;
|
import org.springframework.context.EmbeddedValueResolverAware;
|
||||||
import org.springframework.format.AnnotationFormatterFactory;
|
import org.springframework.format.AnnotationFormatterFactory;
|
||||||
import org.springframework.format.Parser;
|
import org.springframework.format.Parser;
|
||||||
|
|
@ -57,16 +55,7 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
|
||||||
|
|
||||||
|
|
||||||
public JodaDateTimeFormatAnnotationFormatterFactory() {
|
public JodaDateTimeFormatAnnotationFormatterFactory() {
|
||||||
Set<Class<?>> rawFieldTypes = new HashSet<Class<?>>(8);
|
this.fieldTypes = createFieldTypes();
|
||||||
rawFieldTypes.add(LocalDate.class);
|
|
||||||
rawFieldTypes.add(LocalTime.class);
|
|
||||||
rawFieldTypes.add(LocalDateTime.class);
|
|
||||||
rawFieldTypes.add(DateTime.class);
|
|
||||||
rawFieldTypes.add(DateMidnight.class);
|
|
||||||
rawFieldTypes.add(Date.class);
|
|
||||||
rawFieldTypes.add(Calendar.class);
|
|
||||||
rawFieldTypes.add(Long.class);
|
|
||||||
this.fieldTypes = Collections.unmodifiableSet(rawFieldTypes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Set<Class<?>> getFieldTypes() {
|
public final Set<Class<?>> getFieldTypes() {
|
||||||
|
|
@ -105,7 +94,26 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
|
||||||
return new DateTimeParser(configureDateTimeFormatterFrom(annotation));
|
return new DateTimeParser(configureDateTimeFormatterFrom(annotation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// internal helpers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the set of field types that may be annotated with @DateTimeFormat.
|
||||||
|
* Note: the 3 ReadablePartial concrete types are registered explicitly since addFormatterForFieldType rules exist for each of these types
|
||||||
|
* (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)
|
||||||
|
* @see JodaTimeFormatterRegistrar#registerFormatters(org.springframework.format.FormatterRegistry)
|
||||||
|
*/
|
||||||
|
private Set<Class<?>> createFieldTypes() {
|
||||||
|
Set<Class<?>> rawFieldTypes = new HashSet<Class<?>>(7);
|
||||||
|
rawFieldTypes.add(ReadableInstant.class);
|
||||||
|
rawFieldTypes.add(LocalDate.class);
|
||||||
|
rawFieldTypes.add(LocalTime.class);
|
||||||
|
rawFieldTypes.add(LocalDateTime.class);
|
||||||
|
rawFieldTypes.add(Date.class);
|
||||||
|
rawFieldTypes.add(Calendar.class);
|
||||||
|
rawFieldTypes.add(Long.class);
|
||||||
|
return Collections.unmodifiableSet(rawFieldTypes);
|
||||||
|
}
|
||||||
|
|
||||||
private DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) {
|
private DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) {
|
||||||
if (StringUtils.hasLength(annotation.pattern())) {
|
if (StringUtils.hasLength(annotation.pattern())) {
|
||||||
return forPattern(resolveEmbeddedValue(annotation.pattern()));
|
return forPattern(resolveEmbeddedValue(annotation.pattern()));
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ import java.util.Date;
|
||||||
|
|
||||||
import org.joda.time.DateMidnight;
|
import org.joda.time.DateMidnight;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.Instant;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.joda.time.LocalDateTime;
|
import org.joda.time.LocalDateTime;
|
||||||
import org.joda.time.LocalTime;
|
import org.joda.time.LocalTime;
|
||||||
|
import org.joda.time.MutableDateTime;
|
||||||
import org.joda.time.ReadableInstant;
|
import org.joda.time.ReadableInstant;
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||||
|
|
||||||
|
|
@ -46,6 +47,8 @@ final class JodaTimeConverters {
|
||||||
registry.addConverter(new DateTimeToLocalTimeConverter());
|
registry.addConverter(new DateTimeToLocalTimeConverter());
|
||||||
registry.addConverter(new DateTimeToLocalDateTimeConverter());
|
registry.addConverter(new DateTimeToLocalDateTimeConverter());
|
||||||
registry.addConverter(new DateTimeToDateMidnightConverter());
|
registry.addConverter(new DateTimeToDateMidnightConverter());
|
||||||
|
registry.addConverter(new DateTimeToInstantConverter());
|
||||||
|
registry.addConverter(new DateTimeToMutableDateTimeConverter());
|
||||||
registry.addConverter(new DateTimeToDateConverter());
|
registry.addConverter(new DateTimeToDateConverter());
|
||||||
registry.addConverter(new DateTimeToCalendarConverter());
|
registry.addConverter(new DateTimeToCalendarConverter());
|
||||||
registry.addConverter(new DateTimeToLongConverter());
|
registry.addConverter(new DateTimeToLongConverter());
|
||||||
|
|
@ -94,6 +97,26 @@ final class JodaTimeConverters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when binding a parsed DateTime to an Instant field.
|
||||||
|
* @see DateTimeParser
|
||||||
|
*/
|
||||||
|
private static class DateTimeToInstantConverter implements Converter<DateTime, Instant> {
|
||||||
|
public Instant convert(DateTime source) {
|
||||||
|
return source.toInstant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used when binding a parsed DateTime to a MutableDateTime field.
|
||||||
|
* @see DateTimeParser
|
||||||
|
*/
|
||||||
|
private static class DateTimeToMutableDateTimeConverter implements Converter<DateTime, MutableDateTime> {
|
||||||
|
public MutableDateTime convert(DateTime source) {
|
||||||
|
return source.toMutableDateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used when binding a parsed DateTime to a java.util.Date field.
|
* Used when binding a parsed DateTime to a java.util.Date field.
|
||||||
* @see DateTimeParser
|
* @see DateTimeParser
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,6 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
|
||||||
}
|
}
|
||||||
if (this.dateStyle != null) {
|
if (this.dateStyle != null) {
|
||||||
return DateTimeFormat.forStyle(this.dateStyle + "-");
|
return DateTimeFormat.forStyle(this.dateStyle + "-");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return DateTimeFormat.shortDate();
|
return DateTimeFormat.shortDate();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,11 @@ import java.util.Locale;
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.DateTimeZone;
|
import org.joda.time.DateTimeZone;
|
||||||
|
import org.joda.time.Instant;
|
||||||
import org.joda.time.LocalDate;
|
import org.joda.time.LocalDate;
|
||||||
import org.joda.time.LocalDateTime;
|
import org.joda.time.LocalDateTime;
|
||||||
import org.joda.time.LocalTime;
|
import org.joda.time.LocalTime;
|
||||||
|
import org.joda.time.MutableDateTime;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -310,6 +312,41 @@ public class JodaTimeFormattingTests {
|
||||||
assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("isoDateTime"));
|
assertEquals("2009-10-31T07:00:00.000-05:00", binder.getBindingResult().getFieldValue("isoDateTime"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindInstant() {
|
||||||
|
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||||
|
propertyValues.add("instant", "10/31/09 12:00 PM");
|
||||||
|
binder.bind(propertyValues);
|
||||||
|
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||||
|
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("instant"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindInstantAnnotated() {
|
||||||
|
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||||
|
propertyValues.add("instantAnnotated", "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("instantAnnotated"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindMutableDateTime() {
|
||||||
|
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||||
|
propertyValues.add("mutableDateTime", "10/31/09 12:00 PM");
|
||||||
|
binder.bind(propertyValues);
|
||||||
|
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||||
|
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("mutableDateTime"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBindMutableDateTimeAnnotated() {
|
||||||
|
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||||
|
propertyValues.add("mutableDateTimeAnnotated", "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("mutableDateTimeAnnotated"));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private static class JodaTimeBean {
|
private static class JodaTimeBean {
|
||||||
|
|
@ -368,6 +405,16 @@ public class JodaTimeFormattingTests {
|
||||||
@DateTimeFormat(iso=ISO.DATE_TIME)
|
@DateTimeFormat(iso=ISO.DATE_TIME)
|
||||||
private DateTime isoDateTime;
|
private DateTime isoDateTime;
|
||||||
|
|
||||||
|
private Instant instant;
|
||||||
|
|
||||||
|
@DateTimeFormat(iso=ISO.DATE_TIME)
|
||||||
|
private Instant instantAnnotated;
|
||||||
|
|
||||||
|
private MutableDateTime mutableDateTime;
|
||||||
|
|
||||||
|
@DateTimeFormat(iso=ISO.DATE_TIME)
|
||||||
|
private Instant mutableDateTimeAnnotated;
|
||||||
|
|
||||||
private final List<JodaTimeBean> children = new ArrayList<JodaTimeBean>();
|
private final List<JodaTimeBean> children = new ArrayList<JodaTimeBean>();
|
||||||
|
|
||||||
public LocalDate getLocalDate() {
|
public LocalDate getLocalDate() {
|
||||||
|
|
@ -530,6 +577,38 @@ public class JodaTimeFormattingTests {
|
||||||
public void setIsoDateTime(DateTime isoDateTime) {
|
public void setIsoDateTime(DateTime isoDateTime) {
|
||||||
this.isoDateTime = isoDateTime;
|
this.isoDateTime = isoDateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Instant getInstant() {
|
||||||
|
return instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstant(Instant instant) {
|
||||||
|
this.instant = instant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getInstantAnnotated() {
|
||||||
|
return instantAnnotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInstantAnnotated(Instant instantAnnotated) {
|
||||||
|
this.instantAnnotated = instantAnnotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableDateTime getMutableDateTime() {
|
||||||
|
return mutableDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMutableDateTime(MutableDateTime mutableDateTime) {
|
||||||
|
this.mutableDateTime = mutableDateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getMutableDateTimeAnnotated() {
|
||||||
|
return mutableDateTimeAnnotated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMutableDateTimeAnnotated(Instant mutableDateTimeAnnotated) {
|
||||||
|
this.mutableDateTimeAnnotated = mutableDateTimeAnnotated;
|
||||||
|
}
|
||||||
|
|
||||||
public List<JodaTimeBean> getChildren() {
|
public List<JodaTimeBean> getChildren() {
|
||||||
return children;
|
return children;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue