From 0f31830ae2a75da60e839246cb80c4057f9ef5fc Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 16 Apr 2021 19:07:15 +0200 Subject: [PATCH] Retain root cause for parsing patterns in @DateTimeFormat The support for fallback parsing patterns in @DateTimeFormat introduced in gh-20292 introduced a regression in that the original cause of the parsing exception was no longer retained. gh-26777 addressed that regression for `java.time` support; whereas, this commit addresses that regression for legacy Date types. This commit ensures that the original ParseException is set as the cause for any newly created ParseException, thereby retaining the original exception as the root cause. Closes gh-26804 --- .../format/datetime/DateFormatter.java | 4 ++- .../format/datetime/DateFormattingTests.java | 35 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java index d69e9c15e5..2158a4684f 100644 --- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java +++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java @@ -219,9 +219,11 @@ public class DateFormatter implements Formatter { } } if (this.source != null) { - throw new ParseException( + ParseException parseException = new ParseException( String.format("Unable to parse date time value \"%s\" using configuration from %s", text, this.source), ex.getErrorOffset()); + parseException.initCause(ex); + throw parseException; } // else rethrow original exception throw ex; diff --git a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java index ebfbc694dc..15342c69b6 100644 --- a/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java +++ b/spring-context/src/test/java/org/springframework/format/datetime/DateFormattingTests.java @@ -119,6 +119,36 @@ public class DateFormattingTests { assertThat(binder.getBindingResult().getFieldValue("styleDate")).isEqualTo("10/31/09"); } + @Test + void styleDateWithInvalidFormat() { + String propertyName = "styleDate"; + String propertyValue = "99/01/01"; + 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); + TypeMismatchException exception = fieldError.unwrap(TypeMismatchException.class); + exception.printStackTrace(System.err); + assertThat(exception) + .hasMessageContaining("for property 'styleDate'") + .hasCauseInstanceOf(ConversionFailedException.class).getCause() + .hasMessageContaining("for value '99/01/01'") + .hasCauseInstanceOf(IllegalArgumentException.class).getCause() + .hasMessageContaining("Parse attempt failed for value [99/01/01]") + .hasCauseInstanceOf(ParseException.class).getCause() + // Unable to parse date time value "99/01/01" using configuration from + // @org.springframework.format.annotation.DateTimeFormat(pattern=, style=S-, iso=NONE, fallbackPatterns=[]) + .hasMessageContainingAll( + "Unable to parse date time value \"99/01/01\" using configuration from", + "@org.springframework.format.annotation.DateTimeFormat", + "style=S-", "iso=NONE", "fallbackPatterns=[]") + .hasCauseInstanceOf(ParseException.class).getCause() + .hasMessageStartingWith("Unparseable date: \"99/01/01\"") + .hasNoCause(); + } + @Test void testBindDateArray() { MutablePropertyValues propertyValues = new MutablePropertyValues(); @@ -330,7 +360,10 @@ public class DateFormattingTests { .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"); + "yyyy-MM-dd", "M/d/yy", "yyyyMMdd", "yyyy.MM.dd") + .hasCauseInstanceOf(ParseException.class).getCause() + .hasMessageStartingWith("Unparseable date: \"210302\"") + .hasNoCause(); } }