Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4209296

(cal) API: Calendar subclassing is broken since 1.2



    • Type: Bug
    • Status: Resolved
    • Priority: P4
    • Resolution: Won't Fix
    • Affects Version/s: 1.2.0, 1.4.0, 5.0
    • Fix Version/s: None
    • Component/s: core-libs
    • Subcomponent:
    • Introduced In Version:
    • CPU:
      generic, x86
    • OS:
      generic, windows_2000, windows_xp


      Name: bb33257 Date: 02/05/99

      There is a problem in Calendar in JDK 1.2. Subclasses that
      were written for JDK 1.1 don't work anymore. Consider a
      subclass that has to work with both 1.1.x and 1.2. It can't
      use the stamp array in my computeTime method. Instead, it
      has to rely on calling isSet().

      Consider the following calls:

              // Now find the # of days in the month
              c.roll(Calendar.DATE, false);
              daysInMonth = c.get(Calendar.DATE);

      When roll is called, it ends up calling set on the DATE
      field, which has the side effect of setting areFieldsSet and
      isTimeSet to false. It also sets isSet[DATE] to true and
      updates stamp[DATE].

      If c is a Gregorian calendar, then it works properly.
      Here's what happens:

      1. The roll method calls complete, which calls computeFields.

      2. After the fields values are set,
      GregorianCalendar.computeFields sets each element in the
      stamp array to INTERNALLY_SET.

      3. The get method immediately calls complete, which notices
      that isTimeSet is false and calls updateTime, which in turn
      calls computeTime.

      4. That method uses the stamp array to decide which fields
      it should use to compute the time. It doesn't look at the
      isSet array at all. It properly updates the time based on
      the relevant fields.

      5. Next, complete calls computeFields.

      6. Finally, get returns fields[DATE].

      In contrast, if c is a JDK 1.1-compatible subclass, this is
      what happens:

      1. same thing: roll ends up calling computeFields.

      2. Nothing (!): computeFields method doesn't have access
      to the stamp array.

      3. same thing: get ends up calling computeTime.

      4. computeTime method calls isSet() to decide which
      combination of fields to use, much like the Gregorian
      calendar used to do.

      5. In 1.2, isSet() returns (stamp[field] != UNSET). This is
      almost always false, because computeFields wasn't able to
      update the stamp array.

      6. The calendar thinks there aren't enough fields set to
      compute the time, so it throws an exception. Boom.

      To restate the requirements for 1.2 and later, we want the

      1. Subclasses under 1.1 should work under 1.2.

      This means isSet() must work, in particular, it must read
      the isSet[] array, since subclasses may modify that array

      2. Subclasses under 1.2 should work.

      If a subclass sets up the fields, it must be able to make
      isSet() do the right thing.

      3. GregorianCalendar and other subclasses within java.text
      must work.

      For this to be true, isSet() has to read the time stamp.

      So I propose:

      1. Make isSet() read the isSet[] array.

      2. Make Calendar.isSet() non-final, and for GregorianCalendar,
      override it to read the time stamp.

      (Review ID: 53793)



          Issue Links



              naoto Naoto Sato
              bcbeck Brian Beck (Inactive)
              0 Vote for this issue
              2 Start watching this issue