JDK-4209296 : (cal) API: Calendar subclassing is broken since 1.2
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 1.2.0,1.4.0,5.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: generic,windows_2000,windows_xp
  • CPU: generic,x86
  • Submitted: 1999-02-05
  • Updated: 2017-07-06
  • Resolved: 2017-07-06
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Description
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
following:

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
directly.

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)

======================================================================

Comments
Will not fix this as users are encouraged to use java.time functions instead of java.util.Calendar.
06-07-2017

Last updated is 1 year ago. Is this issue still available for JDK 9?
04-12-2014

EVALUATION After some cleanup in Tiger and Mustang, stamp[] is no longer shared by Calendar and GregorianCalendar. Added the some (package-private) methods to Calendar so that Calendar subclasses don't need to handle stamp[]. But it needs further work to make those methods protected.
11-11-2005

WORK AROUND Name: bb33257 Date: 02/05/99 None! Classes outside the JDK cannot change the stamp[] array, and the stamp[] array determines isSet(). ======================================================================
06-08-2004

EVALUATION Looks like the very first thing we need is a very clear specification (in javadoc form) how all this was and is supposed to work. If we have to choose between supporting 1.1 subclasses and 1.2 subclasses, the former win. Also, Calendar and GregorianCalendar should not share implementation - GregorianCalendar should be implemented as just another subclass using the public API of Calendar. Accessing internal data of a superclass is a no-no. norbert.lindenberg@Eng 1999-02-08 Reclassifying as an RFE because of the need to change Calendar.isSet() to be non-final in order to make this fix. If approved, this is an easy fix. alan.liu@eng 1999-03-19 We need to solve the dependency on stamp[] in Calendar, which may involve API changes. This should be deferred to the next upgrade release. masayoshi.okutsu@Eng 1999-06-11 My proposal is to: - Make set(), clear() and isSet() non final - Move stamp[] from Calendar to GregorianCalendar as a private variable masayoshi.okutsu@Eng 1999-06-20 We couldn't get any response on the fix proposal above from the submitter. Closing this one as "will not fix." ###@###.### 2001-12-06 Reopened for Tiger calendar cleanup. ###@###.### 2002-06-26
06-12-2001