Author: j...@google.com Date: Mon Jun 1 22:59:06 2009 New Revision: 5490 Modified: trunk/user/super/com/google/gwt/emul/java/util/Date.java trunk/user/test/com/google/gwt/emultest/java/util/DateTest.java
Log: two changes to java.util.Date in an effort to track down a very intermittent failure on IE. IE doesn't provide useful stack traces for JS-initiated exceptions, so all we know is that jsdate is uninitialized or not an object at some point when it is dereferenced. The changes are: - use a JSO field storing the JS Date object rather than making an expando on the underlying object (which couldn't ever work in hosted mode, but since this is a JRE emulation class it didn't have to) - add checks before each dereference of jsdate to see if it has been mangled; if so throws a Java exception so we can get a good stack trace. This does add some overhead, but it shouldn't be too bad. This is a temporary change that will be removed once the cause is found. Patch by: jat Review by: amitmanjhi, scottb Modified: trunk/user/super/com/google/gwt/emul/java/util/Date.java ============================================================================== --- trunk/user/super/com/google/gwt/emul/java/util/Date.java (original) +++ trunk/user/super/com/google/gwt/emul/java/util/Date.java Mon Jun 1 22:59:06 2009 @@ -15,12 +15,21 @@ */ package java.util; +import com.google.gwt.core.client.JavaScriptObject; + import java.io.Serializable; /** * Represents a date and time. */ public class Date implements Cloneable, Comparable<Date>, Serializable { + + /** + * JavaScript Date instance. + */ + @SuppressWarnings("unused") // used from JSNI + private JavaScriptObject jsdate; + /** * Used only by toString(). */ @@ -88,6 +97,16 @@ return isNaN(d) ? -1 : d; }-*/; + /** + * Throw an exception if jsdate is not an object. + * + * @param val + */ + @SuppressWarnings("unused") // called by JSNI + private static void throwJsDateException(String val) { + throw new IllegalStateException("jsdate is " + val); + } + private static native double utc0(int year, int month, int date, int hrs, int min, int sec) /*-{ return Date.UTC(year + 1900, month, date, hrs, min, sec); @@ -147,27 +166,33 @@ } public native int getDate() /*-{ - return this.jsdate.getDate(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getDate(); }-*/; public native int getDay() /*-{ - return this.jsdate.getDay(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getDay(); }-*/; public native int getHours() /*-{ - return this.jsdate.getHours(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getHours(); }-*/; public native int getMinutes() /*-{ - return this.jsdate.getMinutes(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getMinutes(); }-*/; public native int getMonth() /*-{ - return this.jsdate.getMonth(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getMonth(); }-*/; public native int getSeconds() /*-{ - return this.jsdate.getSeconds(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getSeconds(); }-*/; public long getTime() { @@ -175,11 +200,13 @@ } public native int getTimezoneOffset() /*-{ - return this.jsdate.getTimezoneOffset(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getTimezoneOffset(); }-*/; public native int getYear() /*-{ - return this.jsdate.getFullYear()-1900; + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getFullYear()-1900; }-*/; @Override @@ -188,23 +215,28 @@ } public native void setDate(int date) /*-{ - this.jsdate.setDate(date); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setDate(date); }-*/; public native void setHours(int hours) /*-{ - this.jsdate.setHours(hours); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setHours(hours); }-*/; public native void setMinutes(int minutes) /*-{ - this.jsdate.setMinutes(minutes); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setMinutes(minutes); }-*/; public native void setMonth(int month) /*-{ - this.jsdate.setMonth(month); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setMonth(month); }-*/; public native void setSeconds(int seconds) /*-{ - this.jsdate.setSeconds(seconds); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setSeconds(seconds); }-*/; public void setTime(long time) { @@ -212,14 +244,16 @@ } public native void setYear(int year) /*-{ - this.jsdate.setFullYear(year + 1900); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setFullYear(year + 1900); }-*/; public native String toGMTString() /*-{ - var d = this.jsdate; + th...@java.util.date::checkJsDate()(); + var d = th...@java.util.date::jsdate; var padTwo = @java.util.Date::padTwo(I); var month = - @java.util.Date::monthToString(I)(this.jsdate.getUTCMonth()); + @java.util.Date::monthToString(I)(th...@java.util.date::jsdate.getUTCMonth()); return d.getUTCDate() + " " + month + " " + @@ -231,17 +265,19 @@ }-*/; public native String toLocaleString() /*-{ - return this.jsdate.toLocaleString(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.toLocaleString(); }-*/; @Override public native String toString() /*-{ - var d = this.jsdate; + th...@java.util.date::checkJsDate()(); + var d = th...@java.util.date::jsdate; var padTwo = @java.util.Date::padTwo(I); var day = - @java.util.Date::dayToString(I)(this.jsdate.getDay()); + @java.util.Date::dayToString(I)(d.getDay()); var month = - @java.util.Date::monthToString(I)(this.jsdate.getMonth()); + @java.util.Date::monthToString(I)(d.getMonth()); // Compute timezone offset. The value that getTimezoneOffset returns is // backwards for the transformation that we want. @@ -259,26 +295,41 @@ + " " + d.getFullYear(); }-*/; + /** + * Check that jsdate is valid and throw an exception if not. + */ + @SuppressWarnings("unused") // called by JSNI + private native void checkJsDate() /*-{ + if (!th...@java.util.date::jsdate + || typeof th...@java.util.date::jsdate != "object") { + @java.util.Date::throwJsDateException(Ljava/lang/String;)("" + + th...@java.util.date::jsdate); + } + }-*/; + private native double getTime0() /*-{ - return this.jsdate.getTime(); + th...@java.util.date::checkJsDate()(); + return th...@java.util.date::jsdate.getTime(); }-*/; private native void init() /*-{ - this.jsdate = new Date(); + th...@java.util.date::jsdate = new Date(); }-*/; private native void init(double date) /*-{ - this.jsdate = new Date(date); + th...@java.util.date::jsdate = new Date(date); }-*/; private native void init(int year, int month, int date, int hrs, int min, int sec) /*-{ - this.jsdate = new Date(); - this.jsdate.setFullYear(year + 1900, month, date); - this.jsdate.setHours(hrs, min, sec, 0); + th...@java.util.date::jsdate = new Date(); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setFullYear(year + 1900, month, date); + th...@java.util.date::jsdate.setHours(hrs, min, sec, 0); }-*/; private native void setTime0(double time) /*-{ - this.jsdate.setTime(time); + th...@java.util.date::checkJsDate()(); + th...@java.util.date::jsdate.setTime(time); }-*/; } Modified: trunk/user/test/com/google/gwt/emultest/java/util/DateTest.java ============================================================================== --- trunk/user/test/com/google/gwt/emultest/java/util/DateTest.java (original) +++ trunk/user/test/com/google/gwt/emultest/java/util/DateTest.java Mon Jun 1 22:59:06 2009 @@ -32,6 +32,21 @@ public static final String PAST = "PAST"; public static final long SECOND_MILLISECONDS_SHIFT = 10; + private static native void mungeDateNull(Date d) /*-{ + d...@java.util.date::jsdate = null; + }-*/; + + private static native void mungeDatePrimitive(Date d) /*-{ + d...@java.util.date::jsdate = 42; + }-*/; + + private static native void mungeDateUndef(Date d) /*-{ + // use (void 0) to get an undefined value + d...@java.util.date::jsdate = (void 0); + }-*/; + + Date theDate = new Date(); + /** * Sets module name so that javascript compiler can operate. */ @@ -94,6 +109,39 @@ assertFalse(a2); } + /** + * Test that Date correctly catches when its internal jsdate + * instance is mangled. + */ + public void testCheck() { + if (GWT.isScript()) { + Date d = new Date(); + mungeDateNull(d); + try { + d.getHours(); + fail("Expected IllegalStateException"); + } catch (IllegalStateException expected) { + // do nothing + } + d = new Date(); + mungeDateUndef(d); + try { + d.getHours(); + fail("Expected IllegalStateException"); + } catch (IllegalStateException expected) { + // do nothing + } + d = new Date(); + mungeDatePrimitive(d); + try { + d.getHours(); + fail("Expected IllegalStateException"); + } catch (IllegalStateException expected) { + // do nothing + } + } + } + /** Testing for public java.lang.Object java.util.Date.clone(). */ public void testClone() { @@ -303,6 +351,21 @@ assertEquals(110, a2); } + /** + * Testing to that if we set the day number to 31 for a month that only has 30 + * days in it, that the date rolls over to the first day of the next month in + * sequence. + */ + public void testInvalidDateForMonth() { + int monthNum = 3; // April + int numDaysInOldMonth = 30; + int newDayNum = 31; + Date dateWithThirtyDays = new Date(2006, monthNum, 30); + dateWithThirtyDays.setDate(newDayNum); + assertEquals(dateWithThirtyDays.getMonth(), monthNum + 1); + assertEquals(dateWithThirtyDays.getDate(), newDayNum - numDaysInOldMonth); + } + /** Testing for public static long java.util.Date.parse(java.lang.String). */ public void testParse() { try { @@ -356,21 +419,6 @@ } } - /** - * Testing to that if we set the day number to 31 for a month that only has 30 - * days in it, that the date rolls over to the first day of the next month in - * sequence. - */ - public void testInvalidDateForMonth() { - int monthNum = 3; // April - int numDaysInOldMonth = 30; - int newDayNum = 31; - Date dateWithThirtyDays = new Date(2006, monthNum, 30); - dateWithThirtyDays.setDate(newDayNum); - assertEquals(dateWithThirtyDays.getMonth(), monthNum + 1); - assertEquals(dateWithThirtyDays.getDate(), newDayNum - numDaysInOldMonth); - } - /** Testing for public void java.util.Date.setHours(int). */ public void testSetHours() { for (int i = 0; i < 24; i++) { @@ -380,6 +428,39 @@ } } + /** + * We want to test to see that if we are currently in a month with 31 days and + * we set the month to one which has less than 31 days, that the month + * returned by the date class will be one higher than the month that we + * originally set (according to the spec of java.util.date). + */ + public void testSetInvalidMonthForDate() { + int dayNum = 31; + int newMonthNum = 1; + int numDaysInNewMonth = 28; + Date dateWithThirtyOneDays = new Date(2006, 12, dayNum); + dateWithThirtyOneDays.setMonth(newMonthNum); + assertEquals(dateWithThirtyOneDays.getMonth(), newMonthNum + 1); + assertEquals(dateWithThirtyOneDays.getDate(), dayNum - numDaysInNewMonth); + } + + /** + * We want to test to see that if the date is Feb 29th (in a leap year) and we + * set the year to a non-leap year, that the month and day will roll over to + * March 1st. + */ + public void testSetInvalidYearForDate() { + int dayNum = 29; + int monthNum = 1; // February + int newYearNum = 2005; + int numDaysInFebInNewYear = 28; + Date leapYearDate = new Date(2004, monthNum, dayNum); + leapYearDate.setYear(newYearNum); + assertEquals(leapYearDate.getYear(), newYearNum); + assertEquals(leapYearDate.getMonth(), monthNum + 1); + assertEquals(leapYearDate.getDate(), dayNum - numDaysInFebInNewYear); + } + /** Testing for public void java.util.Date.setMinutes(int). */ public void testSetMinutes() { for (int i = 0; i < 24; i++) { @@ -403,22 +484,6 @@ } } - /** - * We want to test to see that if we are currently in a month with 31 days and - * we set the month to one which has less than 31 days, that the month - * returned by the date class will be one higher than the month that we - * originally set (according to the spec of java.util.date). - */ - public void testSetInvalidMonthForDate() { - int dayNum = 31; - int newMonthNum = 1; - int numDaysInNewMonth = 28; - Date dateWithThirtyOneDays = new Date(2006, 12, dayNum); - dateWithThirtyOneDays.setMonth(newMonthNum); - assertEquals(dateWithThirtyOneDays.getMonth(), newMonthNum + 1); - assertEquals(dateWithThirtyOneDays.getDate(), dayNum - numDaysInNewMonth); - } - /** Testing for public void java.util.Date.setSeconds(int). */ public void testSetSeconds() { for (int i = 0; i < 24; i++) { @@ -438,35 +503,6 @@ } } - /** Testing for public void java.util.Date.setYear(int). */ - public void testSetYear() { - for (int i = 1880; i < 2050; i++) { - // We want to use a fixed date here. If we use the current date, the - // assertion may fail - // when the date is February 29th, and we set the year to a non-leap year - Date accum0 = new Date(2006, 12, 01); - accum0.setYear(i); - assertEquals(accum0.getYear(), i); - } - } - - /** - * We want to test to see that if the date is Feb 29th (in a leap year) and we - * set the year to a non-leap year, that the month and day will roll over to - * March 1st. - */ - public void testSetInvalidYearForDate() { - int dayNum = 29; - int monthNum = 1; // February - int newYearNum = 2005; - int numDaysInFebInNewYear = 28; - Date leapYearDate = new Date(2004, monthNum, dayNum); - leapYearDate.setYear(newYearNum); - assertEquals(leapYearDate.getYear(), newYearNum); - assertEquals(leapYearDate.getMonth(), monthNum + 1); - assertEquals(leapYearDate.getDate(), dayNum - numDaysInFebInNewYear); - } - /** * We want to test to see that if the date is Feb 29th (in a leap year) and we * set the year to another leap year, that the month and day will be retained. @@ -483,6 +519,18 @@ assertEquals(leapYearDate.getDate(), dayNum); } + /** Testing for public void java.util.Date.setYear(int). */ + public void testSetYear() { + for (int i = 1880; i < 2050; i++) { + // We want to use a fixed date here. If we use the current date, the + // assertion may fail + // when the date is February 29th, and we set the year to a non-leap year + Date accum0 = new Date(2006, 12, 01); + accum0.setYear(i); + assertEquals(accum0.getYear(), i); + } + } + /** Testing for public java.lang.String java.util.Date.toGMTString(). */ public void testToGMTString() { @@ -618,6 +666,4 @@ private long roundToDay(long accum0) { return accum0 >> DAY_MILLISECONDS_SHIFT << DAY_MILLISECONDS_SHIFT; } - - Date theDate = new Date(); } --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---