Merge pull request #161 from philwebb/SPR-7121
* SPR-7121: Support for custom global Joda DateTimeFormatters Move JRuby dependency below Joda Support DateTimeFormat annotation without Joda Corrected date pattern in JavaDocs Polish whitespace and formatting
This commit is contained in:
@@ -262,12 +262,12 @@ project('spring-context') {
|
||||
}
|
||||
compile("org.beanshell:bsh:2.0b4", optional)
|
||||
compile("org.codehaus.groovy:groovy-all:1.6.3", optional)
|
||||
compile("org.jruby:jruby:1.4.0", optional)
|
||||
compile("org.hibernate:hibernate-validator:4.2.0.Final") { dep ->
|
||||
optional dep
|
||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||
}
|
||||
compile("joda-time:joda-time:1.6", optional)
|
||||
compile("org.jruby:jruby:1.4.0", optional)
|
||||
compile("javax.cache:cache-api:0.5", optional)
|
||||
compile("net.sf.ehcache:ehcache-core:2.0.0", optional)
|
||||
compile("org.slf4j:slf4j-api:1.6.1", optional)
|
||||
|
||||
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
|
||||
* Supports formatting by style pattern, ISO date time pattern, or custom format pattern string.
|
||||
* Can be applied to <code>java.util.Date</code>, <code>java.util.Calendar</code>, <code>java.long.Long</code>, or Joda Time fields.
|
||||
* <p>
|
||||
* For style-based formatting, set the {@link #style()} attribute to be the style pattern code.
|
||||
* 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 '-'.
|
||||
@@ -39,7 +39,7 @@ import java.lang.annotation.Target;
|
||||
* 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
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
@@ -76,23 +76,23 @@ public @interface DateTimeFormat {
|
||||
* Common ISO date time format patterns.
|
||||
*/
|
||||
public enum ISO {
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* The most common ISO Date Format <code>yyyy-MM-dd</code> e.g. 2000-10-31.
|
||||
*/
|
||||
DATE,
|
||||
|
||||
/**
|
||||
* The most common ISO Time Format <code>hh:mm:ss.SSSZ</code> e.g. 01:30:00.000-05:00.
|
||||
/**
|
||||
* The most common ISO Time Format <code>HH:mm:ss.SSSZ</code> e.g. 01:30:00.000-05:00.
|
||||
*/
|
||||
TIME,
|
||||
|
||||
/**
|
||||
* The most common ISO DateTime Format <code>yyyy-MM-dd'T'hh:mm:ss.SSSZ</code> e.g. 2000-10-31 01:30:00.000-05:00.
|
||||
/**
|
||||
* The most common ISO DateTime Format <code>yyyy-MM-dd'T'HH:mm:ss.SSSZ</code> 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.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -19,11 +19,18 @@ package org.springframework.format.datetime;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A formatter for {@link java.util.Date} types.
|
||||
@@ -31,15 +38,30 @@ import org.springframework.format.Formatter;
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @since 3.0
|
||||
* @see SimpleDateFormat
|
||||
* @see SimpleDateFormat
|
||||
*/
|
||||
public class DateFormatter implements Formatter<Date> {
|
||||
|
||||
private static final Map<ISO, String> ISO_PATTERNS;
|
||||
static {
|
||||
Map<ISO, String> formats = new HashMap<DateTimeFormat.ISO, String>();
|
||||
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");
|
||||
ISO_PATTERNS = Collections.unmodifiableMap(formats);
|
||||
}
|
||||
|
||||
|
||||
private String pattern;
|
||||
|
||||
private int style = DateFormat.DEFAULT;
|
||||
|
||||
private String stylePattern;
|
||||
|
||||
private ISO iso;
|
||||
|
||||
private TimeZone timeZone;
|
||||
|
||||
private boolean lenient = false;
|
||||
@@ -80,6 +102,32 @@ public class DateFormatter implements Formatter<Date> {
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the two character to use to format date values. The first character 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>
|
||||
* This method mimics the styles supported by Joda Time.
|
||||
* @param stylePattern two characters from the set {"S", "M", "L", "F", "-"}
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setStylePattern(String stylePattern) {
|
||||
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.
|
||||
*/
|
||||
@@ -107,13 +155,7 @@ public class DateFormatter implements Formatter<Date> {
|
||||
|
||||
|
||||
protected DateFormat getDateFormat(Locale locale) {
|
||||
DateFormat dateFormat;
|
||||
if (this.pattern != null) {
|
||||
dateFormat = new SimpleDateFormat(this.pattern, locale);
|
||||
}
|
||||
else {
|
||||
dateFormat = DateFormat.getDateInstance(this.style, locale);
|
||||
}
|
||||
DateFormat dateFormat = createDateFormat(locale);
|
||||
if (this.timeZone != null) {
|
||||
dateFormat.setTimeZone(this.timeZone);
|
||||
}
|
||||
@@ -121,4 +163,45 @@ public class DateFormatter implements Formatter<Date> {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
private DateFormat createDateFormat(Locale locale) {
|
||||
if (StringUtils.hasLength(this.pattern)) {
|
||||
return new SimpleDateFormat(this.pattern, locale);
|
||||
}
|
||||
if (iso != null && iso != ISO.NONE) {
|
||||
String pattern = ISO_PATTERNS.get(iso);
|
||||
Assert.state(pattern != null, "Unsupported ISO format " + iso);
|
||||
SimpleDateFormat format = new SimpleDateFormat(pattern);
|
||||
format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return format;
|
||||
}
|
||||
if(StringUtils.hasLength(stylePattern)) {
|
||||
int dateStyle = getStylePatternForChar(0);
|
||||
int timeStyle = getStylePatternForChar(1);
|
||||
if(dateStyle != -1 && timeStyle != -1) {
|
||||
return DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
|
||||
}
|
||||
if(dateStyle != -1) {
|
||||
return DateFormat.getDateInstance(dateStyle, locale);
|
||||
}
|
||||
if(timeStyle != -1) {
|
||||
return DateFormat.getTimeInstance(timeStyle, locale);
|
||||
}
|
||||
throw new IllegalStateException("Unsupported style pattern '"+ stylePattern+ "'");
|
||||
|
||||
}
|
||||
return DateFormat.getDateInstance(this.style, locale);
|
||||
}
|
||||
|
||||
private int getStylePatternForChar(int index) {
|
||||
if(stylePattern != null && stylePattern.length() > index) {
|
||||
switch (stylePattern.charAt(index)) {
|
||||
case 'S': return DateFormat.SHORT;
|
||||
case 'M': return DateFormat.MEDIUM;
|
||||
case 'L': return DateFormat.LONG;
|
||||
case 'F': return DateFormat.FULL;
|
||||
case '-': return -1;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unsupported style pattern '"+ stylePattern+ "'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||
import org.springframework.format.FormatterRegistrar;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Configures Date formatting for use with Spring.
|
||||
* <p>
|
||||
* Designed for direct instantiation but also exposes the static
|
||||
* {@link #addDateConverters(ConverterRegistry)} utility method for ad hoc use against any
|
||||
* {@code ConverterRegistry} instance.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 3.2
|
||||
* @see JodaTimeFormatterRegistrar
|
||||
* @see FormatterRegistrar#registerFormatters
|
||||
*/
|
||||
public class DateFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
|
||||
private DateFormatter dateFormatter = new DateFormatter();
|
||||
|
||||
|
||||
public void registerFormatters(FormatterRegistry registry) {
|
||||
addDateConverters(registry);
|
||||
registry.addFormatter(dateFormatter);
|
||||
registry.addFormatterForFieldType(Calendar.class, dateFormatter);
|
||||
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the date formatter to register. If not specified default {@link DateFormatter}
|
||||
* will be used. This method can be used if additional 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
|
||||
*/
|
||||
public static void addDateConverters(ConverterRegistry converterRegistry) {
|
||||
converterRegistry.addConverter(new DateToLongConverter());
|
||||
converterRegistry.addConverter(new DateToCalendarConverter());
|
||||
converterRegistry.addConverter(new CalendarToDateConverter());
|
||||
converterRegistry.addConverter(new CalendarToLongConverter());
|
||||
converterRegistry.addConverter(new LongToDateConverter());
|
||||
converterRegistry.addConverter(new LongToCalendarConverter());
|
||||
}
|
||||
|
||||
|
||||
private static class DateToLongConverter implements Converter<Date, Long> {
|
||||
public Long convert(Date source) {
|
||||
return source.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class DateToCalendarConverter implements Converter<Date, Calendar> {
|
||||
public Calendar convert(Date source) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(source);
|
||||
return calendar;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class CalendarToDateConverter implements Converter<Calendar, Date> {
|
||||
public Date convert(Calendar source) {
|
||||
return source.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class CalendarToLongConverter implements Converter<Calendar, Long> {
|
||||
public Long convert(Calendar source) {
|
||||
return source.getTime().getTime();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class LongToDateConverter implements Converter<Long, Date> {
|
||||
public Date convert(Long source) {
|
||||
return new Date(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class LongToCalendarConverter implements Converter<Long, Calendar> {
|
||||
|
||||
private DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
|
||||
|
||||
public Calendar convert(Long source) {
|
||||
return dateToCalendarConverter.convert(new Date(source));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.EmbeddedValueResolverAware;
|
||||
import org.springframework.format.AnnotationFormatterFactory;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.Parser;
|
||||
import org.springframework.format.Printer;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.datetime.joda.JodaDateTimeFormatAnnotationFormatterFactory;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* Formats fields annotated with the {@link DateTimeFormat} annotation.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see JodaDateTimeFormatAnnotationFormatterFactory
|
||||
* @since 3.2
|
||||
*/
|
||||
public class DateTimeFormatAnnotationFormatterFactory implements
|
||||
AnnotationFormatterFactory<DateTimeFormat>, EmbeddedValueResolverAware {
|
||||
|
||||
|
||||
private static final Set<Class<?>> FIELD_TYPES;
|
||||
static {
|
||||
Set<Class<?>> fieldTypes = new HashSet<Class<?>>();
|
||||
fieldTypes.add(Date.class);
|
||||
fieldTypes.add(Calendar.class);
|
||||
fieldTypes.add(Long.class);
|
||||
FIELD_TYPES = Collections.unmodifiableSet(fieldTypes);
|
||||
}
|
||||
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
|
||||
public void setEmbeddedValueResolver(StringValueResolver resolver) {
|
||||
this.embeddedValueResolver = resolver;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getFieldTypes() {
|
||||
return FIELD_TYPES;
|
||||
}
|
||||
|
||||
public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
return getFormatter(annotation, fieldType);
|
||||
}
|
||||
|
||||
public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
return getFormatter(annotation, fieldType);
|
||||
}
|
||||
|
||||
protected Formatter<Date> getFormatter(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setStylePattern(resolveEmbeddedValue(annotation.style()));
|
||||
formatter.setIso(annotation.iso());
|
||||
formatter.setPattern(resolveEmbeddedValue(annotation.pattern()));
|
||||
return formatter;
|
||||
}
|
||||
|
||||
protected String resolveEmbeddedValue(String value) {
|
||||
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.util.TimeZone;
|
||||
|
||||
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.beans.factory.FactoryBean;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link FactoryBean} that creates a Joda {@link DateTimeFormatter}. Formatters will be
|
||||
* created using the defined {@link #setPattern(String) pattern}, {@link #setIso(ISO) ISO}
|
||||
* or {@link #setStyle(String) style} (considered in that order).
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @see #getDateTimeFormatter()
|
||||
* @see #getDateTimeFormatter(DateTimeFormatter)
|
||||
* @since 3.2
|
||||
*/
|
||||
public class DateTimeFormatterFactory implements FactoryBean<DateTimeFormatter> {
|
||||
|
||||
private ISO iso;
|
||||
|
||||
private String style;
|
||||
|
||||
private String pattern;
|
||||
|
||||
private TimeZone timeZone;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link DateTimeFormatterFactory} instance.
|
||||
*/
|
||||
public DateTimeFormatterFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link DateTimeFormatterFactory} instance.
|
||||
* @param pattern the pattern to use to format date values
|
||||
*/
|
||||
public DateTimeFormatterFactory(String pattern) {
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return DateTimeFormatter.class;
|
||||
}
|
||||
|
||||
public DateTimeFormatter getObject() throws Exception {
|
||||
return getDateTimeFormatter();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new DateTimeFormatter using this factory. If no specific
|
||||
* {@link #setStyle(String) style} {@link #setIso(ISO) ISO} or
|
||||
* {@link #setPattern(String) pattern} have been defined the
|
||||
* {@link DateTimeFormat#mediumDateTime() medium date time format} will be used.
|
||||
* @return a new date time formatter
|
||||
* @see #getObject()
|
||||
* @see #getDateTimeFormatter(DateTimeFormatter)
|
||||
*/
|
||||
public DateTimeFormatter getDateTimeFormatter() {
|
||||
return getDateTimeFormatter(DateTimeFormat.mediumDateTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new DateTimeFormatter using this factory. If no specific
|
||||
* {@link #setStyle(String) style} {@link #setIso(ISO) ISO} or
|
||||
* {@link #setPattern(String) pattern} have been defined the specific
|
||||
* {@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 getDateTimeFormatter(DateTimeFormatter fallbackFormatter) {
|
||||
DateTimeFormatter dateTimeFormatter = createDateTimeFormatter();
|
||||
if(dateTimeFormatter != null && this.timeZone != null) {
|
||||
dateTimeFormatter.withZone(DateTimeZone.forTimeZone(this.timeZone));
|
||||
}
|
||||
return (dateTimeFormatter != null ? dateTimeFormatter : fallbackFormatter);
|
||||
}
|
||||
|
||||
private DateTimeFormatter createDateTimeFormatter() {
|
||||
if (StringUtils.hasLength(pattern)) {
|
||||
return DateTimeFormat.forPattern(pattern);
|
||||
}
|
||||
if (iso != null && iso != ISO.NONE) {
|
||||
if (iso == ISO.DATE) {
|
||||
return ISODateTimeFormat.date();
|
||||
}
|
||||
if (iso == ISO.TIME) {
|
||||
return ISODateTimeFormat.time();
|
||||
}
|
||||
return ISODateTimeFormat.dateTime();
|
||||
}
|
||||
if (StringUtils.hasLength(style)) {
|
||||
return DateTimeFormat.forStyle(style);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the 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 character to use to format date values. The first character 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>
|
||||
* 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 for this date.
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -34,12 +34,10 @@ 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;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* Formats fields annotated with the {@link DateTimeFormat} annotation.
|
||||
* Formats fields annotated with the {@link DateTimeFormat} annotation using Joda time.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
@@ -49,20 +47,33 @@ import org.springframework.util.StringValueResolver;
|
||||
public class JodaDateTimeFormatAnnotationFormatterFactory
|
||||
implements AnnotationFormatterFactory<DateTimeFormat>, EmbeddedValueResolverAware {
|
||||
|
||||
private final Set<Class<?>> fieldTypes;
|
||||
private static final Set<Class<?>> FIELD_TYPES;
|
||||
static {
|
||||
// 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)
|
||||
Set<Class<?>> fieldTypes = new HashSet<Class<?>>(7);
|
||||
fieldTypes.add(ReadableInstant.class);
|
||||
fieldTypes.add(LocalDate.class);
|
||||
fieldTypes.add(LocalTime.class);
|
||||
fieldTypes.add(LocalDateTime.class);
|
||||
fieldTypes.add(Date.class);
|
||||
fieldTypes.add(Calendar.class);
|
||||
fieldTypes.add(Long.class);
|
||||
FIELD_TYPES = Collections.unmodifiableSet(fieldTypes);
|
||||
}
|
||||
|
||||
|
||||
private StringValueResolver embeddedValueResolver;
|
||||
|
||||
|
||||
public JodaDateTimeFormatAnnotationFormatterFactory() {
|
||||
this.fieldTypes = createFieldTypes();
|
||||
}
|
||||
|
||||
public final Set<Class<?>> getFieldTypes() {
|
||||
return this.fieldTypes;
|
||||
return FIELD_TYPES;
|
||||
}
|
||||
|
||||
|
||||
public void setEmbeddedValueResolver(StringValueResolver resolver) {
|
||||
this.embeddedValueResolver = resolver;
|
||||
}
|
||||
@@ -71,79 +82,42 @@ public class JodaDateTimeFormatAnnotationFormatterFactory
|
||||
return (this.embeddedValueResolver != null ? this.embeddedValueResolver.resolveStringValue(value) : value);
|
||||
}
|
||||
|
||||
|
||||
public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
DateTimeFormatter formatter = configureDateTimeFormatterFrom(annotation);
|
||||
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
|
||||
|
||||
if (ReadableInstant.class.isAssignableFrom(fieldType)) {
|
||||
return new ReadableInstantPrinter(formatter);
|
||||
}
|
||||
else if (ReadablePartial.class.isAssignableFrom(fieldType)) {
|
||||
|
||||
if (ReadablePartial.class.isAssignableFrom(fieldType)) {
|
||||
return new ReadablePartialPrinter(formatter);
|
||||
}
|
||||
else if (Calendar.class.isAssignableFrom(fieldType)) {
|
||||
|
||||
if (Calendar.class.isAssignableFrom(fieldType)) {
|
||||
// assumes Calendar->ReadableInstant converter is registered
|
||||
return new ReadableInstantPrinter(formatter);
|
||||
return new ReadableInstantPrinter(formatter);
|
||||
}
|
||||
else {
|
||||
// assumes Date->Long converter is registered
|
||||
return new MillisecondInstantPrinter(formatter);
|
||||
}
|
||||
|
||||
// assumes Date->Long converter is registered
|
||||
return new MillisecondInstantPrinter(formatter);
|
||||
}
|
||||
|
||||
public Parser<DateTime> getParser(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
return new DateTimeParser(configureDateTimeFormatterFrom(annotation));
|
||||
return new DateTimeParser(getFormatter(annotation, fieldType));
|
||||
}
|
||||
|
||||
// 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)
|
||||
/**
|
||||
* Factory method used to create a {@link DateTimeFormatter}.
|
||||
* @param annotation the format annotation for the field
|
||||
* @param fieldType the type of field
|
||||
* @return a {@link DateTimeFormatter} instance
|
||||
* @since 3.2
|
||||
*/
|
||||
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);
|
||||
protected DateTimeFormatter getFormatter(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
DateTimeFormatterFactory factory = new DateTimeFormatterFactory();
|
||||
factory.setStyle(resolveEmbeddedValue(annotation.style()));
|
||||
factory.setIso(annotation.iso());
|
||||
factory.setPattern(resolveEmbeddedValue(annotation.pattern()));
|
||||
return factory.getDateTimeFormatter();
|
||||
}
|
||||
|
||||
private DateTimeFormatter configureDateTimeFormatterFrom(DateTimeFormat annotation) {
|
||||
if (StringUtils.hasLength(annotation.pattern())) {
|
||||
return forPattern(resolveEmbeddedValue(annotation.pattern()));
|
||||
}
|
||||
else if (annotation.iso() != ISO.NONE) {
|
||||
return forIso(annotation.iso());
|
||||
}
|
||||
else {
|
||||
return forStyle(resolveEmbeddedValue(annotation.style()));
|
||||
}
|
||||
}
|
||||
|
||||
private DateTimeFormatter forPattern(String pattern) {
|
||||
return org.joda.time.format.DateTimeFormat.forPattern(pattern);
|
||||
}
|
||||
|
||||
private DateTimeFormatter forStyle(String style) {
|
||||
return org.joda.time.format.DateTimeFormat.forStyle(style);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -29,6 +29,7 @@ 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.
|
||||
@@ -43,6 +44,7 @@ final class JodaTimeConverters {
|
||||
* @param registry the converter registry
|
||||
*/
|
||||
public static void registerConverters(ConverterRegistry registry) {
|
||||
DateFormatterRegistrar.addDateConverters(registry);
|
||||
registry.addConverter(new DateTimeToLocalDateConverter());
|
||||
registry.addConverter(new DateTimeToLocalTimeConverter());
|
||||
registry.addConverter(new DateTimeToLocalDateTimeConverter());
|
||||
@@ -52,14 +54,13 @@ final class JodaTimeConverters {
|
||||
registry.addConverter(new DateTimeToDateConverter());
|
||||
registry.addConverter(new DateTimeToCalendarConverter());
|
||||
registry.addConverter(new DateTimeToLongConverter());
|
||||
registry.addConverter(new DateToLongConverter());
|
||||
registry.addConverter(new CalendarToReadableInstantConverter());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a LocalDate field.
|
||||
* @see DateTimeParser
|
||||
* @see DateTimeParser
|
||||
**/
|
||||
private static class DateTimeToLocalDateConverter implements Converter<DateTime, LocalDate> {
|
||||
public LocalDate convert(DateTime source) {
|
||||
@@ -67,9 +68,9 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a LocalTime field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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) {
|
||||
@@ -77,9 +78,9 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a LocalDateTime field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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) {
|
||||
@@ -87,9 +88,9 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a DateMidnight field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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) {
|
||||
@@ -97,9 +98,9 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to an Instant field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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) {
|
||||
@@ -107,19 +108,19 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a MutableDateTime field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a java.util.Date field.
|
||||
* @see DateTimeParser
|
||||
*/
|
||||
private static class DateTimeToDateConverter implements Converter<DateTime, Date> {
|
||||
public Date convert(DateTime source) {
|
||||
@@ -127,9 +128,9 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a java.util.Calendar field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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) {
|
||||
@@ -137,9 +138,9 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when binding a parsed DateTime to a java.lang.Long field.
|
||||
* @see DateTimeParser
|
||||
/**
|
||||
* 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) {
|
||||
@@ -147,22 +148,11 @@ final class JodaTimeConverters {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when printing a java.util.Date field with a MillisecondInstantPrinter.
|
||||
* @see MillisecondInstantPrinter
|
||||
* @see JodaDateTimeFormatAnnotationFormatterFactory
|
||||
*/
|
||||
private static class DateToLongConverter implements Converter<Date, Long> {
|
||||
public Long convert(Date source) {
|
||||
return source.getTime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Used when printing a java.util.Calendar field with a ReadableInstantPrinter.
|
||||
* @see MillisecondInstantPrinter
|
||||
* @see JodaDateTimeFormatAnnotationFormatterFactory
|
||||
*/
|
||||
*/
|
||||
private static class CalendarToReadableInstantConverter implements Converter<Calendar, ReadableInstant> {
|
||||
public ReadableInstant convert(Calendar source) {
|
||||
return new DateTime(source);
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.format.datetime.joda;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -25,40 +27,54 @@ import org.joda.time.LocalTime;
|
||||
import org.joda.time.ReadableInstant;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.joda.time.format.ISODateTimeFormat;
|
||||
import org.springframework.format.FormatterRegistrar;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.Parser;
|
||||
import org.springframework.format.Printer;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
import org.springframework.format.datetime.DateFormatterRegistrar;
|
||||
|
||||
/**
|
||||
* Configures Joda Time's Formatting system for use with Spring.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
* @author Phillip Webb
|
||||
* @since 3.1
|
||||
* @see #setDateStyle
|
||||
* @see #setTimeStyle
|
||||
* @see #setDateTimeStyle
|
||||
* @see #setUseIsoFormat
|
||||
* @see FormatterRegistrar#registerFormatters
|
||||
* @see DateFormatterRegistrar
|
||||
*/
|
||||
public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
|
||||
|
||||
private String dateStyle;
|
||||
/**
|
||||
* User defined formatters.
|
||||
*/
|
||||
private Map<Type, DateTimeFormatter> formatters = new HashMap<Type, DateTimeFormatter>();
|
||||
|
||||
private String timeStyle;
|
||||
/**
|
||||
* Factories used when specific formatters have not been specified.
|
||||
*/
|
||||
private Map<Type, DateTimeFormatterFactory> factories;
|
||||
|
||||
private String dateTimeStyle;
|
||||
|
||||
private boolean useIsoFormat;
|
||||
public JodaTimeFormatterRegistrar() {
|
||||
this.factories = new HashMap<Type, DateTimeFormatterFactory>();
|
||||
for (Type type : Type.values()) {
|
||||
this.factories.put(type, new DateTimeFormatterFactory());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the default format style of Joda {@link LocalDate} objects.
|
||||
* Default is {@link DateTimeFormat#shortDate()}.
|
||||
*/
|
||||
public void setDateStyle(String dateStyle) {
|
||||
this.dateStyle = dateStyle;
|
||||
factories.get(Type.DATE).setStyle(dateStyle+"-");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +82,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
|
||||
* Default is {@link DateTimeFormat#shortTime()}.
|
||||
*/
|
||||
public void setTimeStyle(String timeStyle) {
|
||||
this.timeStyle = timeStyle;
|
||||
factories.get(Type.TIME).setStyle("-"+timeStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,7 +91,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
|
||||
* Default is {@link DateTimeFormat#shortDateTime()}.
|
||||
*/
|
||||
public void setDateTimeStyle(String dateTimeStyle) {
|
||||
this.dateTimeStyle = dateTimeStyle;
|
||||
factories.get(Type.DATE_TIME).setStyle(dateTimeStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,64 +100,108 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
|
||||
* If set to true, the dateStyle, timeStyle, and dateTimeStyle properties are ignored.
|
||||
*/
|
||||
public void setUseIsoFormat(boolean useIsoFormat) {
|
||||
this.useIsoFormat = useIsoFormat;
|
||||
factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
|
||||
factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
|
||||
factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter that will be used for objects representing date values.
|
||||
* This formatter will be used for the {@link LocalDate} type. When specified
|
||||
* {@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)
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setDateFormatter(DateTimeFormatter formatter) {
|
||||
this.formatters.put(Type.DATE, formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter that will be used for objects representing date values.
|
||||
* This formatter will be used for the {@link LocalTime} type. When specified
|
||||
* {@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)
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setTimeFormatter(DateTimeFormatter formatter) {
|
||||
this.formatters.put(Type.TIME, formatter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the formatter that will be used for objects representing date and time values.
|
||||
* This formatter will be used for {@link LocalDateTime}, {@link ReadableInstant},
|
||||
* {@link Date} and {@link Calendar} types. When specified
|
||||
* {@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)
|
||||
* @since 3.2
|
||||
*/
|
||||
public void setDateTimeFormatter(DateTimeFormatter formatter) {
|
||||
this.formatters.put(Type.DATE_TIME, formatter);
|
||||
}
|
||||
|
||||
public void registerFormatters(FormatterRegistry registry) {
|
||||
JodaTimeConverters.registerConverters(registry);
|
||||
|
||||
DateTimeFormatter jodaDateFormatter = getJodaDateFormatter();
|
||||
registry.addFormatterForFieldType(LocalDate.class, new ReadablePartialPrinter(jodaDateFormatter),
|
||||
new DateTimeParser(jodaDateFormatter));
|
||||
DateTimeFormatter dateFormatter = getFormatter(Type.DATE);
|
||||
DateTimeFormatter timeFormatter = getFormatter(Type.TIME);
|
||||
DateTimeFormatter dateTimeFormatter = getFormatter(Type.DATE_TIME);
|
||||
|
||||
DateTimeFormatter jodaTimeFormatter = getJodaTimeFormatter();
|
||||
registry.addFormatterForFieldType(LocalTime.class, new ReadablePartialPrinter(jodaTimeFormatter),
|
||||
new DateTimeParser(jodaTimeFormatter));
|
||||
addFormatterForFields(registry,
|
||||
new ReadablePartialPrinter(dateFormatter),
|
||||
new DateTimeParser(dateFormatter),
|
||||
LocalDate.class);
|
||||
|
||||
DateTimeFormatter jodaDateTimeFormatter = getJodaDateTimeFormatter();
|
||||
Parser<DateTime> dateTimeParser = new DateTimeParser(jodaDateTimeFormatter);
|
||||
registry.addFormatterForFieldType(LocalDateTime.class, new ReadablePartialPrinter(jodaDateTimeFormatter),
|
||||
dateTimeParser);
|
||||
addFormatterForFields(registry,
|
||||
new ReadablePartialPrinter(timeFormatter),
|
||||
new DateTimeParser(timeFormatter),
|
||||
LocalTime.class);
|
||||
|
||||
Printer<ReadableInstant> readableInstantPrinter = new ReadableInstantPrinter(jodaDateTimeFormatter);
|
||||
registry.addFormatterForFieldType(ReadableInstant.class, readableInstantPrinter, dateTimeParser);
|
||||
addFormatterForFields(registry,
|
||||
new ReadablePartialPrinter(dateTimeFormatter),
|
||||
new DateTimeParser(dateTimeFormatter),
|
||||
LocalDateTime.class);
|
||||
|
||||
registry.addFormatterForFieldAnnotation(new JodaDateTimeFormatAnnotationFormatterFactory());
|
||||
addFormatterForFields(registry,
|
||||
new ReadableInstantPrinter(dateTimeFormatter),
|
||||
new DateTimeParser(dateTimeFormatter),
|
||||
ReadableInstant.class, Date.class, Calendar.class);
|
||||
|
||||
registry.addFormatterForFieldAnnotation(
|
||||
new JodaDateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private DateTimeFormatter getJodaDateFormatter() {
|
||||
if (this.useIsoFormat) {
|
||||
return ISODateTimeFormat.date();
|
||||
private DateTimeFormatter getFormatter(Type type) {
|
||||
DateTimeFormatter formatter = formatters.get(type);
|
||||
if(formatter != null) {
|
||||
return formatter;
|
||||
}
|
||||
if (this.dateStyle != null) {
|
||||
return DateTimeFormat.forStyle(this.dateStyle + "-");
|
||||
} else {
|
||||
return DateTimeFormat.shortDate();
|
||||
DateTimeFormatter fallbackFormatter = getFallbackFormatter(type);
|
||||
return factories.get(type).getDateTimeFormatter(fallbackFormatter );
|
||||
}
|
||||
|
||||
private DateTimeFormatter getFallbackFormatter(Type type) {
|
||||
switch (type) {
|
||||
case DATE: return DateTimeFormat.shortDate();
|
||||
case TIME: return DateTimeFormat.shortTime();
|
||||
default: return DateTimeFormat.shortDateTime();
|
||||
}
|
||||
}
|
||||
|
||||
private DateTimeFormatter getJodaTimeFormatter() {
|
||||
if (this.useIsoFormat) {
|
||||
return ISODateTimeFormat.time();
|
||||
}
|
||||
if (this.timeStyle != null) {
|
||||
return DateTimeFormat.forStyle("-" + this.timeStyle);
|
||||
} else {
|
||||
return DateTimeFormat.shortTime();
|
||||
}
|
||||
}
|
||||
|
||||
private DateTimeFormatter getJodaDateTimeFormatter() {
|
||||
if (this.useIsoFormat) {
|
||||
return ISODateTimeFormat.dateTime();
|
||||
}
|
||||
if (this.dateTimeStyle != null) {
|
||||
return DateTimeFormat.forStyle(this.dateTimeStyle);
|
||||
} else {
|
||||
return DateTimeFormat.shortDateTime();
|
||||
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}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -16,18 +16,9 @@
|
||||
|
||||
package org.springframework.format.support;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.format.AnnotationFormatterFactory;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.Parser;
|
||||
import org.springframework.format.Printer;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.datetime.DateFormatterRegistrar;
|
||||
import org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar;
|
||||
import org.springframework.format.number.NumberFormatAnnotationFormatterFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -96,39 +87,9 @@ public class DefaultFormattingConversionService extends FormattingConversionServ
|
||||
formatterRegistry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
|
||||
if (jodaTimePresent) {
|
||||
new JodaTimeFormatterRegistrar().registerFormatters(formatterRegistry);
|
||||
} else {
|
||||
formatterRegistry.addFormatterForFieldAnnotation(new NoJodaDateTimeFormatAnnotationFormatterFactory());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dummy AnnotationFormatterFactory that simply fails if @DateTimeFormat is being used
|
||||
* without the JodaTime library being present.
|
||||
*/
|
||||
private static final class NoJodaDateTimeFormatAnnotationFormatterFactory
|
||||
implements AnnotationFormatterFactory<DateTimeFormat> {
|
||||
|
||||
private final Set<Class<?>> fieldTypes;
|
||||
|
||||
public NoJodaDateTimeFormatAnnotationFormatterFactory() {
|
||||
Set<Class<?>> rawFieldTypes = new HashSet<Class<?>>(4);
|
||||
rawFieldTypes.add(Date.class);
|
||||
rawFieldTypes.add(Calendar.class);
|
||||
rawFieldTypes.add(Long.class);
|
||||
this.fieldTypes = Collections.unmodifiableSet(rawFieldTypes);
|
||||
}
|
||||
|
||||
public Set<Class<?>> getFieldTypes() {
|
||||
return this.fieldTypes;
|
||||
}
|
||||
|
||||
public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
throw new IllegalStateException("JodaTime library not available - @DateTimeFormat not supported");
|
||||
}
|
||||
|
||||
public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
|
||||
throw new IllegalStateException("JodaTime library not available - @DateTimeFormat not supported");
|
||||
else {
|
||||
new DateFormatterRegistrar().registerFormatters(formatterRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
@@ -16,39 +16,217 @@
|
||||
|
||||
package org.springframework.format.datetime;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.springframework.format.datetime.DateFormatter;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
|
||||
/**
|
||||
* Tests for {@link DateFormatter}.
|
||||
*
|
||||
* @author Keith Donald
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class DateFormatterTests {
|
||||
|
||||
private DateFormatter formatter = new DateFormatter("yyyy-MM-dd");
|
||||
|
||||
@Rule
|
||||
public ExpectedException thown = ExpectedException.none();
|
||||
|
||||
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
|
||||
|
||||
@Test
|
||||
public void formatValue() {
|
||||
Calendar cal = Calendar.getInstance(Locale.US);
|
||||
cal.clear();
|
||||
cal.set(Calendar.YEAR, 2009);
|
||||
cal.set(Calendar.MONTH, Calendar.JUNE);
|
||||
cal.set(Calendar.DAY_OF_MONTH, 1);
|
||||
assertEquals("2009-06-01", formatter.print(cal.getTime(), Locale.US));
|
||||
public void shouldPrintAndParseDefault() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1);
|
||||
assertThat(formatter.print(date, Locale.US), is("Jun 1, 2009"));
|
||||
assertThat(formatter.parse("Jun 1, 2009", Locale.US), is(date));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void parseValue() throws ParseException {
|
||||
public void shouldPrintAndParseFromPattern() throws ParseException {
|
||||
DateFormatter formatter = new DateFormatter("yyyy-MM-dd");
|
||||
formatter.setTimeZone(UTC);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1);
|
||||
assertThat(formatter.print(date, Locale.US), is("2009-06-01"));
|
||||
assertThat(formatter.parse("2009-06-01", Locale.US), is(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseShort() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setStyle(DateFormat.SHORT);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1);
|
||||
assertThat(formatter.print(date, Locale.US), is("6/1/09"));
|
||||
assertThat(formatter.parse("6/1/09", Locale.US), is(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseMedium() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setStyle(DateFormat.MEDIUM);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1);
|
||||
assertThat(formatter.print(date, Locale.US), is("Jun 1, 2009"));
|
||||
assertThat(formatter.parse("Jun 1, 2009", Locale.US), is(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseLong() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setStyle(DateFormat.LONG);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1);
|
||||
assertThat(formatter.print(date, Locale.US), is("June 1, 2009"));
|
||||
assertThat(formatter.parse("June 1, 2009", Locale.US), is(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseFull() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setStyle(DateFormat.FULL);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1);
|
||||
assertThat(formatter.print(date, Locale.US), is("Monday, June 1, 2009"));
|
||||
assertThat(formatter.parse("Monday, June 1, 2009", Locale.US), is(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseISODate() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setIso(ISO.DATE);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1, 14, 23, 5, 3);
|
||||
assertThat(formatter.print(date, Locale.US), is("2009-06-01"));
|
||||
assertThat(formatter.parse("2009-6-01", Locale.US),
|
||||
is(getDate(2009, Calendar.JUNE, 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseISOTime() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setIso(ISO.TIME);
|
||||
Date date = getDate(2009, Calendar.JANUARY, 1, 14, 23, 5, 3);
|
||||
assertThat(formatter.print(date, Locale.US), is("14:23:05.003+0000"));
|
||||
assertThat(formatter.parse("14:23:05.003+0000", Locale.US),
|
||||
is(getDate(1970, Calendar.JANUARY, 1, 14, 23, 5, 3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseIsoTimeWithZeros() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setIso(ISO.TIME);
|
||||
Date date = formatter.parse("12:00:00.000-00005", Locale.US);
|
||||
System.out.println(date);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldPrintAndParseISODateTime() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setIso(ISO.DATE_TIME);
|
||||
Date date = getDate(2009, Calendar.JUNE, 1, 14, 23, 5, 3);
|
||||
assertThat(formatter.print(date, Locale.US), is("2009-06-01T14:23:05.003+0000"));
|
||||
assertThat(formatter.parse("2009-06-01T14:23:05.003+0000", Locale.US), is(date));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSupportJodaStylePatterns() throws Exception {
|
||||
String[] chars = { "S", "M", "L", "F", "-" };
|
||||
for (String d : chars) {
|
||||
for (String t : chars) {
|
||||
String style = d + t;
|
||||
if (!style.equals("--")) {
|
||||
Date date = getDate(2009, Calendar.JUNE, 10, 14, 23, 0, 0);
|
||||
if (t.equals("-")) {
|
||||
date = getDate(2009, Calendar.JUNE, 10);
|
||||
} else if (d.equals("-")) {
|
||||
date = getDate(1970, Calendar.JANUARY, 1, 14, 23, 0, 0);
|
||||
}
|
||||
testJodaStylePatterns(style, Locale.US, date);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testJodaStylePatterns(String style, Locale locale, Date date)
|
||||
throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setStylePattern(style);
|
||||
DateTimeFormatter jodaFormatter = DateTimeFormat.forStyle(style).withLocale(
|
||||
locale).withZone(DateTimeZone.UTC);
|
||||
String jodaPrinted = jodaFormatter.print(date.getTime());
|
||||
assertThat("Unable to print style pattern " + style,
|
||||
formatter.print(date, locale), is(equalTo(jodaPrinted)));
|
||||
assertThat("Unable to parse style pattern " + style,
|
||||
formatter.parse(jodaPrinted, locale), is(equalTo(date)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldThrowOnUnsupportStylePattern() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setStylePattern("OO");
|
||||
thown.expect(IllegalStateException.class);
|
||||
thown.expectMessage("Unsupported style pattern 'OO'");
|
||||
formatter.parse("2009", Locale.US);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldUseCorrectOrder() throws Exception {
|
||||
DateFormatter formatter = new DateFormatter();
|
||||
formatter.setTimeZone(UTC);
|
||||
formatter.setStyle(DateFormat.SHORT);
|
||||
formatter.setStylePattern("L-");
|
||||
formatter.setIso(ISO.DATE_TIME);
|
||||
formatter.setPattern("yyyy");
|
||||
Date date = getDate(2009, Calendar.JUNE, 1, 14, 23, 5, 3);
|
||||
|
||||
assertThat("uses pattern",formatter.print(date, Locale.US), is("2009"));
|
||||
|
||||
formatter.setPattern("");
|
||||
assertThat("uses ISO", formatter.print(date, Locale.US), is("2009-06-01T14:23:05.003+0000"));
|
||||
|
||||
formatter.setIso(ISO.NONE);
|
||||
assertThat("uses style pattern", formatter.print(date, Locale.US), is("June 1, 2009"));
|
||||
|
||||
formatter.setStylePattern("");
|
||||
assertThat("uses style", formatter.print(date, Locale.US), is("6/1/09"));
|
||||
}
|
||||
|
||||
private Date getDate(int year, int month, int dayOfMonth) {
|
||||
return getDate(year, month, dayOfMonth, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private Date getDate(int year, int month, int dayOfMonth, int hour, int minute,
|
||||
int second, int millisecond) {
|
||||
Calendar cal = Calendar.getInstance(Locale.US);
|
||||
cal.setTimeZone(UTC);
|
||||
cal.clear();
|
||||
cal.set(Calendar.YEAR, 2009);
|
||||
cal.set(Calendar.MONTH, Calendar.JUNE);
|
||||
cal.set(Calendar.DAY_OF_MONTH, 1);
|
||||
assertEquals(cal.getTime(), formatter.parse("2009-06-01", Locale.US));
|
||||
cal.set(Calendar.YEAR, year);
|
||||
cal.set(Calendar.MONTH, month);
|
||||
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
|
||||
cal.set(Calendar.HOUR, hour);
|
||||
cal.set(Calendar.MINUTE, minute);
|
||||
cal.set(Calendar.SECOND, second);
|
||||
cal.set(Calendar.MILLISECOND, millisecond);
|
||||
return cal.getTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
import org.springframework.format.datetime.DateFormatterRegistrar;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
import org.springframework.validation.DataBinder;
|
||||
|
||||
/**
|
||||
* @author Phillip Webb
|
||||
* @author Keith Donald
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class DateFormattingTests {
|
||||
|
||||
private FormattingConversionService conversionService = new FormattingConversionService();
|
||||
|
||||
private DataBinder binder;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
DefaultConversionService.addDefaultConverters(conversionService);
|
||||
|
||||
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
|
||||
registrar.registerFormatters(conversionService);
|
||||
|
||||
SimpleDateBean bean = new SimpleDateBean();
|
||||
bean.getChildren().add(new SimpleDateBean());
|
||||
binder = new DataBinder(bean);
|
||||
binder.setConversionService(conversionService);
|
||||
|
||||
LocaleContextHolder.setLocale(Locale.US);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
LocaleContextHolder.setLocale(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDate() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("date", "10/31/09 12:00 PM");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("date"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateArray() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("date", new String[] {"10/31/09 12:00 PM"});
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("dateAnnotated", "10/31/09");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09", binder.getBindingResult().getFieldValue("dateAnnotated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateAnnotatedWithError() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("dateAnnotated", "Oct X31, 2009");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(1, binder.getBindingResult().getFieldErrorCount("dateAnnotated"));
|
||||
assertEquals("Oct X31, 2009", binder.getBindingResult().getFieldValue("dateAnnotated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testBindDateAnnotatedWithFallbackError() {
|
||||
// TODO This currently passes because of the Date(String) constructor fallback is used
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("dateAnnotated", "Oct 031, 2009");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(1, binder.getBindingResult().getFieldErrorCount("dateAnnotated"));
|
||||
assertEquals("Oct 031, 2009", binder.getBindingResult().getFieldValue("dateAnnotated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindCalendar() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("calendar", "10/31/09 12:00 PM");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("calendar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindCalendarAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("calendarAnnotated", "10/31/09");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09", binder.getBindingResult().getFieldValue("calendarAnnotated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLong() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("millis", "1256961600");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("1256961600", binder.getBindingResult().getFieldValue("millis"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLongAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("millisAnnotated", "10/31/09");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09", binder.getBindingResult().getFieldValue("millisAnnotated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindISODate() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("isoDate", "2009-10-31");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("2009-10-31", binder.getBindingResult().getFieldValue("isoDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindISOTime() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("isoTime", "12:00:00.000-0500");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("17:00:00.000+0000", binder.getBindingResult().getFieldValue("isoTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindISODateTime() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("isoDateTime", "2009-10-31T12:00:00.000-0800");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("2009-10-31T20:00:00.000+0000", binder.getBindingResult().getFieldValue("isoDateTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindNestedDateAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("children[0].dateAnnotated", "10/31/09");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09", binder.getBindingResult().getFieldValue("children[0].dateAnnotated"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class SimpleDateBean {
|
||||
|
||||
@DateTimeFormat
|
||||
private Date date;
|
||||
|
||||
@DateTimeFormat(style="S-")
|
||||
private Date dateAnnotated;
|
||||
|
||||
@DateTimeFormat
|
||||
private Calendar calendar;
|
||||
|
||||
@DateTimeFormat(style="S-")
|
||||
private Calendar calendarAnnotated;
|
||||
|
||||
private Long millis;
|
||||
|
||||
private Long millisAnnotated;
|
||||
|
||||
@DateTimeFormat(pattern="M/d/yy h:mm a")
|
||||
private Date dateAnnotatedPattern;
|
||||
|
||||
@DateTimeFormat(iso=ISO.DATE)
|
||||
private Date isoDate;
|
||||
|
||||
@DateTimeFormat(iso=ISO.TIME)
|
||||
private Date isoTime;
|
||||
|
||||
@DateTimeFormat(iso=ISO.DATE_TIME)
|
||||
private Date isoDateTime;
|
||||
|
||||
private final List<SimpleDateBean> children = new ArrayList<SimpleDateBean>();
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Date getDateAnnotated() {
|
||||
return dateAnnotated;
|
||||
}
|
||||
|
||||
public void setDateAnnotated(Date dateAnnotated) {
|
||||
this.dateAnnotated = dateAnnotated;
|
||||
}
|
||||
|
||||
public Calendar getCalendar() {
|
||||
return calendar;
|
||||
}
|
||||
|
||||
public void setCalendar(Calendar calendar) {
|
||||
this.calendar = calendar;
|
||||
}
|
||||
|
||||
public Calendar getCalendarAnnotated() {
|
||||
return calendarAnnotated;
|
||||
}
|
||||
|
||||
public void setCalendarAnnotated(Calendar calendarAnnotated) {
|
||||
this.calendarAnnotated = calendarAnnotated;
|
||||
}
|
||||
|
||||
public Long getMillis() {
|
||||
return millis;
|
||||
}
|
||||
|
||||
public void setMillis(Long millis) {
|
||||
this.millis = millis;
|
||||
}
|
||||
|
||||
@DateTimeFormat(style="S-")
|
||||
public Long getMillisAnnotated() {
|
||||
return millisAnnotated;
|
||||
}
|
||||
|
||||
public void setMillisAnnotated(@DateTimeFormat(style="S-") Long millisAnnotated) {
|
||||
this.millisAnnotated = millisAnnotated;
|
||||
}
|
||||
|
||||
public Date getIsoDate() {
|
||||
return isoDate;
|
||||
}
|
||||
|
||||
public void setIsoDate(Date isoDate) {
|
||||
this.isoDate = isoDate;
|
||||
}
|
||||
|
||||
public Date getIsoTime() {
|
||||
return isoTime;
|
||||
}
|
||||
|
||||
public void setIsoTime(Date isoTime) {
|
||||
this.isoTime = isoTime;
|
||||
}
|
||||
|
||||
public Date getIsoDateTime() {
|
||||
return isoDateTime;
|
||||
}
|
||||
|
||||
public void setIsoDateTime(Date isoDateTime) {
|
||||
this.isoDateTime = isoDateTime;
|
||||
}
|
||||
|
||||
public List<SimpleDateBean> getChildren() {
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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 static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.hamcrest.Matchers.sameInstance;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
import org.junit.Test;
|
||||
import org.springframework.format.annotation.DateTimeFormat.ISO;
|
||||
|
||||
/**
|
||||
* Tests for {@link DateTimeFormatterFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
public class DateTimeFormatterFactoryTests {
|
||||
|
||||
private DateTimeFormatterFactory factory = new DateTimeFormatterFactory();
|
||||
|
||||
private DateTime dateTime = new DateTime(2009, 10, 21, 12, 10, 00, 00);
|
||||
|
||||
@Test
|
||||
public void shouldDefaultToMediumFormat() throws Exception {
|
||||
assertThat(factory.getObject(), is(equalTo(DateTimeFormat.mediumDateTime())));
|
||||
assertThat(factory.getDateTimeFormatter(), is(equalTo(DateTimeFormat.mediumDateTime())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateFromPattern() throws Exception {
|
||||
factory = new DateTimeFormatterFactory("yyyyMMddHHmmss");
|
||||
DateTimeFormatter formatter = factory.getObject();
|
||||
assertThat(formatter.print(dateTime), is("20091021121000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeSingleton() throws Exception {
|
||||
assertThat(factory.isSingleton(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void shouldCreateDateTimeFormatter() throws Exception {
|
||||
assertThat(factory.getObjectType(), is(equalTo((Class)DateTimeFormatter.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetDateTimeFormatterNullFallback() throws Exception {
|
||||
DateTimeFormatter formatter = factory.getDateTimeFormatter(null);
|
||||
assertThat(formatter, is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetDateTimeFormatterFallback() throws Exception {
|
||||
DateTimeFormatter fallback = DateTimeFormat.forStyle("LL");
|
||||
DateTimeFormatter formatter = factory.getDateTimeFormatter(fallback);
|
||||
assertThat(formatter, is(sameInstance(fallback)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetDateTimeFormatter() throws Exception {
|
||||
factory.setStyle("SS");
|
||||
assertThat(applyLocale(factory.getDateTimeFormatter()).print(dateTime), is("10/21/09 12:10 PM"));
|
||||
|
||||
factory.setIso(ISO.DATE);
|
||||
assertThat(applyLocale(factory.getDateTimeFormatter()).print(dateTime), is("2009-10-21"));
|
||||
|
||||
factory.setPattern("yyyyMMddHHmmss");
|
||||
assertThat(factory.getDateTimeFormatter().print(dateTime), is("20091021121000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldGetWithTimeZone() throws Exception {
|
||||
factory.setPattern("yyyyMMddHHmmss Z");
|
||||
factory.setTimeZone(TimeZone.getTimeZone("-0700"));
|
||||
assertThat(factory.getDateTimeFormatter().print(dateTime), is("20091021121000 -0700"));
|
||||
}
|
||||
|
||||
private DateTimeFormatter applyLocale(DateTimeFormatter dateTimeFormatter) {
|
||||
return dateTimeFormatter.withLocale(Locale.US);
|
||||
}
|
||||
}
|
||||
@@ -49,15 +49,20 @@ import static org.junit.Assert.*;
|
||||
*/
|
||||
public class JodaTimeFormattingTests {
|
||||
|
||||
private FormattingConversionService conversionService = new FormattingConversionService();
|
||||
private FormattingConversionService conversionService;
|
||||
|
||||
private DataBinder binder;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
setUp(registrar);
|
||||
}
|
||||
|
||||
private void setUp(JodaTimeFormatterRegistrar registrar) {
|
||||
conversionService = new FormattingConversionService();
|
||||
DefaultConversionService.addDefaultConverters(conversionService);
|
||||
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.registerFormatters(conversionService);
|
||||
|
||||
JodaTimeBean bean = new JodaTimeBean();
|
||||
@@ -84,7 +89,7 @@ public class JodaTimeFormattingTests {
|
||||
System.out.println(org.joda.time.format.DateTimeFormat.patternForStyle("LL", LocaleContextHolder.getLocale()));
|
||||
System.out.println(org.joda.time.format.DateTimeFormat.patternForStyle("FF", LocaleContextHolder.getLocale()));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBindLocalDate() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -94,6 +99,30 @@ public class JodaTimeFormattingTests {
|
||||
assertEquals("10/31/09", binder.getBindingResult().getFieldValue("localDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLocalDateWithSpecificStyle() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setDateStyle("L");
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("localDate", "October 31, 2009");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("October 31, 2009", binder.getBindingResult().getFieldValue("localDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLocalDateWithSpecifcFormatter() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setDateFormatter(org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd"));
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("localDate", "20091031");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("20091031", binder.getBindingResult().getFieldValue("localDate"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLocalDateArray() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -158,6 +187,30 @@ public class JodaTimeFormattingTests {
|
||||
assertEquals("12:00 PM", binder.getBindingResult().getFieldValue("localTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLocalTimeWithSpecificStyle() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setTimeStyle("M");
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("localTime", "12:00:00 PM");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("12:00:00 PM", binder.getBindingResult().getFieldValue("localTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLocalTimeWithSpecificFormatter() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setTimeFormatter(org.joda.time.format.DateTimeFormat.forPattern("HHmmss"));
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("localTime", "130000");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("130000", binder.getBindingResult().getFieldValue("localTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindLocalTimeAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -205,6 +258,42 @@ public class JodaTimeFormattingTests {
|
||||
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("dateTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateTimeWithSpecificStyle() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setDateTimeStyle("MM");
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("localDateTime", "Oct 31, 2009 12:00:00 PM");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("Oct 31, 2009 12:00:00 PM", binder.getBindingResult().getFieldValue("localDateTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateTimeISO() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setUseIsoFormat(true);
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("dateTime", "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("dateTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateTimeWithSpecificFormatter() throws Exception {
|
||||
JodaTimeFormatterRegistrar registrar = new JodaTimeFormatterRegistrar();
|
||||
registrar.setDateTimeFormatter(org.joda.time.format.DateTimeFormat.forPattern("yyyyMMddHHmmss"));
|
||||
setUp(registrar);
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
propertyValues.add("dateTime", "20091031130000");
|
||||
binder.bind(propertyValues);
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("20091031130000", binder.getBindingResult().getFieldValue("dateTime"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindDateTimeAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -339,7 +428,7 @@ public class JodaTimeFormattingTests {
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("instant"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBindInstantAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -357,7 +446,7 @@ public class JodaTimeFormattingTests {
|
||||
assertEquals(0, binder.getBindingResult().getErrorCount());
|
||||
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("mutableDateTime"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBindMutableDateTimeAnnotated() {
|
||||
MutablePropertyValues propertyValues = new MutablePropertyValues();
|
||||
@@ -483,7 +572,7 @@ public class JodaTimeFormattingTests {
|
||||
public void setLocalDateTimeAnnotated(LocalDateTime localDateTimeAnnotated) {
|
||||
this.localDateTimeAnnotated = localDateTimeAnnotated;
|
||||
}
|
||||
|
||||
|
||||
public LocalDateTime getLocalDateTimeAnnotatedLong() {
|
||||
return localDateTimeAnnotatedLong;
|
||||
}
|
||||
@@ -596,7 +685,7 @@ public class JodaTimeFormattingTests {
|
||||
public void setIsoDateTime(DateTime isoDateTime) {
|
||||
this.isoDateTime = isoDateTime;
|
||||
}
|
||||
|
||||
|
||||
public Instant getInstant() {
|
||||
return instant;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user