From 6660227d222a4a2c771f5601aa34bdcdd386f14e Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Mon, 8 Oct 2012 17:59:13 -0700 Subject: [PATCH] Support for custom global Joda DateTimeFormatters Added dateFormatter, timeFormatter and dateTimeFormatter properties to JodaTimeFormatterRegistrar allowing for custom global formatting. DateTimeFormatterFactory can be used when configuring with XML. Issue: SPR-7121 --- .../datetime/DateFormatterRegistrar.java | 1 + .../joda/DateTimeFormatterFactory.java | 167 ++++++++++++++++++ ...eTimeFormatAnnotationFormatterFactory.java | 107 +++++------ .../joda/JodaTimeFormatterRegistrar.java | 159 +++++++++++------ .../joda/DateTimeFormatterFactoryTests.java | 104 +++++++++++ .../joda/JodaTimeFormattingTests.java | 103 ++++++++++- 6 files changed, 518 insertions(+), 123 deletions(-) create mode 100644 spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java create mode 100644 spring-context/src/test/java/org/springframework/format/datetime/joda/DateTimeFormatterFactoryTests.java diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java index 21c267c111..66584ea56c 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatterRegistrar.java @@ -47,6 +47,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar { public void registerFormatters(FormatterRegistry registry) { addDateConverters(registry); registry.addFormatter(dateFormatter); + registry.addFormatterForFieldType(Calendar.class, dateFormatter); registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory()); } diff --git a/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java b/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java new file mode 100644 index 0000000000..89cd13a8bd --- /dev/null +++ b/spring-context/src/main/java/org/springframework/format/datetime/joda/DateTimeFormatterFactory.java @@ -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 { + + 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 + *