提交 b5d44e1d 编写于 作者: J Juergen Hoeller

Revised Joda-Time support (as a side effect of JSR-310 support in Spring 4.0)

Issue: SPR-9641
上级 d3a40687
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -23,22 +23,26 @@ import java.lang.annotation.Target;
/**
* Declares that a field should be formatted as a date time.
* Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long}, or Joda Time fields.
* <p>
* For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
*
* <p>Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
* Can be applied to {@code java.util.Date}, {@code java.util.Calendar}, {@code java.long.Long},
* Joda-Time value types; and as of Spring 4 and JDK 8, to JSR-310 <code>java.time</code> types too.
*
* <p>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 '-'.
* <p>
* For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format, such as {@link ISO#DATE}.
<p>
* For custom formatting, set the {@link #pattern()} attribute to be the DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
* <p>
* Each attribute is mutually exclusive, so only set one attribute per annotation instance (the one most convenient one for your formatting needs).
*
* <p>For ISO-based formatting, set the {@link #iso()} attribute to be the desired {@link ISO} format,
* such as {@link ISO#DATE}. For custom formatting, set the {@link #pattern()} attribute to be the
* DateTime pattern, such as {@code yyyy/MM/dd hh:mm:ss a}.
*
* <p>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).
* 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
* @author Juergen Hoeller
......@@ -51,23 +55,24 @@ public @interface DateTimeFormat {
/**
* The style pattern to use to format the field.
* Defaults to 'SS' for short date time.
* Set this attribute when you wish to format your field in accordance with a common style other than the default style.
* <p>Defaults to 'SS' for short date time. Set this attribute when you wish to format
* your field in accordance with a common style other than the default style.
*/
String style() default "SS";
/**
* The ISO pattern to use 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.
* Set this attribute when you wish to format your field in accordance with an ISO date time format.
* <p>Defaults to {@link ISO#NONE}, indicating this attribute should be ignored.
* Set this attribute when you wish to format your field in accordance with an ISO format.
*/
ISO iso() default ISO.NONE;
/**
* The custom pattern to use to format the field.
* Defaults to empty String, indicating no custom pattern String has been specified.
* Set this attribute when you wish to format your field in accordance with a custom date time pattern not represented by a style or ISO format.
* <p>Defaults to empty String, indicating no custom pattern String has been specified.
* Set this attribute when you wish to format your field in accordance with a custom
* date time pattern not represented by a style or ISO format.
*/
String pattern() default "";
......@@ -78,18 +83,21 @@ public @interface DateTimeFormat {
public enum ISO {
/**
* The most common ISO Date Format {@code yyyy-MM-dd} e.g. 2000-10-31.
* The most common ISO Date Format {@code yyyy-MM-dd},
* e.g. 2000-10-31.
*/
DATE,
/**
* The most common ISO Time Format {@code HH:mm:ss.SSSZ} e.g. 01:30:00.000-05:00.
* The most common ISO Time Format {@code HH:mm:ss.SSSZ},
* e.g. 01:30:00.000-05:00.
*/
TIME,
/**
* The most common ISO DateTime Format {@code 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.
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
* e.g. 2000-10-31 01:30:00.000-05:00.
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -46,7 +46,7 @@ public class DateFormatter implements Formatter<Date> {
private static final Map<ISO, String> ISO_PATTERNS;
static {
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>();
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>(4);
formats.put(ISO.DATE, "yyyy-MM-dd");
formats.put(ISO.TIME, "HH:mm:ss.SSSZ");
formats.put(ISO.DATE_TIME, "yyyy-MM-dd'T'HH:mm:ss.SSSZ");
......@@ -89,6 +89,15 @@ public class DateFormatter implements Formatter<Date> {
this.pattern = pattern;
}
/**
* Set the ISO format used for this date.
* @param iso the {@link ISO} format
* @since 3.2
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the style to use to format date values.
* <p>If not specified, DateFormat's default style will be used.
......@@ -112,7 +121,7 @@ public class DateFormatter implements Formatter<Date> {
* <li>'F' = Full</li>
* <li>'-' = Omitted</li>
* <ul>
* This method mimics the styles supported by Joda Time.
* This method mimics the styles supported by Joda-Time.
* @param stylePattern two characters from the set {"S", "M", "L", "F", "-"}
* @since 3.2
*/
......@@ -120,14 +129,6 @@ public class DateFormatter implements Formatter<Date> {
this.stylePattern = stylePattern;
}
/**
* Set the ISO format used for this date.
* @param iso the {@link ISO} format
* @since 3.2
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the TimeZone to normalize the date values into, if any.
*/
......@@ -204,4 +205,5 @@ public class DateFormatter implements Formatter<Date> {
}
throw new IllegalStateException("Unsupported style pattern '"+ stylePattern+ "'");
}
}
......@@ -27,8 +27,8 @@ import org.springframework.util.Assert;
/**
* Configures Date formatting for use with Spring.
* <p>
* Designed for direct instantiation but also exposes the static
*
* <p>Designed for direct instantiation but also exposes the static
* {@link #addDateConverters(ConverterRegistry)} utility method for ad hoc use
* against any {@code ConverterRegistry} instance.
*
......@@ -39,10 +39,20 @@ import org.springframework.util.Assert;
*/
public class DateFormatterRegistrar implements FormatterRegistrar {
private DateFormatter dateFormatter;
/**
* 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) {
Assert.notNull(dateFormatter, "DateFormatter must not be null");
this.dateFormatter = dateFormatter;
}
public void registerFormatters(FormatterRegistry registry) {
addDateConverters(registry);
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
......@@ -55,16 +65,6 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
}
}
/**
* 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) {
Assert.notNull(dateFormatter, "DateFormatter must not be null");
this.dateFormatter = dateFormatter;
}
/**
* Add date converters to the specified registry.
* @param converterRegistry the registry of converters to add to
......@@ -80,6 +80,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class DateToLongConverter implements Converter<Date, Long> {
public Long convert(Date source) {
return source.getTime();
}
......@@ -87,6 +88,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class DateToCalendarConverter implements Converter<Date, Calendar> {
public Calendar convert(Date source) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(source);
......@@ -96,6 +98,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class CalendarToDateConverter implements Converter<Calendar, Date> {
public Date convert(Calendar source) {
return source.getTime();
}
......@@ -103,6 +106,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class CalendarToLongConverter implements Converter<Calendar, Long> {
public Long convert(Calendar source) {
return source.getTime().getTime();
}
......@@ -110,6 +114,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class LongToDateConverter implements Converter<Long, Date> {
public Date convert(Long source) {
return new Date(source);
}
......@@ -118,10 +123,11 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private static class LongToCalendarConverter implements Converter<Long, Calendar> {
private DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
private final DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
public Calendar convert(Long source) {
return this.dateToCalendarConverter.convert(new Date(source));
}
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -44,7 +44,7 @@ public class DateTimeFormatAnnotationFormatterFactory implements
private static final Set<Class<?>> FIELD_TYPES;
static {
Set<Class<?>> fieldTypes = new HashSet<Class<?>>();
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(4);
fieldTypes.add(Date.class);
fieldTypes.add(Calendar.class);
fieldTypes.add(Long.class);
......@@ -82,4 +82,5 @@ public class DateTimeFormatAnnotationFormatterFactory implements
protected String resolveEmbeddedValue(String value) {
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -22,32 +22,34 @@ import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.util.StringUtils;
/**
* Factory that creates a Joda {@link DateTimeFormatter}. Formatters will be
* created using the defined {@link #setPattern(String) pattern}, {@link #setIso ISO},
* or {@link #setStyle(String) style} (considered in that order).
* Factory that creates a Joda-Time {@link DateTimeFormatter}.
*
* <p>Formatters will be created using the defined {@link #setPattern pattern},
* {@link #setIso ISO}, and {@link #setStyle style} methods (considered in that order).
*
* @author Phillip Webb
* @author Sam Brannen
* @since 3.2
* @see #createDateTimeFormatter()
* @see #createDateTimeFormatter(DateTimeFormatter)
* @see #setPattern(String)
* @see #setPattern
* @see #setStyle
* @see #setIso
* @see #setStyle(String)
* @see DateTimeFormatterFactoryBean
*/
public class DateTimeFormatterFactory {
private String pattern;
private ISO iso;
private String style;
private String pattern;
private TimeZone timeZone;
......@@ -67,9 +69,50 @@ public class DateTimeFormatterFactory {
/**
* Create a new {@code DateTimeFormatter} using this factory. If no specific
* {@link #setStyle(String) style}, {@link #setIso ISO}, or
* {@link #setPattern(String) pattern} have been defined the
* Set the pattern to use to format date values.
* @param pattern the format pattern
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
/**
* Set the ISO format used to format date values.
* @param iso the ISO format
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the two characters to use to format date values, in Joda-Time style.
* <p>The first character is used for the date style; the second is for
* the time style. Supported characters are:
* <ul>
* <li>'S' = Small</li>
* <li>'M' = Medium</li>
* <li>'L' = Long</li>
* <li>'F' = Full</li>
* <li>'-' = Omitted</li>
* </ul>
* @param style two characters from the set {"S", "M", "L", "F", "-"}
*/
public void setStyle(String style) {
this.style = style;
}
/**
* Set the {@code TimeZone} to normalize the date values into, if any.
* @param timeZone the time zone
*/
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
/**
* Create a new {@code DateTimeFormatter} using this factory.
* <p>If no specific pattern or style has been defined,
* {@link DateTimeFormat#mediumDateTime() medium date time format} will be used.
* @return a new date time formatter
* @see #createDateTimeFormatter(DateTimeFormatter)
......@@ -79,21 +122,20 @@ public class DateTimeFormatterFactory {
}
/**
* Create a new {@code DateTimeFormatter} using this factory. If no specific
* {@link #setStyle(String) style}, {@link #setIso ISO}, or
* {@link #setPattern(String) pattern} have been defined the supplied
* {@code fallbackFormatter} will be used.
* @param fallbackFormatter the fall-back formatter to use when no specific factory
* properties have been set (can be {@code null}).
* Create a new {@code DateTimeFormatter} using this factory.
* <p>If no specific pattern or style has been defined,
* the supplied {@code fallbackFormatter} will be used.
* @param fallbackFormatter the fall-back formatter to use when no specific
* factory properties have been set (can be {@code null}).
* @return a new date time formatter
*/
public DateTimeFormatter createDateTimeFormatter(DateTimeFormatter fallbackFormatter) {
DateTimeFormatter dateTimeFormatter = null;
if (StringUtils.hasLength(pattern)) {
dateTimeFormatter = DateTimeFormat.forPattern(pattern);
if (StringUtils.hasLength(this.pattern)) {
dateTimeFormatter = DateTimeFormat.forPattern(this.pattern);
}
else if (iso != null && iso != ISO.NONE) {
switch (iso) {
else if (this.iso != null && this.iso != ISO.NONE) {
switch (this.iso) {
case DATE:
dateTimeFormatter = ISODateTimeFormat.date();
break;
......@@ -107,11 +149,11 @@ public class DateTimeFormatterFactory {
/* no-op */
break;
default:
throw new IllegalStateException("Unsupported ISO format: " + iso);
throw new IllegalStateException("Unsupported ISO format: " + this.iso);
}
}
else if (StringUtils.hasLength(style)) {
dateTimeFormatter = DateTimeFormat.forStyle(style);
else if (StringUtils.hasLength(this.style)) {
dateTimeFormatter = DateTimeFormat.forStyle(this.style);
}
if (dateTimeFormatter != null && this.timeZone != null) {
......@@ -120,44 +162,4 @@ public class DateTimeFormatterFactory {
return (dateTimeFormatter != null ? dateTimeFormatter : fallbackFormatter);
}
/**
* Set the {@code TimeZone} to normalize the date values into, if any.
* @param timeZone the time zone
*/
public void setTimeZone(TimeZone timeZone) {
this.timeZone = timeZone;
}
/**
* Set the two characters to use to format date values. The first character is used for
* the date style; the second is for the time style. Supported characters are:
* <ul>
* <li>'S' = Small</li>
* <li>'M' = Medium</li>
* <li>'L' = Long</li>
* <li>'F' = Full</li>
* <li>'-' = Omitted</li>
* </ul>
* <p>This method mimics the styles supported by Joda Time.
* @param style two characters from the set {"S", "M", "L", "F", "-"}
*/
public void setStyle(String style) {
this.style = style;
}
/**
* Set the ISO format used to format date values.
* @param iso the ISO format
*/
public void setIso(ISO iso) {
this.iso = iso;
}
/**
* Set the pattern to use to format date values.
* @param pattern the format pattern
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -22,15 +22,15 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
/**
* {@link FactoryBean} that creates a Joda {@link DateTimeFormatter}. See the
* {@linkplain DateTimeFormatterFactory base class} for configuration details.
* {@link FactoryBean} that creates a Joda-Time {@link DateTimeFormatter}.
* See the {@link DateTimeFormatterFactory base class} for configuration details.
*
* @author Phillip Webb
* @author Sam Brannen
* @since 3.2
* @see #setPattern(String)
* @see #setIso(org.springframework.format.annotation.DateTimeFormat.ISO)
* @see #setStyle(String)
* @see #setPattern
* @see #setIso
* @see #setStyle
* @see DateTimeFormatterFactory
*/
public class DateTimeFormatterFactoryBean extends DateTimeFormatterFactory
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -25,7 +25,7 @@ import org.joda.time.format.DateTimeFormatter;
import org.springframework.format.Parser;
/**
* Parses Joda Time {@link DateTime} instances using a {@link DateTimeFormatter}.
* Parses Joda {@link DateTime} instances using a {@link DateTimeFormatter}.
*
* @author Keith Donald
* @since 3.0
......@@ -34,6 +34,7 @@ public final class DateTimeParser implements Parser<DateTime> {
private final DateTimeFormatter formatter;
/**
* Create a new DateTimeParser.
* @param formatter the Joda DateTimeFormatter instance
......@@ -42,6 +43,7 @@ public final class DateTimeParser implements Parser<DateTime> {
this.formatter = formatter;
}
public DateTime parse(String text, Locale locale) throws ParseException {
return JodaTimeContextHolder.getFormatter(this.formatter, locale).parseDateTime(text);
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -56,7 +56,7 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
// (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)
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(7);
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(8);
fieldTypes.add(ReadableInstant.class);
fieldTypes.add(LocalDate.class);
fieldTypes.add(LocalTime.class);
......@@ -71,10 +71,6 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
private StringValueResolver embeddedValueResolver;
public final Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.embeddedValueResolver = resolver;
}
......@@ -83,20 +79,24 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
}
public final Set<Class<?>> getFieldTypes() {
return FIELD_TYPES;
}
public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
if (ReadableInstant.class.isAssignableFrom(fieldType)) {
return new ReadableInstantPrinter(formatter);
}
if (ReadablePartial.class.isAssignableFrom(fieldType)) {
return new ReadablePartialPrinter(formatter);
}
if (Calendar.class.isAssignableFrom(fieldType)) {
else if (ReadableInstant.class.isAssignableFrom(fieldType) || Calendar.class.isAssignableFrom(fieldType)) {
// assumes Calendar->ReadableInstant converter is registered
return new ReadableInstantPrinter(formatter);
}
// assumes Date->Long converter is registered
return new MillisecondInstantPrinter(formatter);
else {
// assumes Date->Long converter is registered
return new MillisecondInstantPrinter(formatter);
}
}
public Parser<DateTime> getParser(DateTimeFormat annotation, Class<?> fieldType) {
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -21,8 +21,10 @@ import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormatter;
/**
* A context that holds user-specific Joda Time settings such as the user's Chronology (calendar system) and time zone.
* A {@code null} property value indicate the user has not specified a setting.
* A context that holds user-specific Joda-Time settings such as the user's
* Chronology (calendar system) and time zone.
*
* <p>A {@code null} property value indicate the user has not specified a setting.
*
* @author Keith Donald
* @since 3.0
......@@ -43,8 +45,7 @@ public class JodaTimeContext {
}
/**
* The user's chronology (calendar system).
* Null if not specified.
* The user's chronology (calendar system), if any.
*/
public Chronology getChronology() {
return this.chronology;
......@@ -58,8 +59,7 @@ public class JodaTimeContext {
}
/**
* The user's timezone.
* Null if not specified.
* The user's timezone, if any.
*/
public DateTimeZone getTimeZone() {
return timeZone;
......@@ -67,9 +67,11 @@ public class JodaTimeContext {
/**
* Gets the Formatter with the this context's settings applied to the base {@code formatter}.
* @param formatter the base formatter that establishes default formatting rules, generally context independent
* @return the context DateTimeFormatter
* Get the DateTimeFormatter with the this context's settings
* applied to the base {@code formatter}.
* @param formatter the base formatter that establishes default
* formatting rules, generally context-independent
* @return the contextual DateTimeFormatter
*/
public DateTimeFormatter getFormatter(DateTimeFormatter formatter) {
if (this.chronology != null) {
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -23,7 +23,8 @@ import org.joda.time.format.DateTimeFormatter;
import org.springframework.core.NamedThreadLocal;
/**
* A holder for a thread-local user {@link JodaTimeContext}.
* A holder for a thread-local {@link JodaTimeContext}
* with user-specific Joda-Time settings.
*
* @author Keith Donald
* @author Juergen Hoeller
......
......@@ -27,12 +27,14 @@ import org.joda.time.LocalDateTime;
import org.joda.time.LocalTime;
import org.joda.time.MutableDateTime;
import org.joda.time.ReadableInstant;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.format.datetime.DateFormatterRegistrar;
/**
* Installs lower-level type converters required to integrate Joda Time support into Spring's field formatting system.
* Installs lower-level type converters required to integrate
* Joda-Time support into Spring's field formatting system.
*
* @author Keith Donald
* @author Phillip Webb
......@@ -50,125 +52,111 @@ final class JodaTimeConverters {
registry.addConverter(new DateTimeToLocalTimeConverter());
registry.addConverter(new DateTimeToLocalDateTimeConverter());
registry.addConverter(new DateTimeToDateMidnightConverter());
registry.addConverter(new DateTimeToInstantConverter());
registry.addConverter(new DateTimeToMutableDateTimeConverter());
registry.addConverter(new DateTimeToInstantConverter());
registry.addConverter(new DateTimeToDateConverter());
registry.addConverter(new DateTimeToCalendarConverter());
registry.addConverter(new DateTimeToLongConverter());
registry.addConverter(new CalendarToReadableInstantConverter());
registry.addConverter(new DateToReadableInstantConverter());
registry.addConverter(new CalendarToReadableInstantConverter());
}
/**
* Used when binding a parsed DateTime to a LocalDate field.
* @see DateTimeParser
**/
private static class DateTimeToLocalDateConverter implements Converter<DateTime, LocalDate> {
public LocalDate convert(DateTime source) {
return source.toLocalDate();
}
}
/**
* Used when binding a parsed DateTime to a LocalTime field.
* @see DateTimeParser
*/
private static class DateTimeToLocalTimeConverter implements Converter<DateTime, LocalTime> {
public LocalTime convert(DateTime source) {
return source.toLocalTime();
}
}
/**
* Used when binding a parsed DateTime to a LocalDateTime field.
* @see DateTimeParser
*/
private static class DateTimeToLocalDateTimeConverter implements Converter<DateTime, LocalDateTime> {
public LocalDateTime convert(DateTime source) {
return source.toLocalDateTime();
}
}
/**
* Used when binding a parsed DateTime to a DateMidnight field.
* @see DateTimeParser
*/
private static class DateTimeToDateMidnightConverter implements Converter<DateTime, DateMidnight> {
public DateMidnight convert(DateTime source) {
return source.toDateMidnight();
}
}
/**
* 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.
* @see DateTimeParser
*/
private static class DateTimeToInstantConverter implements Converter<DateTime, Instant> {
public Instant convert(DateTime source) {
return source.toInstant();
}
}
private static class DateTimeToDateConverter implements Converter<DateTime, Date> {
public Date convert(DateTime source) {
return source.toDate();
}
}
/**
* Used when binding a parsed DateTime to a java.util.Calendar field.
* @see DateTimeParser
*/
private static class DateTimeToCalendarConverter implements Converter<DateTime, Calendar> {
public Calendar convert(DateTime source) {
return source.toGregorianCalendar();
}
}
/**
* Used when binding a parsed DateTime to a java.lang.Long field.
* @see DateTimeParser
*/
private static class DateTimeToLongConverter implements Converter<DateTime, Long> {
public Long convert(DateTime source) {
return source.getMillis();
}
}
/**
* Used when printing a java.util.Calendar field with a ReadableInstantPrinter.
* Used when printing a java.util.Date field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class CalendarToReadableInstantConverter implements Converter<Calendar, ReadableInstant> {
public ReadableInstant convert(Calendar source) {
private static class DateToReadableInstantConverter implements Converter<Date, ReadableInstant> {
public ReadableInstant convert(Date source) {
return new DateTime(source);
}
}
/**
* Used when printing a java.util.Date field with a ReadableInstantPrinter.
* Used when printing a java.util.Calendar field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class DateToReadableInstantConverter implements Converter<Date, ReadableInstant> {
public ReadableInstant convert(Date source) {
private static class CalendarToReadableInstantConverter implements Converter<Calendar, ReadableInstant> {
public ReadableInstant convert(Calendar source) {
return new DateTime(source);
}
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.format.datetime.joda;
import java.util.Calendar;
......@@ -35,7 +36,7 @@ import org.springframework.format.Printer;
import org.springframework.format.annotation.DateTimeFormat.ISO;
/**
* Configures Joda Time's formatting system for use with Spring.
* Configures Joda-Time's formatting system for use with Spring.
*
* @author Keith Donald
* @author Juergen Hoeller
......@@ -51,15 +52,18 @@ import org.springframework.format.annotation.DateTimeFormat.ISO;
*/
public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
private static enum Type {DATE, TIME, DATE_TIME}
/**
* User defined formatters.
*/
private Map<Type, DateTimeFormatter> formatters = new HashMap<Type, DateTimeFormatter>();
private final Map<Type, DateTimeFormatter> formatters = new HashMap<Type, DateTimeFormatter>();
/**
* Factories used when specific formatters have not been specified.
*/
private Map<Type, DateTimeFormatterFactory> factories;
private final Map<Type, DateTimeFormatterFactory> factories;
public JodaTimeFormatterRegistrar() {
......@@ -70,12 +74,24 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
}
/**
* Set whether standard ISO formatting should be applied to all date/time types.
* Default is "false" (no).
* <p>If set to "true", the "dateStyle", "timeStyle" and "dateTimeStyle"
* properties are effectively ignored.
*/
public void setUseIsoFormat(boolean useIsoFormat) {
this.factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
this.factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
this.factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
}
/**
* Set the default format style of Joda {@link LocalDate} objects.
* Default is {@link DateTimeFormat#shortDate()}.
*/
public void setDateStyle(String dateStyle) {
this.factories.get(Type.DATE).setStyle(dateStyle+"-");
this.factories.get(Type.DATE).setStyle(dateStyle + "-");
}
/**
......@@ -83,7 +99,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* Default is {@link DateTimeFormat#shortTime()}.
*/
public void setTimeStyle(String timeStyle) {
this.factories.get(Type.TIME).setStyle("-"+timeStyle);
this.factories.get(Type.TIME).setStyle("-" + timeStyle);
}
/**
......@@ -95,25 +111,14 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
this.factories.get(Type.DATE_TIME).setStyle(dateTimeStyle);
}
/**
* Set whether standard ISO formatting should be applied to all Date/Time types.
* Default is false (no).
* If set to true, the dateStyle, timeStyle, and dateTimeStyle properties are ignored.
*/
public void setUseIsoFormat(boolean useIsoFormat) {
this.factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
this.factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
this.factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
}
/**
* Set the formatter that will be used for objects representing date values.
* <p>This formatter will be used for the {@link LocalDate} type. When specified
* the {@link #setDateStyle(String) dateStyle} and
* {@link #setUseIsoFormat(boolean) useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setTimeFormatter(DateTimeFormatter)
* @see #setDateTimeFormatter(DateTimeFormatter)
* @see #setTimeFormatter
* @see #setDateTimeFormatter
* @since 3.2
*/
public void setDateFormatter(DateTimeFormatter formatter) {
......@@ -126,8 +131,8 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* the {@link #setTimeStyle(String) timeStyle} and
* {@link #setUseIsoFormat(boolean) useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setDateFormatter(DateTimeFormatter)
* @see #setDateTimeFormatter(DateTimeFormatter)
* @see #setDateFormatter
* @see #setDateTimeFormatter
* @since 3.2
*/
public void setTimeFormatter(DateTimeFormatter formatter) {
......@@ -141,14 +146,15 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* the {@link #setDateTimeStyle(String) dateTimeStyle} and
* {@link #setUseIsoFormat(boolean) useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setDateFormatter(DateTimeFormatter)
* @see #setTimeFormatter(DateTimeFormatter)
* @see #setDateFormatter
* @see #setTimeFormatter
* @since 3.2
*/
public void setDateTimeFormatter(DateTimeFormatter formatter) {
this.formatters.put(Type.DATE_TIME, formatter);
}
public void registerFormatters(FormatterRegistry registry) {
JodaTimeConverters.registerConverters(registry);
......@@ -176,26 +182,25 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
new DateTimeParser(dateTimeFormatter),
ReadableInstant.class);
// In order to retain back compatibility we only register Date/Calendar
// In order to retain backwards compatibility we only register Date/Calendar
// types when a user defined formatter is specified (see SPR-10105)
if(this.formatters.containsKey(Type.DATE_TIME)) {
if( this.formatters.containsKey(Type.DATE_TIME)) {
addFormatterForFields(registry,
new ReadableInstantPrinter(dateTimeFormatter),
new DateTimeParser(dateTimeFormatter),
Date.class, Calendar.class);
}
registry.addFormatterForFieldAnnotation(
new JodaDateTimeFormatAnnotationFormatterFactory());
registry.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory());
}
private DateTimeFormatter getFormatter(Type type) {
DateTimeFormatter formatter = this.formatters.get(type);
if(formatter != null) {
if (formatter != null) {
return formatter;
}
DateTimeFormatter fallbackFormatter = getFallbackFormatter(type);
return this.factories.get(type).createDateTimeFormatter(fallbackFormatter );
return this.factories.get(type).createDateTimeFormatter(fallbackFormatter);
}
private DateTimeFormatter getFallbackFormatter(Type type) {
......@@ -208,10 +213,10 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
private void addFormatterForFields(FormatterRegistry registry, Printer<?> printer,
Parser<?> parser, Class<?>... fieldTypes) {
for (Class<?> fieldType : fieldTypes) {
registry.addFormatterForFieldType(fieldType, printer, parser);
}
}
private static enum Type {DATE, TIME, DATE_TIME}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -23,7 +23,7 @@ import org.joda.time.format.DateTimeFormatter;
import org.springframework.format.Printer;
/**
* Prints Long instances using a {@link DateTimeFormatter}.
* Prints Long instances using a Joda {@link DateTimeFormatter}.
*
* @author Keith Donald
* @since 3.0
......@@ -32,6 +32,7 @@ public final class MillisecondInstantPrinter implements Printer<Long> {
private final DateTimeFormatter formatter;
/**
* Create a new ReadableInstantPrinter.
* @param formatter the Joda DateTimeFormatter instance
......@@ -40,6 +41,7 @@ public final class MillisecondInstantPrinter implements Printer<Long> {
this.formatter = formatter;
}
public String print(Long instant, Locale locale) {
return JodaTimeContextHolder.getFormatter(this.formatter, locale).print(instant);
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -20,10 +20,11 @@ import java.util.Locale;
import org.joda.time.ReadableInstant;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.format.Printer;
/**
* Prints JodaTime {@link ReadableInstant} instances using a {@link DateTimeFormatter}.
* Prints Joda-Time {@link ReadableInstant} instances using a {@link DateTimeFormatter}.
*
* @author Keith Donald
* @since 3.0
......@@ -32,6 +33,7 @@ public final class ReadableInstantPrinter implements Printer<ReadableInstant> {
private final DateTimeFormatter formatter;
/**
* Create a new ReadableInstantPrinter.
* @param formatter the Joda DateTimeFormatter instance
......@@ -40,6 +42,7 @@ public final class ReadableInstantPrinter implements Printer<ReadableInstant> {
this.formatter = formatter;
}
public String print(ReadableInstant instant, Locale locale) {
return JodaTimeContextHolder.getFormatter(this.formatter, locale).print(instant);
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -24,7 +24,7 @@ import org.joda.time.format.DateTimeFormatter;
import org.springframework.format.Printer;
/**
* Prints JodaTime {@link ReadablePartial} instances using a {@link DateTimeFormatter}.
* Prints Joda-Time {@link ReadablePartial} instances using a {@link DateTimeFormatter}.
*
* @author Keith Donald
* @since 3.0
......@@ -33,6 +33,7 @@ public final class ReadablePartialPrinter implements Printer<ReadablePartial> {
private final DateTimeFormatter formatter;
/**
* Create a new ReadableInstantPrinter.
* @param formatter the Joda DateTimeFormatter instance
......@@ -41,6 +42,7 @@ public final class ReadablePartialPrinter implements Printer<ReadablePartial> {
this.formatter = formatter;
}
public String print(ReadablePartial partial, Locale locale) {
return JodaTimeContextHolder.getFormatter(this.formatter, locale).print(partial);
}
......
/**
* Integration with the Joda Time for formatting Joda types as well as standard JDK Date types.
* Integration with Joda-Time for formatting Joda date and time types as well as standard JDK Date types.
*/
package org.springframework.format.datetime.joda;
......@@ -26,8 +26,6 @@ import org.joda.time.format.DateTimeFormatter;
import org.junit.Test;
/**
* Tests for {@link DateTimeFormatterFactoryBean}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
......@@ -60,4 +58,5 @@ public class DateTimeFormatterFactoryBeanTests {
factory.setStyle("LL");
assertThat(factory.getObject(), is(sameInstance(formatter)));
}
}
......@@ -30,8 +30,6 @@ import org.junit.Test;
import org.springframework.format.annotation.DateTimeFormat.ISO;
/**
* Tests for {@link DateTimeFormatterFactory}.
*
* @author Phillip Webb
* @author Sam Brannen
*/
......@@ -100,4 +98,5 @@ public class DateTimeFormatterFactoryTests {
private DateTimeFormatter applyLocale(DateTimeFormatter dateTimeFormatter) {
return dateTimeFormatter.withLocale(Locale.US);
}
}
......@@ -116,7 +116,7 @@ public class JodaTimeFormattingTests {
}
@Test
public void testBindLocalDateWithSpecifcFormatter() throws Exception {
public void testBindLocalDateWithSpecificFormatter() throws Exception {
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
registrar.setDateFormatter(org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd"));
setUp(registrar);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册