8025718: Enhance error messages for parsing
authorrriggs
Thu, 26 Sep 2013 15:19:27 -0700
changeset 20747 86a86a94b367
parent 20746 e41a8a513b3e
child 20748 fbf53402134d
8025718: Enhance error messages for parsing Summary: Add values and types to exception messages Reviewed-by: lancea Contributed-by: scolebourne@joda.org
jdk/src/share/classes/java/time/DayOfWeek.java
jdk/src/share/classes/java/time/Instant.java
jdk/src/share/classes/java/time/LocalDate.java
jdk/src/share/classes/java/time/LocalDateTime.java
jdk/src/share/classes/java/time/LocalTime.java
jdk/src/share/classes/java/time/Month.java
jdk/src/share/classes/java/time/MonthDay.java
jdk/src/share/classes/java/time/OffsetDateTime.java
jdk/src/share/classes/java/time/OffsetTime.java
jdk/src/share/classes/java/time/Year.java
jdk/src/share/classes/java/time/YearMonth.java
jdk/src/share/classes/java/time/ZoneId.java
jdk/src/share/classes/java/time/ZoneOffset.java
jdk/src/share/classes/java/time/ZonedDateTime.java
jdk/src/share/classes/java/time/format/Parsed.java
jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java
--- a/jdk/src/share/classes/java/time/DayOfWeek.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/DayOfWeek.java	Thu Sep 26 15:19:27 2013 -0700
@@ -187,7 +187,12 @@
         if (temporal instanceof DayOfWeek) {
             return (DayOfWeek) temporal;
         }
-        return of(temporal.get(DAY_OF_WEEK));
+        try {
+            return of(temporal.get(DAY_OF_WEEK));
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain DayOfWeek from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
+        }
     }
 
     //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/Instant.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/Instant.java	Thu Sep 26 15:19:27 2013 -0700
@@ -366,9 +366,14 @@
             return (Instant) temporal;
         }
         Objects.requireNonNull(temporal, "temporal");
-        long instantSecs = temporal.getLong(INSTANT_SECONDS);
-        int nanoOfSecond = temporal.get(NANO_OF_SECOND);
-        return Instant.ofEpochSecond(instantSecs, nanoOfSecond);
+        try {
+            long instantSecs = temporal.getLong(INSTANT_SECONDS);
+            int nanoOfSecond = temporal.get(NANO_OF_SECOND);
+            return Instant.ofEpochSecond(instantSecs, nanoOfSecond);
+        } catch (DateTimeException ex) {
+            throw new DateTimeException("Unable to obtain Instant from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
+        }
     }
 
     //-----------------------------------------------------------------------
--- a/jdk/src/share/classes/java/time/LocalDate.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/LocalDate.java	Thu Sep 26 15:19:27 2013 -0700
@@ -356,7 +356,8 @@
         Objects.requireNonNull(temporal, "temporal");
         LocalDate date = temporal.query(TemporalQuery.localDate());
         if (date == null) {
-            throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " + temporal.getClass());
+            throw new DateTimeException("Unable to obtain LocalDate from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
         }
         return date;
     }
--- a/jdk/src/share/classes/java/time/LocalDateTime.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/LocalDateTime.java	Thu Sep 26 15:19:27 2013 -0700
@@ -449,7 +449,8 @@
             LocalTime time = LocalTime.from(temporal);
             return new LocalDateTime(date, time);
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain LocalDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain LocalDateTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/LocalTime.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/LocalTime.java	Thu Sep 26 15:19:27 2013 -0700
@@ -397,7 +397,8 @@
         Objects.requireNonNull(temporal, "temporal");
         LocalTime time = temporal.query(TemporalQuery.localTime());
         if (time == null) {
-            throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " + temporal.getClass());
+            throw new DateTimeException("Unable to obtain LocalTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
         }
         return time;
     }
--- a/jdk/src/share/classes/java/time/Month.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/Month.java	Thu Sep 26 15:19:27 2013 -0700
@@ -217,7 +217,8 @@
             }
             return of(temporal.get(MONTH_OF_YEAR));
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain Month from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain Month from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/MonthDay.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/MonthDay.java	Thu Sep 26 15:19:27 2013 -0700
@@ -266,7 +266,8 @@
             }
             return of(temporal.get(MONTH_OF_YEAR), temporal.get(DAY_OF_MONTH));
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain MonthDay from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/OffsetDateTime.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/OffsetDateTime.java	Thu Sep 26 15:19:27 2013 -0700
@@ -347,8 +347,8 @@
         if (temporal instanceof OffsetDateTime) {
             return (OffsetDateTime) temporal;
         }
-        ZoneOffset offset = ZoneOffset.from(temporal);
         try {
+            ZoneOffset offset = ZoneOffset.from(temporal);
             try {
                 LocalDateTime ldt = LocalDateTime.from(temporal);
                 return OffsetDateTime.of(ldt, offset);
@@ -357,7 +357,8 @@
                 return OffsetDateTime.ofInstant(instant, offset);
             }
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain OffsetDateTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/OffsetTime.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/OffsetTime.java	Thu Sep 26 15:19:27 2013 -0700
@@ -284,7 +284,8 @@
             ZoneOffset offset = ZoneOffset.from(temporal);
             return new OffsetTime(time, offset);
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain OffsetTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/Year.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/Year.java	Thu Sep 26 15:19:27 2013 -0700
@@ -249,7 +249,8 @@
             }
             return of(temporal.get(YEAR));
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain Year from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain Year from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/YearMonth.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/YearMonth.java	Thu Sep 26 15:19:27 2013 -0700
@@ -252,7 +252,8 @@
             }
             return of(temporal.get(YEAR), temporal.get(MONTH_OF_YEAR));
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain YearMonth from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/ZoneId.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/ZoneId.java	Thu Sep 26 15:19:27 2013 -0700
@@ -504,7 +504,8 @@
     public static ZoneId from(TemporalAccessor temporal) {
         ZoneId obj = temporal.query(TemporalQuery.zone());
         if (obj == null) {
-            throw new DateTimeException("Unable to obtain ZoneId from TemporalAccessor: " + temporal.getClass());
+            throw new DateTimeException("Unable to obtain ZoneId from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
         }
         return obj;
     }
--- a/jdk/src/share/classes/java/time/ZoneOffset.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/ZoneOffset.java	Thu Sep 26 15:19:27 2013 -0700
@@ -336,7 +336,8 @@
         Objects.requireNonNull(temporal, "temporal");
         ZoneOffset offset = temporal.query(TemporalQuery.offset());
         if (offset == null) {
-            throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " + temporal.getClass());
+            throw new DateTimeException("Unable to obtain ZoneOffset from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName());
         }
         return offset;
     }
--- a/jdk/src/share/classes/java/time/ZonedDateTime.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/ZonedDateTime.java	Thu Sep 26 15:19:27 2013 -0700
@@ -553,7 +553,8 @@
                 return of(ldt, zone);
             }
         } catch (DateTimeException ex) {
-            throw new DateTimeException("Unable to create ZonedDateTime from TemporalAccessor: " + temporal.getClass(), ex);
+            throw new DateTimeException("Unable to obtain ZonedDateTime from TemporalAccessor: " +
+                    temporal + " of type " + temporal.getClass().getName(), ex);
         }
     }
 
--- a/jdk/src/share/classes/java/time/format/Parsed.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/src/share/classes/java/time/format/Parsed.java	Thu Sep 26 15:19:27 2013 -0700
@@ -588,11 +588,23 @@
     //-----------------------------------------------------------------------
     @Override
     public String toString() {
-        String str = fieldValues.toString() + "," + chrono + "," + zone;
+        StringBuilder buf = new StringBuilder(64);
+        buf.append(fieldValues).append(',').append(chrono);
+        if (zone != null) {
+            buf.append(',').append(zone);
+        }
         if (date != null || time != null) {
-            str += " resolved to " + date + "," + time;
+            buf.append(" resolved to ");
+            if (date != null) {
+                buf.append(date);
+                if (time != null) {
+                    buf.append('T').append(time);
+                }
+            } else {
+                buf.append(time);
+            }
         }
-        return str;
+        return buf.toString();
     }
 
 }
--- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java	Wed Oct 09 11:02:55 2013 -0400
+++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java	Thu Sep 26 15:19:27 2013 -0700
@@ -61,12 +61,32 @@
 
 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
 import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
-import java.time.format.DecimalStyle;
+import java.time.DateTimeException;
+import java.time.DayOfWeek;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Month;
+import java.time.MonthDay;
+import java.time.OffsetDateTime;
+import java.time.OffsetTime;
+import java.time.Year;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.chrono.ThaiBuddhistChronology;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
+import java.time.format.DecimalStyle;
 import java.time.format.SignStyle;
+import java.time.temporal.TemporalAccessor;
 import java.util.Locale;
+import java.util.function.Function;
 
 import org.testng.annotations.Test;
 
@@ -87,4 +107,93 @@
         assertSame(test, base);
     }
 
+    @Test
+    public void test_parse_errorMessage() throws Exception {
+        assertGoodErrorDate(DayOfWeek::from, "DayOfWeek");
+        assertGoodErrorDate(Month::from, "Month");
+        assertGoodErrorDate(YearMonth::from, "YearMonth");
+        assertGoodErrorDate(MonthDay::from, "MonthDay");
+        assertGoodErrorDate(LocalDate::from, "LocalDate");
+        assertGoodErrorDate(LocalTime::from, "LocalTime");
+        assertGoodErrorDate(LocalDateTime::from, "LocalDateTime");
+        assertGoodErrorDate(OffsetTime::from, "OffsetTime");
+        assertGoodErrorDate(OffsetDateTime::from, "OffsetDateTime");
+        assertGoodErrorDate(ZonedDateTime::from, "ZonedDateTime");
+        assertGoodErrorDate(Instant::from, "Instant");
+        assertGoodErrorDate(ZoneOffset::from, "ZoneOffset");
+        assertGoodErrorDate(ZoneId::from, "ZoneId");
+        assertGoodErrorDate(ThaiBuddhistChronology.INSTANCE::date, "");
+
+        assertGoodErrorTime(DayOfWeek::from, "DayOfWeek");
+        assertGoodErrorTime(Month::from, "Month");
+        assertGoodErrorTime(Year::from, "Year");
+        assertGoodErrorTime(YearMonth::from, "YearMonth");
+        assertGoodErrorTime(MonthDay::from, "MonthDay");
+        assertGoodErrorTime(LocalDate::from, "LocalDate");
+        assertGoodErrorTime(LocalTime::from, "LocalTime");
+        assertGoodErrorTime(LocalDateTime::from, "LocalDateTime");
+        assertGoodErrorTime(OffsetTime::from, "OffsetTime");
+        assertGoodErrorTime(OffsetDateTime::from, "OffsetDateTime");
+        assertGoodErrorTime(ZonedDateTime::from, "ZonedDateTime");
+        assertGoodErrorTime(Instant::from, "Instant");
+        assertGoodErrorTime(ZoneOffset::from, "ZoneOffset");
+        assertGoodErrorTime(ZoneId::from, "ZoneId");
+        assertGoodErrorTime(ThaiBuddhistChronology.INSTANCE::date, "");
+    }
+
+    private void assertGoodErrorDate(Function<TemporalAccessor, Object> function, String expectedText) {
+        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-mm-dd");
+        TemporalAccessor temporal = f.parse("2010-06-30");
+        try {
+            function.apply(temporal);
+            fail("Should have failed");
+        } catch (DateTimeException ex) {
+            String msg = ex.getMessage();
+            assertTrue(msg.contains(expectedText), msg);
+            assertTrue(msg.contains("Year"), msg);
+            assertTrue(msg.contains("MinuteOfHour"), msg);
+            assertTrue(msg.contains("DayOfMonth"), msg);
+        }
+    }
+
+    private void assertGoodErrorTime(Function<TemporalAccessor, Object> function, String expectedText) {
+        DateTimeFormatter f = DateTimeFormatter.ofPattern("HH:MM:ss");
+        TemporalAccessor temporal = f.parse("11:30:56");
+        try {
+            function.apply(temporal);
+            fail("Should have failed");
+        } catch (DateTimeException ex) {
+            String msg = ex.getMessage();
+            assertTrue(msg.contains(expectedText), msg);
+            assertTrue(msg.contains("HourOfDay"), msg);
+            assertTrue(msg.contains("MonthOfYear"), msg);
+            assertTrue(msg.contains("SecondOfMinute"), msg);
+        }
+    }
+
+    @Test
+    public void test_parsed_toString_resolvedTime() {
+        DateTimeFormatter f = DateTimeFormatter.ofPattern("HH:mm:ss");
+        TemporalAccessor temporal = f.parse("11:30:56");
+        String msg = temporal.toString();
+        assertTrue(msg.contains("11:30:56"), msg);
+    }
+
+    @Test
+    public void test_parsed_toString_resolvedDate() {
+        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        TemporalAccessor temporal = f.parse("2010-06-30");
+        String msg = temporal.toString();
+        assertTrue(msg.contains("2010-06-30"), msg);
+    }
+
+    @Test
+    public void test_parsed_toString_resolvedDateTime() {
+        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        TemporalAccessor temporal = f.parse("2010-06-30 11:30:56");
+        String msg = temporal.toString();
+        assertTrue(msg.contains("2010-06-30"), msg);
+        assertTrue(msg.contains("11:30:56"), msg);
+    }
+
 }