提交 5e00113c 编写于 作者: J Juergen Hoeller

Added extensive default converters for JSR-310 value types

Also adding several further Joda-Time converters for consistency with JSR-310 converters.

Issue: SPR-11259
上级 48909886
......@@ -36,8 +36,13 @@ import org.springframework.format.datetime.DateFormatterRegistrar;
* Installs lower-level type converters required to integrate
* Joda-Time support into Spring's field formatting system.
*
* <p>Note: {@link JodaTimeFormatterRegistrar} installs these converters
* and relies on several of them for its formatters. Some additional
* converters are just being registered for custom conversion scenarios.
*
* @author Keith Donald
* @author Phillip Webb
* @author Juergen Hoeller
* @since 3.0
*/
final class JodaTimeConverters {
......@@ -48,6 +53,7 @@ final class JodaTimeConverters {
*/
public static void registerConverters(ConverterRegistry registry) {
DateFormatterRegistrar.addDateConverters(registry);
registry.addConverter(new DateTimeToLocalDateConverter());
registry.addConverter(new DateTimeToLocalTimeConverter());
registry.addConverter(new DateTimeToLocalDateTimeConverter());
......@@ -59,6 +65,11 @@ final class JodaTimeConverters {
registry.addConverter(new DateTimeToLongConverter());
registry.addConverter(new DateToReadableInstantConverter());
registry.addConverter(new CalendarToReadableInstantConverter());
registry.addConverter(new LongToReadableInstantConverter());
registry.addConverter(new LocalDateTimeToLocalDateConverter());
registry.addConverter(new LocalDateTimeToLocalTimeConverter());
registry.addConverter(new LocalDateToDateMidnightConverter());
registry.addConverter(new DateMidnightToLocalDateConverter());
}
......@@ -144,7 +155,7 @@ final class JodaTimeConverters {
/**
* Used when printing a java.util.Date field with a ReadableInstantPrinter.
* Used when printing a {@code java.util.Date} field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
......@@ -158,7 +169,7 @@ final class JodaTimeConverters {
/**
* Used when printing a java.util.Calendar field with a ReadableInstantPrinter.
* Used when printing a {@code java.util.Calendar} field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
......@@ -170,4 +181,54 @@ final class JodaTimeConverters {
}
}
/**
* Used when printing a Long field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class LongToReadableInstantConverter implements Converter<Long, ReadableInstant> {
@Override
public ReadableInstant convert(Long source) {
return new DateTime(source.longValue());
}
}
private static class LocalDateTimeToLocalDateConverter implements Converter<LocalDateTime, LocalDate> {
@Override
public LocalDate convert(LocalDateTime source) {
return source.toLocalDate();
}
}
private static class LocalDateTimeToLocalTimeConverter implements Converter<LocalDateTime, LocalTime> {
@Override
public LocalTime convert(LocalDateTime source) {
return source.toLocalTime();
}
}
private static class LocalDateToDateMidnightConverter implements Converter<LocalDate, DateMidnight> {
@Override
public DateMidnight convert(LocalDate source) {
return source.toDateMidnight();
}
}
private static class DateMidnightToLocalDateConverter implements Converter<DateMidnight, LocalDate> {
@Override
public LocalDate convert(DateMidnight source) {
return source.toLocalDate();
}
}
}
/*
* 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.
* 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.standard;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.chrono.ChronoZonedDateTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
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
* JSR-310 support into Spring's field formatting system.
*
* <p>Note: {@link DateTimeFormatterRegistrar} installs these converters but
* does not rely on them for its formatters. They are just being registered
* for custom conversion scenarios between different JSR-310 value types
* and also between {@link java.util.Calendar} and JSR-310 value types.
*
* @author Juergen Hoeller
* @since 4.0.1
*/
final class DateTimeConverters {
/**
* Install the converters into the converter registry.
* @param registry the converter registry
*/
public static void registerConverters(ConverterRegistry registry) {
DateFormatterRegistrar.addDateConverters(registry);
registry.addConverter(new LocalDateTimeToLocalDateConverter());
registry.addConverter(new LocalDateTimeToLocalTimeConverter());
registry.addConverter(new ZonedDateTimeToLocalDateConverter());
registry.addConverter(new ZonedDateTimeToLocalTimeConverter());
registry.addConverter(new ZonedDateTimeToLocalDateTimeConverter());
registry.addConverter(new ZonedDateTimeToOffsetDateTimeConverter());
registry.addConverter(new ZonedDateTimeToInstantConverter());
registry.addConverter(new OffsetDateTimeToLocalDateConverter());
registry.addConverter(new OffsetDateTimeToLocalTimeConverter());
registry.addConverter(new OffsetDateTimeToLocalDateTimeConverter());
registry.addConverter(new OffsetDateTimeToZonedDateTimeConverter());
registry.addConverter(new OffsetDateTimeToInstantConverter());
registry.addConverter(new CalendarToZonedDateTimeConverter());
registry.addConverter(new CalendarToOffsetDateTimeConverter());
registry.addConverter(new CalendarToLocalDateConverter());
registry.addConverter(new CalendarToLocalTimeConverter());
registry.addConverter(new CalendarToLocalDateTimeConverter());
registry.addConverter(new CalendarToInstantConverter());
registry.addConverter(new LongToInstantConverter());
registry.addConverter(new InstantToLongConverter());
}
private static ZonedDateTime calendarToZonedDateTime(Calendar source) {
if (source instanceof GregorianCalendar) {
return ((GregorianCalendar) source).toZonedDateTime();
}
else {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(source.getTimeInMillis()),
source.getTimeZone().toZoneId());
}
}
private static class LocalDateTimeToLocalDateConverter implements Converter<LocalDateTime, LocalDate> {
@Override
public LocalDate convert(LocalDateTime source) {
return source.toLocalDate();
}
}
private static class LocalDateTimeToLocalTimeConverter implements Converter<LocalDateTime, LocalTime> {
@Override
public LocalTime convert(LocalDateTime source) {
return source.toLocalTime();
}
}
private static class ZonedDateTimeToLocalDateConverter implements Converter<ZonedDateTime, LocalDate> {
@Override
public LocalDate convert(ZonedDateTime source) {
return source.toLocalDate();
}
}
private static class ZonedDateTimeToLocalTimeConverter implements Converter<ZonedDateTime, LocalTime> {
@Override
public LocalTime convert(ZonedDateTime source) {
return source.toLocalTime();
}
}
private static class ZonedDateTimeToLocalDateTimeConverter implements Converter<ZonedDateTime, LocalDateTime> {
@Override
public LocalDateTime convert(ZonedDateTime source) {
return source.toLocalDateTime();
}
}
private static class ZonedDateTimeToOffsetDateTimeConverter implements Converter<ZonedDateTime, OffsetDateTime> {
@Override
public OffsetDateTime convert(ZonedDateTime source) {
return source.toOffsetDateTime();
}
}
private static class ZonedDateTimeToInstantConverter implements Converter<ZonedDateTime, Instant> {
@Override
public Instant convert(ZonedDateTime source) {
// Explicit cast to interface necessary in order to call Java 8 default method from -source 1.6
return ((ChronoZonedDateTime) source).toInstant();
}
}
private static class OffsetDateTimeToLocalDateConverter implements Converter<OffsetDateTime, LocalDate> {
@Override
public LocalDate convert(OffsetDateTime source) {
return source.toLocalDate();
}
}
private static class OffsetDateTimeToLocalTimeConverter implements Converter<OffsetDateTime, LocalTime> {
@Override
public LocalTime convert(OffsetDateTime source) {
return source.toLocalTime();
}
}
private static class OffsetDateTimeToLocalDateTimeConverter implements Converter<OffsetDateTime, LocalDateTime> {
@Override
public LocalDateTime convert(OffsetDateTime source) {
return source.toLocalDateTime();
}
}
private static class OffsetDateTimeToZonedDateTimeConverter implements Converter<OffsetDateTime, ZonedDateTime> {
@Override
public ZonedDateTime convert(OffsetDateTime source) {
return source.toZonedDateTime();
}
}
private static class OffsetDateTimeToInstantConverter implements Converter<OffsetDateTime, Instant> {
@Override
public Instant convert(OffsetDateTime source) {
return source.toInstant();
}
}
private static class CalendarToZonedDateTimeConverter implements Converter<Calendar, ZonedDateTime> {
@Override
public ZonedDateTime convert(Calendar source) {
return calendarToZonedDateTime(source);
}
}
private static class CalendarToOffsetDateTimeConverter implements Converter<Calendar, OffsetDateTime> {
@Override
public OffsetDateTime convert(Calendar source) {
return calendarToZonedDateTime(source).toOffsetDateTime();
}
}
private static class CalendarToLocalDateConverter implements Converter<Calendar, LocalDate> {
@Override
public LocalDate convert(Calendar source) {
return calendarToZonedDateTime(source).toLocalDate();
}
}
private static class CalendarToLocalTimeConverter implements Converter<Calendar, LocalTime> {
@Override
public LocalTime convert(Calendar source) {
return calendarToZonedDateTime(source).toLocalTime();
}
}
private static class CalendarToLocalDateTimeConverter implements Converter<Calendar, LocalDateTime> {
@Override
public LocalDateTime convert(Calendar source) {
return calendarToZonedDateTime(source).toLocalDateTime();
}
}
private static class CalendarToInstantConverter implements Converter<Calendar, Instant> {
@Override
public Instant convert(Calendar source) {
// Explicit cast to interface necessary in order to call Java 8 default method from -source 1.6
return ((ChronoZonedDateTime) calendarToZonedDateTime(source)).toInstant();
}
}
private static class LongToInstantConverter implements Converter<Long, Instant> {
@Override
public Instant convert(Long source) {
return Instant.ofEpochMilli(source);
}
}
private static class InstantToLongConverter implements Converter<Instant, Long> {
@Override
public Long convert(Instant source) {
return source.toEpochMilli();
}
}
}
......@@ -108,7 +108,7 @@ public class DateTimeFormatterRegistrar implements FormatterRegistrar {
/**
* Set the formatter that will be used for objects representing date values.
* <p>This formatter will be used for the {@link org.joda.time.LocalDate} type.
* <p>This formatter will be used for the {@link LocalDate} type.
* When specified, the {@link #setDateStyle dateStyle} and
* {@link #setUseIsoFormat useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
......@@ -121,8 +121,8 @@ public class DateTimeFormatterRegistrar implements FormatterRegistrar {
/**
* Set the formatter that will be used for objects representing time values.
* <p>This formatter will be used for the {@link org.joda.time.LocalTime} type.
* When specified, the {@link #setTimeStyle timeStyle} and
* <p>This formatter will be used for the {@link LocalTime} and {@link OffsetTime}
* types. When specified, the {@link #setTimeStyle timeStyle} and
* {@link #setUseIsoFormat useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setDateFormatter
......@@ -134,9 +134,9 @@ public class DateTimeFormatterRegistrar implements FormatterRegistrar {
/**
* Set the formatter that will be used for objects representing date and time values.
* <p>This formatter will be used for {@link org.joda.time.LocalDateTime}, {@link org.joda.time.ReadableInstant},
* {@link java.util.Date} and {@link java.util.Calendar} types.
* When specified, the {@link #setDateTimeStyle dateTimeStyle} and
* <p>This formatter will be used for {@link LocalDateTime}, {@link ZonedDateTime}
* and {@link OffsetDateTime} types. When specified, the
* {@link #setDateTimeStyle dateTimeStyle} and
* {@link #setUseIsoFormat useIsoFormat} properties will be ignored.
* @param formatter the formatter to use
* @see #setDateFormatter
......@@ -149,6 +149,8 @@ public class DateTimeFormatterRegistrar implements FormatterRegistrar {
@Override
public void registerFormatters(FormatterRegistry registry) {
DateTimeConverters.registerConverters(registry);
DateTimeFormatter dateFormatter = getFormatter(Type.DATE);
DateTimeFormatter timeFormatter = getFormatter(Type.TIME);
DateTimeFormatter dateTimeFormatter = getFormatter(Type.DATE_TIME);
......
......@@ -16,7 +16,7 @@
package org.springframework.format.datetime.standard;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
......@@ -25,8 +25,10 @@ import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import org.junit.After;
import org.junit.Before;
......@@ -34,7 +36,6 @@ import org.junit.Test;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
......@@ -171,6 +172,15 @@ public class DateTimeFormattingTests {
assertEquals("Oct -31, 2009", binder.getBindingResult().getFieldValue("localDateAnnotated"));
}
@Test
public void testBindLocalDateFromJavaUtilCalendar() throws Exception {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDate", new GregorianCalendar(2009, 9, 31, 0, 0));
binder.bind(propertyValues);
assertEquals(0, binder.getBindingResult().getErrorCount());
assertEquals("10/31/09", binder.getBindingResult().getFieldValue("localDate"));
}
@Test
public void testBindLocalTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
......@@ -213,6 +223,15 @@ public class DateTimeFormattingTests {
assertEquals("12:00:00 PM", binder.getBindingResult().getFieldValue("localTimeAnnotated"));
}
@Test
public void testBindLocalTimeFromJavaUtilCalendar() throws Exception {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localTime", new GregorianCalendar(1970, 0, 0, 12, 0));
binder.bind(propertyValues);
assertEquals(0, binder.getBindingResult().getErrorCount());
assertEquals("12:00 PM", binder.getBindingResult().getFieldValue("localTime"));
}
@Test
public void testBindLocalDateTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
......@@ -231,6 +250,15 @@ public class DateTimeFormattingTests {
assertEquals("Oct 31, 2009 12:00:00 PM", binder.getBindingResult().getFieldValue("localDateTimeAnnotated"));
}
@Test
public void testBindLocalDateTimeFromJavaUtilCalendar() throws Exception {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateTime", new GregorianCalendar(2009, 9, 31, 12, 0));
binder.bind(propertyValues);
assertEquals(0, binder.getBindingResult().getErrorCount());
assertEquals("10/31/09 12:00 PM", binder.getBindingResult().getFieldValue("localDateTime"));
}
@Test
public void testBindDateTimeWithSpecificStyle() throws Exception {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
......@@ -241,9 +269,6 @@ public class DateTimeFormattingTests {
binder.bind(propertyValues);
assertEquals(0, binder.getBindingResult().getErrorCount());
assertEquals("Oct 31, 2009 12:00:00 PM", binder.getBindingResult().getFieldValue("localDateTime"));
Method testMethod = LocalVariableTableParameterNameDiscoverer.class.getMethod("getParameterNames", Method.class);
System.out.println(testMethod.getParameters()[0].getName());
System.out.println(new LocalVariableTableParameterNameDiscoverer().getParameterNames(testMethod)[0]);
}
@Test
......@@ -291,6 +316,17 @@ public class DateTimeFormattingTests {
assertTrue(binder.getBindingResult().getFieldValue("instant").toString().startsWith("2009-10-31T12:00"));
}
@Test
public void testBindInstantFromJavaUtilDate() throws Exception {
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.US);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("instant", df.parse("10/31/09 12:00 PM"));
binder.bind(propertyValues);
assertEquals(0, binder.getBindingResult().getErrorCount());
assertTrue(binder.getBindingResult().getFieldValue("instant").toString().startsWith("2009-10-31T12:00"));
}
public static class DateTimeBean {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册