Skip to content

Commit af41dd1

Browse files
committed
Efficient ISO_LOCAL_* variants for printing LocalDate/LocalTime/LocalDateTime
Issue: SPR-14958 (cherry picked from commit 1ae17c2)
1 parent 17f7f1f commit af41dd1

File tree

3 files changed

+77
-31
lines changed

3 files changed

+77
-31
lines changed

spring-context/src/main/java/org/springframework/format/datetime/standard/DateTimeFormatterRegistrar.java

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
2929
import java.time.ZonedDateTime;
3030
import java.time.format.DateTimeFormatter;
3131
import java.time.format.FormatStyle;
32-
import java.util.HashMap;
32+
import java.util.EnumMap;
3333
import java.util.Map;
3434

3535
import org.springframework.format.FormatterRegistrar;
@@ -58,18 +58,19 @@ private enum Type {DATE, TIME, DATE_TIME}
5858

5959

6060
/**
61-
* User defined formatters.
61+
* User-defined formatters.
6262
*/
63-
private final Map<Type, DateTimeFormatter> formatters = new HashMap<Type, DateTimeFormatter>();
63+
private final Map<Type, DateTimeFormatter> formatters =
64+
new EnumMap<Type, DateTimeFormatter>(Type.class);
6465

6566
/**
6667
* Factories used when specific formatters have not been specified.
6768
*/
68-
private final Map<Type, DateTimeFormatterFactory> factories;
69+
private final Map<Type, DateTimeFormatterFactory> factories =
70+
new EnumMap<Type, DateTimeFormatterFactory>(Type.class);
6971

7072

7173
public DateTimeFormatterRegistrar() {
72-
this.factories = new HashMap<Type, DateTimeFormatterFactory>();
7374
for (Type type : Type.values()) {
7475
this.factories.put(type, new DateTimeFormatterFactory());
7576
}
@@ -157,33 +158,38 @@ public void setDateTimeFormatter(DateTimeFormatter formatter) {
157158
public void registerFormatters(FormatterRegistry registry) {
158159
DateTimeConverters.registerConverters(registry);
159160

160-
DateTimeFormatter dateFormatter = getFormatter(Type.DATE);
161-
DateTimeFormatter timeFormatter = getFormatter(Type.TIME);
162-
DateTimeFormatter dateTimeFormatter = getFormatter(Type.DATE_TIME);
161+
DateTimeFormatter df = getFormatter(Type.DATE);
162+
DateTimeFormatter tf = getFormatter(Type.TIME);
163+
DateTimeFormatter dtf = getFormatter(Type.DATE_TIME);
164+
165+
// Efficient ISO_LOCAL_* variants for printing since they are twice as fast...
163166

164167
registry.addFormatterForFieldType(LocalDate.class,
165-
new TemporalAccessorPrinter(dateFormatter),
166-
new TemporalAccessorParser(LocalDate.class, dateFormatter));
168+
new TemporalAccessorPrinter(
169+
df == DateTimeFormatter.ISO_DATE ? DateTimeFormatter.ISO_LOCAL_DATE : df),
170+
new TemporalAccessorParser(LocalDate.class, df));
167171

168172
registry.addFormatterForFieldType(LocalTime.class,
169-
new TemporalAccessorPrinter(timeFormatter),
170-
new TemporalAccessorParser(LocalTime.class, timeFormatter));
173+
new TemporalAccessorPrinter(
174+
tf == DateTimeFormatter.ISO_TIME ? DateTimeFormatter.ISO_LOCAL_TIME : tf),
175+
new TemporalAccessorParser(LocalTime.class, tf));
171176

172177
registry.addFormatterForFieldType(LocalDateTime.class,
173-
new TemporalAccessorPrinter(dateTimeFormatter),
174-
new TemporalAccessorParser(LocalDateTime.class, dateTimeFormatter));
178+
new TemporalAccessorPrinter(
179+
dtf == DateTimeFormatter.ISO_DATE_TIME ? DateTimeFormatter.ISO_LOCAL_DATE_TIME : dtf),
180+
new TemporalAccessorParser(LocalDateTime.class, dtf));
175181

176182
registry.addFormatterForFieldType(ZonedDateTime.class,
177-
new TemporalAccessorPrinter(dateTimeFormatter),
178-
new TemporalAccessorParser(ZonedDateTime.class, dateTimeFormatter));
183+
new TemporalAccessorPrinter(dtf),
184+
new TemporalAccessorParser(ZonedDateTime.class, dtf));
179185

180186
registry.addFormatterForFieldType(OffsetDateTime.class,
181-
new TemporalAccessorPrinter(dateTimeFormatter),
182-
new TemporalAccessorParser(OffsetDateTime.class, dateTimeFormatter));
187+
new TemporalAccessorPrinter(dtf),
188+
new TemporalAccessorParser(OffsetDateTime.class, dtf));
183189

184190
registry.addFormatterForFieldType(OffsetTime.class,
185-
new TemporalAccessorPrinter(timeFormatter),
186-
new TemporalAccessorParser(OffsetTime.class, timeFormatter));
191+
new TemporalAccessorPrinter(tf),
192+
new TemporalAccessorParser(OffsetTime.class, tf));
187193

188194
registry.addFormatterForFieldType(Instant.class, new InstantFormatter());
189195
registry.addFormatterForFieldType(Period.class, new PeriodFormatter());

spring-context/src/main/java/org/springframework/format/datetime/standard/Jsr310DateTimeFormatAnnotationFormatterFactory.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -68,6 +68,24 @@ public final Set<Class<?>> getFieldTypes() {
6868
@Override
6969
public Printer<?> getPrinter(DateTimeFormat annotation, Class<?> fieldType) {
7070
DateTimeFormatter formatter = getFormatter(annotation, fieldType);
71+
72+
// Efficient ISO_LOCAL_* variants for printing since they are twice as fast...
73+
if (formatter == DateTimeFormatter.ISO_DATE) {
74+
if (isLocal(fieldType)) {
75+
formatter = DateTimeFormatter.ISO_LOCAL_DATE;
76+
}
77+
}
78+
else if (formatter == DateTimeFormatter.ISO_TIME) {
79+
if (isLocal(fieldType)) {
80+
formatter = DateTimeFormatter.ISO_LOCAL_TIME;
81+
}
82+
}
83+
else if (formatter == DateTimeFormatter.ISO_DATE_TIME) {
84+
if (isLocal(fieldType)) {
85+
formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
86+
}
87+
}
88+
7189
return new TemporalAccessorPrinter(formatter);
7290
}
7391

@@ -81,7 +99,7 @@ public Parser<?> getParser(DateTimeFormat annotation, Class<?> fieldType) {
8199
/**
82100
* Factory method used to create a {@link DateTimeFormatter}.
83101
* @param annotation the format annotation for the field
84-
* @param fieldType the type of field
102+
* @param fieldType the declared type of the field
85103
* @return a {@link DateTimeFormatter} instance
86104
*/
87105
protected DateTimeFormatter getFormatter(DateTimeFormat annotation, Class<?> fieldType) {
@@ -92,4 +110,8 @@ protected DateTimeFormatter getFormatter(DateTimeFormat annotation, Class<?> fie
92110
return factory.createDateTimeFormatter();
93111
}
94112

113+
private boolean isLocal(Class<?> fieldType) {
114+
return fieldType.getSimpleName().startsWith("Local");
115+
}
116+
95117
}

spring-context/src/test/java/org/springframework/format/datetime/standard/DateTimeFormattingTests.java

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,15 @@ public void testBindISODate() {
311311

312312
@Test
313313
public void testBindISOTime() {
314+
MutablePropertyValues propertyValues = new MutablePropertyValues();
315+
propertyValues.add("isoTime", "12:00:00");
316+
binder.bind(propertyValues);
317+
assertEquals(0, binder.getBindingResult().getErrorCount());
318+
assertEquals("12:00:00", binder.getBindingResult().getFieldValue("isoTime"));
319+
}
320+
321+
@Test
322+
public void testBindISOTimeWithZone() {
314323
MutablePropertyValues propertyValues = new MutablePropertyValues();
315324
propertyValues.add("isoTime", "12:00:00.000-05:00");
316325
binder.bind(propertyValues);
@@ -320,6 +329,15 @@ public void testBindISOTime() {
320329

321330
@Test
322331
public void testBindISODateTime() {
332+
MutablePropertyValues propertyValues = new MutablePropertyValues();
333+
propertyValues.add("isoDateTime", "2009-10-31T12:00:00");
334+
binder.bind(propertyValues);
335+
assertEquals(0, binder.getBindingResult().getErrorCount());
336+
assertEquals("2009-10-31T12:00:00", binder.getBindingResult().getFieldValue("isoDateTime"));
337+
}
338+
339+
@Test
340+
public void testBindISODateTimeWithZone() {
323341
MutablePropertyValues propertyValues = new MutablePropertyValues();
324342
propertyValues.add("isoDateTime", "2009-10-31T12:00:00.000Z");
325343
binder.bind(propertyValues);
@@ -386,29 +404,29 @@ public static class DateTimeBean {
386404

387405
private LocalDate localDate;
388406

389-
@DateTimeFormat(style="M-")
407+
@DateTimeFormat(style = "M-")
390408
private LocalDate localDateAnnotated;
391409

392410
private LocalTime localTime;
393411

394-
@DateTimeFormat(style="-M")
412+
@DateTimeFormat(style = "-M")
395413
private LocalTime localTimeAnnotated;
396414

397415
private LocalDateTime localDateTime;
398416

399-
@DateTimeFormat(style="MM")
417+
@DateTimeFormat(style = "MM")
400418
private LocalDateTime localDateTimeAnnotated;
401419

402-
@DateTimeFormat(pattern="M/d/yy h:mm a")
420+
@DateTimeFormat(pattern = "M/d/yy h:mm a")
403421
private LocalDateTime dateTimeAnnotatedPattern;
404422

405-
@DateTimeFormat(iso=ISO.DATE)
423+
@DateTimeFormat(iso = ISO.DATE)
406424
private LocalDate isoDate;
407425

408-
@DateTimeFormat(iso=ISO.TIME)
426+
@DateTimeFormat(iso = ISO.TIME)
409427
private LocalTime isoTime;
410428

411-
@DateTimeFormat(iso=ISO.DATE_TIME)
429+
@DateTimeFormat(iso = ISO.DATE_TIME)
412430
private LocalDateTime isoDateTime;
413431

414432
private Instant instant;
@@ -421,7 +439,7 @@ public static class DateTimeBean {
421439

422440
private MonthDay monthDay;
423441

424-
private final List<DateTimeBean> children = new ArrayList<DateTimeBean>();
442+
private final List<DateTimeBean> children = new ArrayList<>();
425443

426444
public LocalDate getLocalDate() {
427445
return localDate;

0 commit comments

Comments
 (0)