From f26552efabf876b589fff12c31e1b6de9b52b2ba 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 d69e9c15e5fb..2158a4684fa9 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 Date parse(String text, Locale locale) throws ParseException { } } 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 ebfbc694dc51..15342c69b6ad 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 @@ void testBindDateAnnotated() { 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 @@ void patternDateWithUnsupportedPattern() { .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(); } }