Support multiple parsing patterns in @DateTimeFormat

Prior to this commit, @DateTimeFormat only supported a single format
for parsing date time values via the style, iso, and pattern attributes.

This commit introduces a new fallbackPatterns attribute that can be
used to configure multiple fallback patterns for parsing date time
values. This allows applications to accept multiple input formats for
date time values.

For example, if you wish to use the ISO date format for parsing and
printing but allow for lenient parsing of user input for various
additional date formats, you could annotate a field or method parameter
with configuration similar to the following.

    @DateTimeFormat(
        iso = ISO.DATE,
        fallbackPatterns = { "M/d/yy", "dd.MM.yyyy" }
    )

Closes gh-20292
This commit is contained in:
Sam Brannen
2021-03-02 20:35:05 +01:00
parent 5593e95e89
commit b2bcb0f93a
11 changed files with 708 additions and 227 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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,6 +16,7 @@
package org.springframework.format.datetime;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@@ -25,16 +26,23 @@ import java.util.Locale;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.validation.FieldError;
import static org.assertj.core.api.Assertions.assertThat;
@@ -42,10 +50,11 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Phillip Webb
* @author Keith Donald
* @author Juergen Hoeller
* @author Sam Brannen
*/
public class DateFormattingTests {
private FormattingConversionService conversionService;
private final FormattingConversionService conversionService = new FormattingConversionService();
private DataBinder binder;
@@ -57,7 +66,6 @@ public class DateFormattingTests {
}
private void setup(DateFormatterRegistrar registrar) {
conversionService = new FormattingConversionService();
DefaultConversionService.addDefaultConverters(conversionService);
registrar.registerFormatters(conversionService);
@@ -87,34 +95,34 @@ public class DateFormattingTests {
@Test
void testBindLongAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("millisAnnotated", "10/31/09");
propertyValues.add("styleMillis", "10/31/09");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("millisAnnotated")).isEqualTo("10/31/09");
assertThat(binder.getBindingResult().getFieldValue("styleMillis")).isEqualTo("10/31/09");
}
@Test
void testBindCalendarAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("calendarAnnotated", "10/31/09");
propertyValues.add("styleCalendar", "10/31/09");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("calendarAnnotated")).isEqualTo("10/31/09");
assertThat(binder.getBindingResult().getFieldValue("styleCalendar")).isEqualTo("10/31/09");
}
@Test
void testBindDateAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotated", "10/31/09");
propertyValues.add("styleDate", "10/31/09");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("dateAnnotated")).isEqualTo("10/31/09");
assertThat(binder.getBindingResult().getFieldValue("styleDate")).isEqualTo("10/31/09");
}
@Test
void testBindDateArray() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotated", new String[]{"10/31/09 12:00 PM"});
propertyValues.add("styleDate", new String[]{"10/31/09 12:00 PM"});
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
}
@@ -122,10 +130,10 @@ public class DateFormattingTests {
@Test
void testBindDateAnnotatedWithError() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotated", "Oct X31, 2009");
propertyValues.add("styleDate", "Oct X31, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getFieldErrorCount("dateAnnotated")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("dateAnnotated")).isEqualTo("Oct X31, 2009");
assertThat(binder.getBindingResult().getFieldErrorCount("styleDate")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("styleDate")).isEqualTo("Oct X31, 2009");
}
@Test
@@ -133,19 +141,19 @@ public class DateFormattingTests {
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");
propertyValues.add("styleDate", "Oct 031, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getFieldErrorCount("dateAnnotated")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("dateAnnotated")).isEqualTo("Oct 031, 2009");
assertThat(binder.getBindingResult().getFieldErrorCount("styleDate")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("styleDate")).isEqualTo("Oct 031, 2009");
}
@Test
void testBindDateAnnotatedPattern() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotatedPattern", "10/31/09 1:05");
propertyValues.add("patternDate", "10/31/09 1:05");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("dateAnnotatedPattern")).isEqualTo("10/31/09 1:05");
assertThat(binder.getBindingResult().getFieldValue("patternDate")).isEqualTo("10/31/09 1:05");
}
@Test
@@ -156,16 +164,17 @@ public class DateFormattingTests {
registrar.setFormatter(dateFormatter);
setup(registrar);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotatedPattern", "10/31/09 1:05");
propertyValues.add("patternDate", "10/31/09 1:05");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("dateAnnotatedPattern")).isEqualTo("10/31/09 1:05");
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue("patternDate")).isEqualTo("10/31/09 1:05");
}
@Test
void testBindDateTimeOverflow() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateAnnotatedPattern", "02/29/09 12:00 PM");
propertyValues.add("patternDate", "02/29/09 12:00 PM");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(1);
}
@@ -200,10 +209,10 @@ public class DateFormattingTests {
@Test
void testBindNestedDateAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("children[0].dateAnnotated", "10/31/09");
propertyValues.add("children[0].styleDate", "10/31/09");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("children[0].dateAnnotated")).isEqualTo("10/31/09");
assertThat(binder.getBindingResult().getFieldValue("children[0].styleDate")).isEqualTo("10/31/09");
}
@Test
@@ -247,35 +256,127 @@ public class DateFormattingTests {
}
@Nested
class FallbackPatternTests {
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02", "2021.03.02", "20210302", "3/2/21"})
void styleCalendar(String propertyValue) {
String propertyName = "styleCalendarWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("3/2/21");
}
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02", "2021.03.02", "20210302", "3/2/21"})
void styleDate(String propertyValue) {
String propertyName = "styleDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("3/2/21");
}
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02", "2021.03.02", "20210302", "3/2/21"})
void patternDate(String propertyValue) {
String propertyName = "patternDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("2021-03-02");
}
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02", "2021.03.02", "20210302", "3/2/21"})
void isoDate(String propertyValue) {
String propertyName = "isoDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("2021-03-02");
}
@Test
void patternDateWithUnsupportedPattern() {
String propertyValue = "210302";
String propertyName = "patternDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(1);
FieldError fieldError = bindingResult.getFieldError(propertyName);
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'patternDateWithFallbackPatterns'")
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
.hasMessageContaining("for value '210302'")
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
.hasMessageContaining("Parse attempt failed for value [210302]")
.hasCauseInstanceOf(ParseException.class).getCause()
// Unable to parse date time value "210302" using configuration from
// @org.springframework.format.annotation.DateTimeFormat(
// pattern=yyyy-MM-dd, style=SS, iso=NONE, fallbackPatterns=[M/d/yy, yyyyMMdd, yyyy.MM.dd])
.hasMessageContainingAll(
"Unable to parse date time value \"210302\" using configuration from",
"@org.springframework.format.annotation.DateTimeFormat",
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd");
}
}
@SuppressWarnings("unused")
private static class SimpleDateBean {
private Long millis;
private Long millisAnnotated;
private Long styleMillis;
@DateTimeFormat(style="S-")
private Calendar calendarAnnotated;
@DateTimeFormat(style = "S-")
private Calendar styleCalendar;
@DateTimeFormat(style="S-")
private Date dateAnnotated;
@DateTimeFormat(style = "S-", fallbackPatterns = { "yyyy-MM-dd", "yyyyMMdd", "yyyy.MM.dd" })
private Calendar styleCalendarWithFallbackPatterns;
@DateTimeFormat(pattern="M/d/yy h:mm")
private Date dateAnnotatedPattern;
@DateTimeFormat(style = "S-")
private Date styleDate;
@DateTimeFormat(iso=ISO.DATE)
@DateTimeFormat(style = "S-", fallbackPatterns = { "yyyy-MM-dd", "yyyyMMdd", "yyyy.MM.dd" })
private Date styleDateWithFallbackPatterns;
@DateTimeFormat(pattern = "M/d/yy h:mm")
private Date patternDate;
@DateTimeFormat(pattern = "yyyy-MM-dd", fallbackPatterns = { "M/d/yy", "yyyyMMdd", "yyyy.MM.dd" })
private Date patternDateWithFallbackPatterns;
@DateTimeFormat(iso = ISO.DATE)
private Date isoDate;
@DateTimeFormat(iso=ISO.TIME)
@DateTimeFormat(iso = ISO.DATE, fallbackPatterns = { "M/d/yy", "yyyyMMdd", "yyyy.MM.dd" })
private Date isoDateWithFallbackPatterns;
@DateTimeFormat(iso = ISO.TIME)
private Date isoTime;
@DateTimeFormat(iso=ISO.DATE_TIME)
@DateTimeFormat(iso = ISO.DATE_TIME)
private Date isoDateTime;
private final List<SimpleDateBean> children = new ArrayList<>();
public Long getMillis() {
return millis;
return this.millis;
}
public void setMillis(Long millis) {
@@ -283,48 +384,80 @@ public class DateFormattingTests {
}
@DateTimeFormat(style="S-")
public Long getMillisAnnotated() {
return millisAnnotated;
public Long getStyleMillis() {
return this.styleMillis;
}
public void setMillisAnnotated(@DateTimeFormat(style="S-") Long millisAnnotated) {
this.millisAnnotated = millisAnnotated;
public void setStyleMillis(@DateTimeFormat(style="S-") Long styleMillis) {
this.styleMillis = styleMillis;
}
public Calendar getCalendarAnnotated() {
return calendarAnnotated;
public Calendar getStyleCalendar() {
return this.styleCalendar;
}
public void setCalendarAnnotated(Calendar calendarAnnotated) {
this.calendarAnnotated = calendarAnnotated;
public void setStyleCalendar(Calendar styleCalendar) {
this.styleCalendar = styleCalendar;
}
public Date getDateAnnotated() {
return dateAnnotated;
public Calendar getStyleCalendarWithFallbackPatterns() {
return this.styleCalendarWithFallbackPatterns;
}
public void setDateAnnotated(Date dateAnnotated) {
this.dateAnnotated = dateAnnotated;
public void setStyleCalendarWithFallbackPatterns(Calendar styleCalendarWithFallbackPatterns) {
this.styleCalendarWithFallbackPatterns = styleCalendarWithFallbackPatterns;
}
public Date getDateAnnotatedPattern() {
return dateAnnotatedPattern;
public Date getStyleDate() {
return this.styleDate;
}
public void setDateAnnotatedPattern(Date dateAnnotatedPattern) {
this.dateAnnotatedPattern = dateAnnotatedPattern;
public void setStyleDate(Date styleDate) {
this.styleDate = styleDate;
}
public Date getStyleDateWithFallbackPatterns() {
return this.styleDateWithFallbackPatterns;
}
public void setStyleDateWithFallbackPatterns(Date styleDateWithFallbackPatterns) {
this.styleDateWithFallbackPatterns = styleDateWithFallbackPatterns;
}
public Date getPatternDate() {
return this.patternDate;
}
public void setPatternDate(Date patternDate) {
this.patternDate = patternDate;
}
public Date getPatternDateWithFallbackPatterns() {
return this.patternDateWithFallbackPatterns;
}
public void setPatternDateWithFallbackPatterns(Date patternDateWithFallbackPatterns) {
this.patternDateWithFallbackPatterns = patternDateWithFallbackPatterns;
}
public Date getIsoDate() {
return isoDate;
return this.isoDate;
}
public void setIsoDate(Date isoDate) {
this.isoDate = isoDate;
}
public Date getIsoDateWithFallbackPatterns() {
return this.isoDateWithFallbackPatterns;
}
public void setIsoDateWithFallbackPatterns(Date isoDateWithFallbackPatterns) {
this.isoDateWithFallbackPatterns = isoDateWithFallbackPatterns;
}
public Date getIsoTime() {
return isoTime;
return this.isoTime;
}
public void setIsoTime(Date isoTime) {
@@ -332,7 +465,7 @@ public class DateFormattingTests {
}
public Date getIsoDateTime() {
return isoDateTime;
return this.isoDateTime;
}
public void setIsoDateTime(Date isoDateTime) {
@@ -340,7 +473,7 @@ public class DateFormattingTests {
}
public List<SimpleDateBean> getChildren() {
return children;
return this.children;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@@ -28,6 +28,7 @@ import java.time.Year;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.Date;
@@ -38,15 +39,22 @@ import java.util.TimeZone;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.TypeMismatchException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.core.convert.ConversionFailedException;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.validation.BindingResult;
import org.springframework.validation.DataBinder;
import org.springframework.validation.FieldError;
import static org.assertj.core.api.Assertions.assertThat;
@@ -54,22 +62,22 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Keith Donald
* @author Juergen Hoeller
* @author Phillip Webb
* @author Sam Brannen
*/
public class DateTimeFormattingTests {
class DateTimeFormattingTests {
private FormattingConversionService conversionService;
private final FormattingConversionService conversionService = new FormattingConversionService();
private DataBinder binder;
@BeforeEach
public void setup() {
void setup() {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
setup(registrar);
}
private void setup(DateTimeFormatterRegistrar registrar) {
conversionService = new FormattingConversionService();
DefaultConversionService.addDefaultConverters(conversionService);
registrar.registerFormatters(conversionService);
@@ -85,14 +93,14 @@ public class DateTimeFormattingTests {
}
@AfterEach
public void cleanup() {
void cleanup() {
LocaleContextHolder.setLocale(null);
DateTimeContextHolder.setDateTimeContext(null);
}
@Test
public void testBindLocalDate() {
void testBindLocalDate() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDate", "10/31/09");
binder.bind(propertyValues);
@@ -101,7 +109,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalDateWithSpecificStyle() {
void testBindLocalDateWithSpecificStyle() {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setDateStyle(FormatStyle.LONG);
setup(registrar);
@@ -113,7 +121,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalDateWithSpecificFormatter() {
void testBindLocalDateWithSpecificFormatter() {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setDateFormatter(DateTimeFormatter.ofPattern("yyyyMMdd"));
setup(registrar);
@@ -125,7 +133,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalDateArray() {
void testBindLocalDateArray() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDate", new String[] {"10/31/09"});
binder.bind(propertyValues);
@@ -133,54 +141,54 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalDateAnnotated() {
void testBindLocalDateAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateAnnotated", "Oct 31, 2009");
propertyValues.add("styleLocalDate", "Oct 31, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("localDateAnnotated")).isEqualTo("Oct 31, 2009");
assertThat(binder.getBindingResult().getFieldValue("styleLocalDate")).isEqualTo("Oct 31, 2009");
}
@Test
public void testBindLocalDateAnnotatedWithError() {
void testBindLocalDateAnnotatedWithError() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateAnnotated", "Oct -31, 2009");
propertyValues.add("styleLocalDate", "Oct -31, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getFieldErrorCount("localDateAnnotated")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("localDateAnnotated")).isEqualTo("Oct -31, 2009");
assertThat(binder.getBindingResult().getFieldErrorCount("styleLocalDate")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("styleLocalDate")).isEqualTo("Oct -31, 2009");
}
@Test
public void testBindNestedLocalDateAnnotated() {
void testBindNestedLocalDateAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("children[0].localDateAnnotated", "Oct 31, 2009");
propertyValues.add("children[0].styleLocalDate", "Oct 31, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("children[0].localDateAnnotated")).isEqualTo("Oct 31, 2009");
assertThat(binder.getBindingResult().getFieldValue("children[0].styleLocalDate")).isEqualTo("Oct 31, 2009");
}
@Test
public void testBindLocalDateAnnotatedWithDirectFieldAccess() {
void testBindLocalDateAnnotatedWithDirectFieldAccess() {
binder.initDirectFieldAccess();
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateAnnotated", "Oct 31, 2009");
propertyValues.add("styleLocalDate", "Oct 31, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("localDateAnnotated")).isEqualTo("Oct 31, 2009");
assertThat(binder.getBindingResult().getFieldValue("styleLocalDate")).isEqualTo("Oct 31, 2009");
}
@Test
public void testBindLocalDateAnnotatedWithDirectFieldAccessAndError() {
void testBindLocalDateAnnotatedWithDirectFieldAccessAndError() {
binder.initDirectFieldAccess();
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateAnnotated", "Oct -31, 2009");
propertyValues.add("styleLocalDate", "Oct -31, 2009");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getFieldErrorCount("localDateAnnotated")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("localDateAnnotated")).isEqualTo("Oct -31, 2009");
assertThat(binder.getBindingResult().getFieldErrorCount("styleLocalDate")).isEqualTo(1);
assertThat(binder.getBindingResult().getFieldValue("styleLocalDate")).isEqualTo("Oct -31, 2009");
}
@Test
public void testBindLocalDateFromJavaUtilCalendar() {
void testBindLocalDateFromJavaUtilCalendar() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDate", new GregorianCalendar(2009, 9, 31, 0, 0));
binder.bind(propertyValues);
@@ -189,7 +197,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalTime() {
void testBindLocalTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localTime", "12:00 PM");
binder.bind(propertyValues);
@@ -198,7 +206,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalTimeWithSpecificStyle() {
void testBindLocalTimeWithSpecificStyle() {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setTimeStyle(FormatStyle.MEDIUM);
setup(registrar);
@@ -210,7 +218,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalTimeWithSpecificFormatter() {
void testBindLocalTimeWithSpecificFormatter() {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setTimeFormatter(DateTimeFormatter.ofPattern("HHmmss"));
setup(registrar);
@@ -222,16 +230,16 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalTimeAnnotated() {
void testBindLocalTimeAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localTimeAnnotated", "12:00:00 PM");
propertyValues.add("styleLocalTime", "12:00:00 PM");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("localTimeAnnotated")).isEqualTo("12:00:00 PM");
assertThat(binder.getBindingResult().getFieldValue("styleLocalTime")).isEqualTo("12:00:00 PM");
}
@Test
public void testBindLocalTimeFromJavaUtilCalendar() {
void testBindLocalTimeFromJavaUtilCalendar() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localTime", new GregorianCalendar(1970, 0, 0, 12, 0));
binder.bind(propertyValues);
@@ -240,7 +248,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalDateTime() {
void testBindLocalDateTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateTime", LocalDateTime.of(2009, 10, 31, 12, 0));
binder.bind(propertyValues);
@@ -251,18 +259,18 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindLocalDateTimeAnnotated() {
void testBindLocalDateTimeAnnotated() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateTimeAnnotated", LocalDateTime.of(2009, 10, 31, 12, 0));
propertyValues.add("styleLocalDateTime", LocalDateTime.of(2009, 10, 31, 12, 0));
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
String value = binder.getBindingResult().getFieldValue("localDateTimeAnnotated").toString();
String value = binder.getBindingResult().getFieldValue("styleLocalDateTime").toString();
assertThat(value.startsWith("Oct 31, 2009")).isTrue();
assertThat(value.endsWith("12:00:00 PM")).isTrue();
}
@Test
public void testBindLocalDateTimeFromJavaUtilCalendar() {
void testBindLocalDateTimeFromJavaUtilCalendar() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("localDateTime", new GregorianCalendar(2009, 9, 31, 12, 0));
binder.bind(propertyValues);
@@ -273,7 +281,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindDateTimeWithSpecificStyle() {
void testBindDateTimeWithSpecificStyle() {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setDateTimeStyle(FormatStyle.MEDIUM);
setup(registrar);
@@ -287,69 +295,69 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindDateTimeAnnotatedPattern() {
void testBindPatternLocalDateTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateTimeAnnotatedPattern", "10/31/09 12:00 PM");
propertyValues.add("patternLocalDateTime", "10/31/09 12:00 PM");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("dateTimeAnnotatedPattern")).isEqualTo("10/31/09 12:00 PM");
assertThat(binder.getBindingResult().getFieldValue("patternLocalDateTime")).isEqualTo("10/31/09 12:00 PM");
}
@Test
public void testBindDateTimeOverflow() {
void testBindDateTimeOverflow() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("dateTimeAnnotatedPattern", "02/29/09 12:00 PM");
propertyValues.add("patternLocalDateTime", "02/29/09 12:00 PM");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(1);
}
@Test
public void testBindISODate() {
void testBindISODate() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("isoDate", "2009-10-31");
propertyValues.add("isoLocalDate", "2009-10-31");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("isoDate")).isEqualTo("2009-10-31");
assertThat(binder.getBindingResult().getFieldValue("isoLocalDate")).isEqualTo("2009-10-31");
}
@Test
public void testBindISOTime() {
void testBindISOTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("isoTime", "12:00:00");
propertyValues.add("isoLocalTime", "12:00:00");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("isoTime")).isEqualTo("12:00:00");
assertThat(binder.getBindingResult().getFieldValue("isoLocalTime")).isEqualTo("12:00:00");
}
@Test
public void testBindISOTimeWithZone() {
void testBindISOTimeWithZone() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("isoTime", "12:00:00.000-05:00");
propertyValues.add("isoLocalTime", "12:00:00.000-05:00");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("isoTime")).isEqualTo("12:00:00");
assertThat(binder.getBindingResult().getFieldValue("isoLocalTime")).isEqualTo("12:00:00");
}
@Test
public void testBindISODateTime() {
void testBindISODateTime() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("isoDateTime", "2009-10-31T12:00:00");
propertyValues.add("isoLocalDateTime", "2009-10-31T12:00:00");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("isoDateTime")).isEqualTo("2009-10-31T12:00:00");
assertThat(binder.getBindingResult().getFieldValue("isoLocalDateTime")).isEqualTo("2009-10-31T12:00:00");
}
@Test
public void testBindISODateTimeWithZone() {
void testBindISODateTimeWithZone() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("isoDateTime", "2009-10-31T12:00:00.000Z");
propertyValues.add("isoLocalDateTime", "2009-10-31T12:00:00.000Z");
binder.bind(propertyValues);
assertThat(binder.getBindingResult().getErrorCount()).isEqualTo(0);
assertThat(binder.getBindingResult().getFieldValue("isoDateTime")).isEqualTo("2009-10-31T12:00:00");
assertThat(binder.getBindingResult().getFieldValue("isoLocalDateTime")).isEqualTo("2009-10-31T12:00:00");
}
@Test
public void testBindInstant() {
void testBindInstant() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("instant", "2009-10-31T12:00:00.000Z");
binder.bind(propertyValues);
@@ -359,7 +367,7 @@ public class DateTimeFormattingTests {
@Test
@SuppressWarnings("deprecation")
public void testBindInstantFromJavaUtilDate() {
void testBindInstantFromJavaUtilDate() {
TimeZone defaultZone = TimeZone.getDefault();
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
try {
@@ -375,7 +383,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindPeriod() {
void testBindPeriod() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("period", "P6Y3M1D");
binder.bind(propertyValues);
@@ -384,7 +392,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindDuration() {
void testBindDuration() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("duration", "PT8H6M12.345S");
binder.bind(propertyValues);
@@ -393,7 +401,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindYear() {
void testBindYear() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("year", "2007");
binder.bind(propertyValues);
@@ -402,7 +410,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindMonth() {
void testBindMonth() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("month", "JULY");
binder.bind(propertyValues);
@@ -411,7 +419,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindMonthInAnyCase() {
void testBindMonthInAnyCase() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("month", "July");
binder.bind(propertyValues);
@@ -420,7 +428,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindYearMonth() {
void testBindYearMonth() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("yearMonth", "2007-12");
binder.bind(propertyValues);
@@ -429,7 +437,7 @@ public class DateTimeFormattingTests {
}
@Test
public void testBindMonthDay() {
void testBindMonthDay() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("monthDay", "--12-03");
binder.bind(propertyValues);
@@ -437,35 +445,125 @@ public class DateTimeFormattingTests {
assertThat(binder.getBindingResult().getFieldValue("monthDay").toString().equals("--12-03")).isTrue();
}
@Nested
class FallbackPatternTests {
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02", "2021.03.02", "20210302", "3/2/21"})
void styleLocalDate(String propertyValue) {
String propertyName = "styleLocalDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("3/2/21");
}
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02", "2021.03.02", "20210302", "3/2/21"})
void patternLocalDate(String propertyValue) {
String propertyName = "patternLocalDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("2021-03-02");
}
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"12:00:00 PM", "12:00:00", "12:00"})
void styleLocalTime(String propertyValue) {
String propertyName = "styleLocalTimeWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("12:00:00 PM");
}
@ParameterizedTest(name = "input date: {0}")
@ValueSource(strings = {"2021-03-02T12:00:00", "2021-03-02 12:00:00", "3/2/21 12:00"})
void isoLocalDateTime(String propertyValue) {
String propertyName = "isoLocalDateTimeWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(0);
assertThat(bindingResult.getFieldValue(propertyName)).isEqualTo("2021-03-02T12:00:00");
}
@Test
void patternLocalDateWithUnsupportedPattern() {
String propertyValue = "210302";
String propertyName = "patternLocalDateWithFallbackPatterns";
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add(propertyName, propertyValue);
binder.bind(propertyValues);
BindingResult bindingResult = binder.getBindingResult();
assertThat(bindingResult.getErrorCount()).isEqualTo(1);
FieldError fieldError = bindingResult.getFieldError(propertyName);
assertThat(fieldError.unwrap(TypeMismatchException.class))
.hasMessageContaining("for property 'patternLocalDateWithFallbackPatterns'")
.hasCauseInstanceOf(ConversionFailedException.class).getCause()
.hasMessageContaining("for value '210302'")
.hasCauseInstanceOf(IllegalArgumentException.class).getCause()
.hasMessageContaining("Parse attempt failed for value [210302]")
.hasCauseInstanceOf(DateTimeParseException.class).getCause()
// Unable to parse date time value "210302" using configuration from
// @org.springframework.format.annotation.DateTimeFormat(
// pattern=yyyy-MM-dd, style=SS, iso=NONE, fallbackPatterns=[M/d/yy, yyyyMMdd, yyyy.MM.dd])
.hasMessageContainingAll(
"Unable to parse date time value \"210302\" using configuration from",
"@org.springframework.format.annotation.DateTimeFormat",
"yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd");
}
}
public static class DateTimeBean {
private LocalDate localDate;
@DateTimeFormat(style = "M-")
private LocalDate localDateAnnotated;
private LocalDate styleLocalDate;
@DateTimeFormat(style = "S-", fallbackPatterns = { "yyyy-MM-dd", "yyyyMMdd", "yyyy.MM.dd" })
private LocalDate styleLocalDateWithFallbackPatterns;
@DateTimeFormat(pattern = "yyyy-MM-dd", fallbackPatterns = { "M/d/yy", "yyyyMMdd", "yyyy.MM.dd" })
private LocalDate patternLocalDateWithFallbackPatterns;
private LocalTime localTime;
@DateTimeFormat(style = "-M")
private LocalTime localTimeAnnotated;
private LocalTime styleLocalTime;
@DateTimeFormat(style = "-M", fallbackPatterns = { "HH:mm:ss", "HH:mm"})
private LocalTime styleLocalTimeWithFallbackPatterns;
private LocalDateTime localDateTime;
@DateTimeFormat(style = "MM")
private LocalDateTime localDateTimeAnnotated;
private LocalDateTime styleLocalDateTime;
@DateTimeFormat(pattern = "M/d/yy h:mm a")
private LocalDateTime dateTimeAnnotatedPattern;
private LocalDateTime patternLocalDateTime;
@DateTimeFormat(iso = ISO.DATE)
private LocalDate isoDate;
private LocalDate isoLocalDate;
@DateTimeFormat(iso = ISO.TIME)
private LocalTime isoTime;
private LocalTime isoLocalTime;
@DateTimeFormat(iso = ISO.DATE_TIME)
private LocalDateTime isoDateTime;
private LocalDateTime isoLocalDateTime;
@DateTimeFormat(iso = ISO.DATE_TIME, fallbackPatterns = { "yyyy-MM-dd HH:mm:ss", "M/d/yy HH:mm"})
private LocalDateTime isoLocalDateTimeWithFallbackPatterns;
private Instant instant;
@@ -483,88 +581,120 @@ public class DateTimeFormattingTests {
private final List<DateTimeBean> children = new ArrayList<>();
public LocalDate getLocalDate() {
return localDate;
return this.localDate;
}
public void setLocalDate(LocalDate localDate) {
this.localDate = localDate;
}
public LocalDate getLocalDateAnnotated() {
return localDateAnnotated;
public LocalDate getStyleLocalDate() {
return this.styleLocalDate;
}
public void setLocalDateAnnotated(LocalDate localDateAnnotated) {
this.localDateAnnotated = localDateAnnotated;
public void setStyleLocalDate(LocalDate styleLocalDate) {
this.styleLocalDate = styleLocalDate;
}
public LocalDate getStyleLocalDateWithFallbackPatterns() {
return this.styleLocalDateWithFallbackPatterns;
}
public void setStyleLocalDateWithFallbackPatterns(LocalDate styleLocalDateWithFallbackPatterns) {
this.styleLocalDateWithFallbackPatterns = styleLocalDateWithFallbackPatterns;
}
public LocalDate getPatternLocalDateWithFallbackPatterns() {
return this.patternLocalDateWithFallbackPatterns;
}
public void setPatternLocalDateWithFallbackPatterns(LocalDate patternLocalDateWithFallbackPatterns) {
this.patternLocalDateWithFallbackPatterns = patternLocalDateWithFallbackPatterns;
}
public LocalTime getLocalTime() {
return localTime;
return this.localTime;
}
public void setLocalTime(LocalTime localTime) {
this.localTime = localTime;
}
public LocalTime getLocalTimeAnnotated() {
return localTimeAnnotated;
public LocalTime getStyleLocalTime() {
return this.styleLocalTime;
}
public void setLocalTimeAnnotated(LocalTime localTimeAnnotated) {
this.localTimeAnnotated = localTimeAnnotated;
public void setStyleLocalTime(LocalTime styleLocalTime) {
this.styleLocalTime = styleLocalTime;
}
public LocalTime getStyleLocalTimeWithFallbackPatterns() {
return this.styleLocalTimeWithFallbackPatterns;
}
public void setStyleLocalTimeWithFallbackPatterns(LocalTime styleLocalTimeWithFallbackPatterns) {
this.styleLocalTimeWithFallbackPatterns = styleLocalTimeWithFallbackPatterns;
}
public LocalDateTime getLocalDateTime() {
return localDateTime;
return this.localDateTime;
}
public void setLocalDateTime(LocalDateTime localDateTime) {
this.localDateTime = localDateTime;
}
public LocalDateTime getLocalDateTimeAnnotated() {
return localDateTimeAnnotated;
public LocalDateTime getStyleLocalDateTime() {
return this.styleLocalDateTime;
}
public void setLocalDateTimeAnnotated(LocalDateTime localDateTimeAnnotated) {
this.localDateTimeAnnotated = localDateTimeAnnotated;
public void setStyleLocalDateTime(LocalDateTime styleLocalDateTime) {
this.styleLocalDateTime = styleLocalDateTime;
}
public LocalDateTime getDateTimeAnnotatedPattern() {
return dateTimeAnnotatedPattern;
public LocalDateTime getPatternLocalDateTime() {
return this.patternLocalDateTime;
}
public void setDateTimeAnnotatedPattern(LocalDateTime dateTimeAnnotatedPattern) {
this.dateTimeAnnotatedPattern = dateTimeAnnotatedPattern;
public void setPatternLocalDateTime(LocalDateTime patternLocalDateTime) {
this.patternLocalDateTime = patternLocalDateTime;
}
public LocalDate getIsoDate() {
return isoDate;
public LocalDate getIsoLocalDate() {
return this.isoLocalDate;
}
public void setIsoDate(LocalDate isoDate) {
this.isoDate = isoDate;
public void setIsoLocalDate(LocalDate isoLocalDate) {
this.isoLocalDate = isoLocalDate;
}
public LocalTime getIsoTime() {
return isoTime;
public LocalTime getIsoLocalTime() {
return this.isoLocalTime;
}
public void setIsoTime(LocalTime isoTime) {
this.isoTime = isoTime;
public void setIsoLocalTime(LocalTime isoLocalTime) {
this.isoLocalTime = isoLocalTime;
}
public LocalDateTime getIsoDateTime() {
return isoDateTime;
public LocalDateTime getIsoLocalDateTime() {
return this.isoLocalDateTime;
}
public void setIsoDateTime(LocalDateTime isoDateTime) {
this.isoDateTime = isoDateTime;
public void setIsoLocalDateTime(LocalDateTime isoLocalDateTime) {
this.isoLocalDateTime = isoLocalDateTime;
}
public LocalDateTime getIsoLocalDateTimeWithFallbackPatterns() {
return this.isoLocalDateTimeWithFallbackPatterns;
}
public void setIsoLocalDateTimeWithFallbackPatterns(LocalDateTime isoLocalDateTimeWithFallbackPatterns) {
this.isoLocalDateTimeWithFallbackPatterns = isoLocalDateTimeWithFallbackPatterns;
}
public Instant getInstant() {
return instant;
return this.instant;
}
public void setInstant(Instant instant) {
@@ -572,7 +702,7 @@ public class DateTimeFormattingTests {
}
public Period getPeriod() {
return period;
return this.period;
}
public void setPeriod(Period period) {
@@ -580,7 +710,7 @@ public class DateTimeFormattingTests {
}
public Duration getDuration() {
return duration;
return this.duration;
}
public void setDuration(Duration duration) {
@@ -588,7 +718,7 @@ public class DateTimeFormattingTests {
}
public Year getYear() {
return year;
return this.year;
}
public void setYear(Year year) {
@@ -596,7 +726,7 @@ public class DateTimeFormattingTests {
}
public Month getMonth() {
return month;
return this.month;
}
public void setMonth(Month month) {
@@ -604,7 +734,7 @@ public class DateTimeFormattingTests {
}
public YearMonth getYearMonth() {
return yearMonth;
return this.yearMonth;
}
public void setYearMonth(YearMonth yearMonth) {
@@ -612,7 +742,7 @@ public class DateTimeFormattingTests {
}
public MonthDay getMonthDay() {
return monthDay;
return this.monthDay;
}
public void setMonthDay(MonthDay monthDay) {
@@ -620,7 +750,7 @@ public class DateTimeFormattingTests {
}
public List<DateTimeBean> getChildren() {
return children;
return this.children;
}
}