jaxp/src/com/sun/org/apache/xerces/internal/jaxp/datatype/XMLGregorianCalendarImpl.java

Print this page

        

@@ -23,10 +23,12 @@
  * questions.
  */
 
 package com.sun.org.apache.xerces.internal.jaxp.datatype;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.TimeZone;
 import java.util.Calendar;

@@ -193,10 +195,21 @@
 
 public class XMLGregorianCalendarImpl
         extends XMLGregorianCalendar
         implements Serializable, Cloneable {
 
+    /** Backup values **/
+    transient private BigInteger orig_eon;
+    transient private int orig_year = DatatypeConstants.FIELD_UNDEFINED;
+    transient private int orig_month = DatatypeConstants.FIELD_UNDEFINED;
+    transient private int orig_day = DatatypeConstants.FIELD_UNDEFINED;
+    transient private int orig_hour = DatatypeConstants.FIELD_UNDEFINED;
+    transient private int orig_minute = DatatypeConstants.FIELD_UNDEFINED;
+    transient private int orig_second = DatatypeConstants.FIELD_UNDEFINED;
+    transient private BigDecimal orig_fracSeconds;
+    transient private int orig_timezone = DatatypeConstants.FIELD_UNDEFINED;
+
     /**
      * <p>Eon of this <code>XMLGregorianCalendar</code>.</p>
      */
     private BigInteger eon = null;
 

@@ -239,15 +252,20 @@
      * <p>Fractional second of this <code>XMLGregorianCalendar</code>.</p>
      */
     private BigDecimal fractionalSecond = null;
 
     /**
-     * <p>Constant to represent a billion.</p>
+     * <p>BigInteger constant; representing a billion.</p>
      */
-    private static final BigInteger BILLION = new BigInteger("1000000000");
+    private static final BigInteger BILLION_B = new BigInteger("1000000000");
 
     /**
+     * <p>int constant; representing a billion.</p>
+     */
+    private static final int BILLION_I = 1000000000;
+    
+    /**
      *   <p>Obtain a pure Gregorian Calendar by calling
      *   GregorianCalendar.setChange(PURE_GREGORIAN_CHANGE). </p>
      */
     private static final Date PURE_GREGORIAN_CHANGE =
         new Date(Long.MIN_VALUE);

@@ -439,13 +457,30 @@
             throw new IllegalArgumentException(
                     DatatypeMessageFormatter.formatMessage(null, "InvalidXGCRepresentation", new Object[]{lexicalRepresentation})
                     //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value."
             );
         }
+        
+        save();
     }
 
     /**
+     * save original values
+     */
+    private void save() {
+        orig_eon = eon;
+        orig_year = year;
+        orig_month = month;
+        orig_day = day;
+        orig_hour = hour;
+        orig_minute = minute;
+        orig_second = second;
+        orig_fracSeconds = fractionalSecond;
+        orig_timezone = timezone;
+    }
+    
+    /**
      * <p>Create an instance with all date/time datatype fields set to
      * {@link DatatypeConstants#FIELD_UNDEFINED} or null respectively.</p>
      */
     public XMLGregorianCalendarImpl() {
 

@@ -519,10 +554,11 @@
                 );
                 */
 
                 }
 
+        save();
     }
 
     /**
      * <p>Private constructor of value spaces that a
      * <code>java.util.GregorianCalendar</code> instance would need to convert to an

@@ -553,11 +589,15 @@
                 setYear(year);
         setMonth(month);
         setDay(day);
         setTime(hour, minute, second);
                 setTimezone(timezone);
-                setMillisecond(millisecond);
+        BigDecimal realMilliseconds = null;
+        if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
+            realMilliseconds = BigDecimal.valueOf(millisecond, 3);
+        }
+        setFractionalSecond(realMilliseconds);
 
                 if (!isValid()) {
 
             throw new IllegalArgumentException(
                 DatatypeMessageFormatter.formatMessage(null,

@@ -579,10 +619,12 @@
                     + ", is not a valid representation of an XML Gregorian Calendar value."
                     );
                  */
 
                 }
+        
+        save();
     }
 
         /**
          * <p>Convert a <code>java.util.GregorianCalendar</code> to XML Schema 1.0
          * representation.</p>

@@ -659,10 +701,11 @@
                 cal.get(Calendar.MILLISECOND));
 
         // Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds.
         int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
         this.setTimezone(offsetInMinutes);
+        save();
     }
 
     // Factories
 
     /**

@@ -1162,11 +1205,11 @@
     public void setYear(BigInteger year) {
         if (year == null) {
             this.eon = null;
             this.year = DatatypeConstants.FIELD_UNDEFINED;
         } else {
-            BigInteger temp = year.remainder(BILLION);
+            BigInteger temp = year.remainder(BILLION_B);
             this.year = temp.intValue();
             setEon(year.subtract(temp));
         }
     }
 

@@ -1185,16 +1228,17 @@
      */
     public void setYear(int year) {
         if (year == DatatypeConstants.FIELD_UNDEFINED) {
             this.year = DatatypeConstants.FIELD_UNDEFINED;
             this.eon = null;
-        } else if (Math.abs(year) < BILLION.intValue()) {
+        } 
+        else if (Math.abs(year) < BILLION_I) {
             this.year = year;
             this.eon = null;
         } else {
             BigInteger theYear = BigInteger.valueOf((long) year);
-            BigInteger remainder = theYear.remainder(BILLION);
+            BigInteger remainder = theYear.remainder(BILLION_B);
             this.year = remainder.intValue();
             setEon(theYear.subtract(remainder));
         }
     }
 

@@ -1686,10 +1730,13 @@
     public boolean equals(Object obj) {
 
         if (obj == null || !(obj instanceof XMLGregorianCalendar)) {
             return false;
         }
+        if (obj == this) {
+            return true;
+        }
         return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL;
     }
 
     /**
      * <p>Returns a hash code consistent with the definition of the equals method.</p>

@@ -1948,56 +1995,41 @@
         // since setters do not allow for invalid values,
         // (except for exceptional case of year field of zero),
         // no need to check for anything except for constraints
         // between fields.
 
-        //check if days in month is valid. Can be dependent on leap year.
-        if (getMonth() == DatatypeConstants.FEBRUARY) {
-            // years could not be set
-            int maxDays = 29;
-
+        // check if days in month is valid. Can be dependent on leap year.
+        if (month != DatatypeConstants.FIELD_UNDEFINED && day != DatatypeConstants.FIELD_UNDEFINED) {
+            if (year != DatatypeConstants.FIELD_UNDEFINED) {
             if (eon == null) {
-                if(year!=DatatypeConstants.FIELD_UNDEFINED)
-                    maxDays = maximumDayInMonthFor(year,getMonth());
-            } else {
-                BigInteger years = getEonAndYear();
-                if (years != null) {
-                    maxDays = maximumDayInMonthFor(getEonAndYear(), DatatypeConstants.FEBRUARY);
+                    if (day > maximumDayInMonthFor(year, month)) {
+                        return false;
                 }
             }
-            if (getDay() > maxDays) {
+                else if (day > maximumDayInMonthFor(getEonAndYear(), month)) {
                 return false;
             }
         }
+            // Use 2000 as a default since it's a leap year.
+            else if (day > maximumDayInMonthFor(2000, month)) {
+                return false;
+            }
+        }
 
         // http://www.w3.org/2001/05/xmlschema-errata#e2-45
-        if (getHour() == 24) {
-            if(getMinute() != 0) {
+        if (hour == 24 && (minute != 0 || second != 0 || 
+                (fractionalSecond != null && fractionalSecond.compareTo(DECIMAL_ZERO) != 0))) {
                 return false;
-            } else if (getSecond() != 0) {
-                return false;
             }
-        }
 
         // XML Schema 1.0 specification defines year value of zero as
         // invalid. Allow this class to set year field to zero
         // since XML Schema 1.0 errata states that lexical zero will
         // be allowed in next version and treated as 1 B.C.E.
-        if (eon == null) {
-            // optimize check.
-            if (year == 0) {
+        if (eon == null && year == 0) {
                 return false;
             }
-        } else {
-            BigInteger yearField = getEonAndYear();
-            if (yearField != null) {
-                int result = compareField(yearField, BigInteger.ZERO);
-                if (result == DatatypeConstants.EQUAL) {
-                    return false;
-                }
-            }
-        }
         return true;
     }
 
     /**
      * <p>Add <code>duration</code> to this instance.<\p>

@@ -2211,11 +2243,11 @@
             intTemp = getMonth() + monthCarry;
             int endMonth = (intTemp - 1) % (13 - 1);
             int quotient;
             if (endMonth < 0) {
                 endMonth = (13 - 1) + endMonth + 1;
-                quotient = new BigDecimal(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue();
+                quotient = BigDecimal.valueOf(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue();
             } else {
                 quotient = (intTemp - 1) / (13 - 1);
                 endMonth += 1;
             }
             setMonth(endMonth);

@@ -2257,44 +2289,46 @@
     private static final BigInteger HUNDRED = BigInteger.valueOf(100);
     private static final BigInteger FOUR_HUNDRED = BigInteger.valueOf(400);
     private static final BigInteger SIXTY = BigInteger.valueOf(60);
     private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24);
     private static final BigInteger TWELVE = BigInteger.valueOf(12);
-    private static final BigDecimal DECIMAL_ZERO = new BigDecimal("0");
-    private static final BigDecimal DECIMAL_ONE = new BigDecimal("1");
-    private static final BigDecimal DECIMAL_SIXTY = new BigDecimal("60");
+    private static final BigDecimal DECIMAL_ZERO = BigDecimal.valueOf(0);
+    private static final BigDecimal DECIMAL_ONE = BigDecimal.valueOf(1);
+    private static final BigDecimal DECIMAL_SIXTY = BigDecimal.valueOf(60);
 
 
-    private static int daysInMonth[] = { 0,  // XML Schema months start at 1.
+    private static class DaysInMonth {
+        private static final int [] table = { 0,  // XML Schema months start at 1.
                                        31, 28, 31, 30, 31, 30,
                                        31, 31, 30, 31, 30, 31};
+    }
 
     private static int maximumDayInMonthFor(BigInteger year, int month) {
         if (month != DatatypeConstants.FEBRUARY) {
-            return daysInMonth[month];
+            return DaysInMonth.table[month];
         } else {
             if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) ||
                     (!year.mod(HUNDRED).equals(BigInteger.ZERO) &&
                             year.mod(FOUR).equals(BigInteger.ZERO))) {
                 // is a leap year.
                 return 29;
             } else {
-                return daysInMonth[month];
+                return DaysInMonth.table[month];
             }
         }
     }
 
     private static int maximumDayInMonthFor(int year, int month) {
         if (month != DatatypeConstants.FEBRUARY) {
-            return daysInMonth[month];
+            return DaysInMonth.table[month];
         } else {
             if (((year % 400) == 0) ||
                     (((year % 100) != 0) && ((year % 4) == 0))) {
                 // is a leap year.
                 return 29;
             } else {
-                return daysInMonth[DatatypeConstants.FEBRUARY];
+                return DaysInMonth.table[DatatypeConstants.FEBRUARY];
             }
         }
     }
 
     /**

@@ -2402,15 +2436,21 @@
         result = new GregorianCalendar(tz, locale);
         result.clear();
         result.setGregorianChange(PURE_GREGORIAN_CHANGE);
 
         // if year( and eon) are undefined, leave default Calendar values
-        BigInteger year = getEonAndYear();
-        if (year != null) {
-            result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
-            result.set(Calendar.YEAR, year.abs().intValue());
+        if (year != DatatypeConstants.FIELD_UNDEFINED) {
+            if (eon == null) {
+                result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
+                result.set(Calendar.YEAR, Math.abs(year));
         }
+            else {
+                BigInteger eonAndYear = getEonAndYear();
+                result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
+                result.set(Calendar.YEAR, eonAndYear.abs().intValue());
+            }
+        }
 
         // only set month if it is set
         if (month != DatatypeConstants.FIELD_UNDEFINED) {
             // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
             result.set(Calendar.MONTH, month - 1);

@@ -2541,30 +2581,45 @@
         result = new GregorianCalendar(tz, aLocale);
         result.clear();
         result.setGregorianChange(PURE_GREGORIAN_CHANGE);
 
         // if year( and eon) are undefined, leave default Calendar values
-        BigInteger year = getEonAndYear();
-        if (year != null) {
-            result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
-            result.set(Calendar.YEAR, year.abs().intValue());
+        if (year != DatatypeConstants.FIELD_UNDEFINED) {
+            if (eon == null) {
+                result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
+                result.set(Calendar.YEAR, Math.abs(year));
+            }
+            else {
+                final BigInteger eonAndYear = getEonAndYear();
+                result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
+                result.set(Calendar.YEAR, eonAndYear.abs().intValue());
+            }
         } else {
             // use default if set
-            BigInteger defaultYear = (defaults != null) ? defaults.getEonAndYear() : null;
-            if (defaultYear != null) {
-                result.set(Calendar.ERA, defaultYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
-                result.set(Calendar.YEAR, defaultYear.abs().intValue());
+            if (defaults != null) {
+                final int defaultYear = defaults.getYear();
+                if (defaultYear != DatatypeConstants.FIELD_UNDEFINED) {
+                    if (defaults.getEon() == null) {
+                        result.set(Calendar.ERA, defaultYear < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
+                        result.set(Calendar.YEAR, Math.abs(defaultYear));
             }
+                    else {
+                        final BigInteger defaultEonAndYear = defaults.getEonAndYear();
+                        result.set(Calendar.ERA, defaultEonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
+                        result.set(Calendar.YEAR, defaultEonAndYear.abs().intValue());
         }
+                }
+            }
+        }
 
         // only set month if it is set
         if (month != DatatypeConstants.FIELD_UNDEFINED) {
             // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
             result.set(Calendar.MONTH, month - 1);
         } else {
             // use default if set
-            int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
+            final int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
             if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) {
                 // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
                 result.set(Calendar.MONTH, defaultMonth - 1);
             }
         }

@@ -2572,11 +2627,11 @@
         // only set day if it is set
         if (day != DatatypeConstants.FIELD_UNDEFINED) {
             result.set(Calendar.DAY_OF_MONTH, day);
         } else {
             // use default if set
-            int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
+            final int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
             if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) {
                 result.set(Calendar.DAY_OF_MONTH, defaultDay);
             }
         }
 

@@ -2594,11 +2649,11 @@
         // only set minute if it is set
         if (minute != DatatypeConstants.FIELD_UNDEFINED) {
             result.set(Calendar.MINUTE, minute);
         } else {
             // use default if set
-            int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
+            final int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
             if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) {
                 result.set(Calendar.MINUTE, defaultMinute);
             }
         }
 

@@ -2605,11 +2660,11 @@
         // only set second if it is set
         if (second != DatatypeConstants.FIELD_UNDEFINED) {
             result.set(Calendar.SECOND, second);
         } else {
             // use default if set
-            int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
+            final int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
             if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) {
                 result.set(Calendar.SECOND, defaultSecond);
             }
         }
 

@@ -2616,11 +2671,11 @@
         // only set millisend if it is set
         if (fractionalSecond != null) {
             result.set(Calendar.MILLISECOND, getMillisecond());
         } else {
             // use default if set
-            BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
+            final BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
             if (defaultFractionalSecond != null) {
                 result.set(Calendar.MILLISECOND, defaults.getMillisecond());
             }
         }
 

@@ -2669,10 +2724,13 @@
             StringBuffer customTimezoneId = new StringBuffer(8);
             customTimezoneId.append("GMT");
             customTimezoneId.append(sign);
             customTimezoneId.append(hour);
             if (minutes != 0) {
+                if (minutes < 10) {
+                    customTimezoneId.append('0');
+                }
                 customTimezoneId.append(minutes);
             }
             result = TimeZone.getTimeZone(customTimezoneId.toString());
         }
         return result;

@@ -2716,11 +2774,11 @@
             fractionalSecond = null;
         } else {
             if(millisecond<0 || 999<millisecond)
                 if(millisecond!=DatatypeConstants.FIELD_UNDEFINED)
                     invalidFieldValue(MILLISECOND, millisecond);
-            fractionalSecond = new BigDecimal((long) millisecond).movePointLeft(3);
+            fractionalSecond = BigDecimal.valueOf(millisecond, 3);
         }
     }
 
     public void setFractionalSecond(BigDecimal fractional) {
         if (fractional != null) {

@@ -2768,11 +2826,11 @@
                 }
 
                 // seen meta character. we don't do error check against the format
                 switch (format.charAt(fidx++)) {
                     case 'Y' : // year
-                        parseAndSetYear(4);
+                        parseYear();
                         break;
 
                     case 'M' : // month
                         setMonth(parseInt(2, 2));
                         break;

@@ -2849,11 +2907,11 @@
             throws IllegalArgumentException {
 
             int n = 0;
             char ch;
             int vstart = vidx;
-            while (isDigit(ch=peek()) && (vidx - vstart) <= maxDigits) {
+            while (isDigit(ch=peek()) && (vidx - vstart) < maxDigits) {
                 vidx++;
                 n = n*10 + ch-'0';
             }
             if ((vidx - vstart) < minDigits) {
                 // we are expecting more digits

@@ -2861,44 +2919,36 @@
             }
 
             return n;
         }
 
-        private void parseAndSetYear(int minDigits)
+        private void parseYear()
                 throws IllegalArgumentException {
             int vstart = vidx;
-            int n = 0;
-            boolean neg = false;
+            int sign = 0;
 
             // skip leading negative, if it exists
             if (peek() == '-') {
                 vidx++;
-                neg = true;
+                sign = 1;
             }
-            while(true) {
-                char ch = peek();
-                if(!isDigit(ch))
-                    break;
+            while (isDigit(peek())) {
                 vidx++;
-                n = n*10 + ch-'0';
             }
-
-            if ((vidx - vstart) < minDigits) {
+            final int digits = vidx - vstart - sign;
+            if (digits < 4) {
                 // we are expecting more digits
                 throw new IllegalArgumentException(value); //,vidx);
             }
-
-            if(vidx-vstart<7) {
-                // definitely int only. I don't know the exact # of digits that can be in int,
-                // but as long as we can catch (0-9999) range, that should be enough.
-                if(neg)     n = -n;
-                year = n;
-                eon = null;
-            } else {
-                setYear(new BigInteger(value.substring(vstart, vidx)));
+            final String yearString = value.substring(vstart, vidx);
+            if (digits < 10) {
+                setYear(Integer.parseInt(yearString));
             }
+            else {
+                setYear(new BigInteger(yearString));
         }
+        }
 
         private BigDecimal parseBigDecimal()
                 throws IllegalArgumentException {
             int vstart = vidx;
 

@@ -2920,155 +2970,128 @@
 
     /**
      * Prints this object according to the format specification.
      *
      * <p>
-     * I wrote a custom format method for a particular format string to
-     * see if it improves the performance, but it didn't. So this interpreting
-     * approach isn't too bad.
-     *
-     * <p>
      * StringBuffer -> StringBuilder change had a very visible impact.
-     * It almost cut the execution time to half, but unfortunately we can't use it
-     * because we need to run on JDK 1.3
+     * It almost cut the execution time to half.
+     * Diff from Xerces:
+     * Xerces use StringBuffer due to the requirement to support
+     * JDKs older than JDK 1.5
      */
     private String format( String format ) {
-        char[] buf = new char[32];
-        int bufPtr = 0;
-
+        StringBuilder buf = new StringBuilder();
         int fidx=0,flen=format.length();
 
         while(fidx<flen) {
             char fch = format.charAt(fidx++);
             if(fch!='%') {// not a meta char
-                buf[bufPtr++] = fch;
+                buf.append(fch);
                 continue;
             }
 
             switch(format.charAt(fidx++)) {
             case 'Y':
-                if(eon==null) {
-                    // optimized path
-                    int y = getYear();
-                    if(y<0) {
-                        buf[bufPtr++] = '-';
-                        y = -y;
+                    if (eon == null) {
+                        int absYear = year;
+                        if (absYear < 0) {
+                            buf.append('-');
+                            absYear = -year;
                     }
-                    bufPtr = print4Number(buf,bufPtr,y);
-                } else {
-                    String s = getEonAndYear().toString();
-                    // reallocate the buffer now so that it has enough space
-                    char[] n = new char[buf.length+s.length()];
-                    System.arraycopy(buf,0,n,0,bufPtr);
-                    buf = n;
-                    for(int i=s.length();i<4;i++)
-                        buf[bufPtr++] = '0';
-                    s.getChars(0,s.length(),buf,bufPtr);
-                    bufPtr += s.length();
+                        printNumber(buf, absYear, 4);
                 }
+                    else {
+                        printNumber(buf, getEonAndYear(), 4);
+                    }
                 break;
             case 'M':
-                bufPtr = print2Number(buf,bufPtr,getMonth());
+                    printNumber(buf,getMonth(),2);
                 break;
             case 'D':
-                bufPtr = print2Number(buf,bufPtr,getDay());
+                    printNumber(buf,getDay(),2);
                 break;
             case 'h':
-                bufPtr = print2Number(buf,bufPtr,getHour());
+                    printNumber(buf,getHour(),2);
                 break;
             case 'm':
-                bufPtr = print2Number(buf,bufPtr,getMinute());
+                    printNumber(buf,getMinute(),2);
                 break;
             case 's':
-                bufPtr = print2Number(buf,bufPtr,getSecond());
+                    printNumber(buf,getSecond(),2);
                 if (getFractionalSecond() != null) {
-                    // Note: toPlainString() isn't available before Java 1.5
-                    String frac = getFractionalSecond().toString();
-
-                    int pos = frac.indexOf("E-");
-                    if (pos >= 0) {
-                        String zeros = frac.substring(pos+2);
-                        frac = frac.substring(0,pos);
-                        pos = frac.indexOf(".");
-                        if (pos >= 0) {
-                            frac = frac.substring(0,pos) + frac.substring(pos+1);
-                        }
-                        int count = Integer.parseInt(zeros);
-                        if (count < 40) {
-                            frac = "00000000000000000000000000000000000000000".substring(0,count-1) + frac;
-                        } else {
-                            // do it the hard way
-                            while (count > 1) {
-                                frac = "0" + frac;
-                                count--;
-                            }
-                        }
-                        frac = "0." + frac;
-                    }
-
-                    // reallocate the buffer now so that it has enough space
-                    char[] n = new char[buf.length+frac.length()];
-                    System.arraycopy(buf,0,n,0,bufPtr);
-                    buf = n;
+                        //Xerces uses a custom method toString instead of
+                        //toPlainString() since it needs to support JDKs older than 1.5
+                        String frac = getFractionalSecond().toPlainString();
                     //skip leading zero.
-                    frac.getChars(1, frac.length(), buf, bufPtr);
-                    bufPtr += frac.length()-1;
+                        buf.append(frac.substring(1, frac.length()));
                 }
                 break;
             case 'z':
                 int offset = getTimezone();
                 if (offset == 0) {
-                    buf[bufPtr++] = 'Z';
-                } else
-                if (offset != DatatypeConstants.FIELD_UNDEFINED) {
+                        buf.append('Z');
+                    } 
+                    else if (offset != DatatypeConstants.FIELD_UNDEFINED) {
                     if (offset < 0) {
-                        buf[bufPtr++] = '-';
+                            buf.append('-');
                         offset *= -1;
-                    } else {
-                        buf[bufPtr++] = '+';
                     }
-                    bufPtr = print2Number(buf, bufPtr, offset / 60);
-                    buf[bufPtr++] = ':';
-                    bufPtr = print2Number(buf, bufPtr, offset % 60);
+                        else {
+                            buf.append('+');
                 }
+                        printNumber(buf,offset/60,2);
+                        buf.append(':');
+                        printNumber(buf,offset%60,2);
+                    }
                 break;
             default:
                 throw new InternalError();  // impossible
             }
         }
 
-        return new String(buf,0,bufPtr);
+        return buf.toString();
     }
 
     /**
-     * Prints an int as two digits into the buffer.
+     * Prints an integer as a String. 
      *
+     * @param out
+     *      The formatted string will be appended into this buffer.
      * @param number
-     *      Number to be printed. Must be positive.
+     *      The integer to be printed. 
+     * @param nDigits
+     *      The field will be printed by using at least this
+     *      number of digits. For example, 5 will be printed as "0005"
+     *      if nDigits==4. 
      */
-    private int print2Number( char[] out, int bufptr, int number ) {
-        out[bufptr++] = (char) ('0'+(number/10));
-        out[bufptr++] = (char) ('0'+(number%10));
-        return bufptr;
+    private void printNumber( StringBuilder out, int number, int nDigits ) {
+        String s = String.valueOf(number);
+        for (int i = s.length(); i < nDigits; i++) {
+            out.append('0');
     }
+        out.append(s);
+    }
 
     /**
-     * Prints an int as four digits into the buffer.
+     * Prints an BigInteger as a String. 
      *
+     * @param out
+     *      The formatted string will be appended into this buffer.
      * @param number
-     *      Number to be printed. Must be positive.
+     *      The integer to be printed. 
+     * @param nDigits
+     *      The field will be printed by using at least this
+     *      number of digits. For example, 5 will be printed as "0005"
+     *      if nDigits==4. 
      */
-    private int print4Number( char[] out, int bufptr, int number ) {
-        out[bufptr+3] = (char) ('0'+(number%10));
-        number /= 10;
-        out[bufptr+2] = (char) ('0'+(number%10));
-        number /= 10;
-        out[bufptr+1] = (char) ('0'+(number%10));
-        number /= 10;
-        out[bufptr  ] = (char) ('0'+(number%10));
-        return bufptr+4;
+    private void printNumber( StringBuilder out, BigInteger number, int nDigits) {
+        String s = number.toString();
+        for (int i=s.length(); i < nDigits; i++) {
+            out.append('0');
     }
+        out.append(s);
+    }
 
     /**
      * Compute <code>value*signum</code> where value==null is treated as
      * value==0.
      * @return non-null {@link BigInteger}.

@@ -3083,8 +3106,28 @@
     /** <p><code>reset()</code> is designed to allow the reuse of existing
      * <code>XMLGregorianCalendar</code>s thus saving resources associated
      *  with the creation of new <code>XMLGregorianCalendar</code>s.</p>
      */
     public void reset() {
-        //PENDING : Implementation of reset method
+        eon = orig_eon;
+        year = orig_year;
+        month = orig_month;
+        day = orig_day;
+        hour = orig_hour;
+        minute = orig_minute;
+        second = orig_second;
+        fractionalSecond = orig_fracSeconds;
+        timezone = orig_timezone;
     }
+
+    /** Deserialize Calendar. */
+    private void readObject(ObjectInputStream ois)
+        throws ClassNotFoundException, IOException {
+
+        // perform default deseralization
+        ois.defaultReadObject();
+
+        // initialize orig_* fields
+        save();
+
+    } // readObject(ObjectInputStream)    
 }