Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#FFCCCC
class CalendarSubclass extends Calendar {
  @Override public boolean after(Object when) {
    // correctly calls Calendar.compareTo()
    if (when instanceof Calendar && 
        super.compareTo((Calendar) when) == 0) {
      return true;
    }
    return super.after(when);
  }

  @Override public int compareTo(Calendar anotherCalendar) {
    return compareDays(this.getFirstDayOfWeek(),
                       anotherCalendar.getFirstDayOfWeek());
  }

  private int compareDays(int currentFirstDayOfWeek,
                          int anotherFirstDayOfWeek) {
    return (currentFirstDayOfWeek > anotherFirstDayOfWeek) ? 1
           : (currentFirstDayOfWeek == anotherFirstDayOfWeek) ? 0 : -1;
  }

  public static void main(String[] args) {
    CalendarSubclass cs1 = new CalendarSubclass();
    cs1.setTime(new Date());
    // Date of last Sunday (before now)
    cs1.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
    // Wed Dec 31 19:00:00 EST 1969
    CalendarSubclass cs2 = new CalendarSubclass();
    // expected to print true
    System.out.println(cs1.after(cs2));
  }

  // Implementation of other Calendar abstract methods
}

Such errors generally occur because the developer made assumptions about the implementation-specific details of the superclass. Even when these assumptions are initially correct, implementation details of the superclass may change without warning.

Wiki Markup
The {{java.util.Calendar}} class provides a {{compareTo()}} method and an {{after()}} method. The {{after()}} method is documented in the _Java API Reference_ \[[API 2006|AA. Bibliography#API 06]\] as follows:

...

The developer of the subclass was unaware of the implementation details of Calendar.after() and incorrectly assumed that the superclass's after() method would invoke only its own the superclass's methods without invoking overriding methods from the subclass. Rule MET05-J. Ensure that constructors do not call overridable methods describes similar programming errorsprogramming errors.

Such errors generally occur because the developer made assumptions about the implementation-specific details of the superclass. Even when these assumptions are initially correct, implementation details of the superclass may change without warning.

Compliant Solution (Calendar)

Wiki Markup
This compliant solution uses a design pattern called composition and forwarding (sometimes also called delegation) \[[Lieberman 1986|AA. Bibliography#Lieberman 86]\], \[[Gamma 1995|AA. Bibliography#Gamma 95], p. 20\]. The compliant solution introduces a new _forwarder_ class that contains a {{private}} member field of the {{Calendar}} type; this is _composition_ rather than inheritance. In this example, the field refers to {{CalendarImplementation}}, a concrete instantiable implementation of the {{abstract}} {{Calendar}} class. The compliant solution also introduces a wrapper class called {{CompositeCalendar}} that provides the same overridden methods found in the {{CalendarSubclass}} from the preceding noncompliant code example.

...

The introduction of the entrySet() method in the java.util.Hashtable superclass in JDK 1.2 left the java.security.Provider subclass class vulnerable to a security attack. The Provider class extends java.util.Properties, which in turn extends Hashtable. The Provider class maps a cryptographic algorithm name (for example "RSA") to a class that provides its implementation.

The Provider class inherits the put() and remove() methods from Hashtable and adds security manager checks to each. These checks ensure that malicious code cannot add or remove the mappings. When entrySet() was introduced, it became possible for untrusted code to remove the mappings from the Hashtable because Provider failed to override this method to provide the necessary security manager check [SCG 2009]. This problem is commonly known as a the fragile class hierarchy in other object-oriented languages, such as C++ problem.

Related Guidelines

Secure Coding Guidelines for the Java Programming Language, Version 3.0

Guideline 1-3. Understand how a superclass can affect subclass behavior

...

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="05578c42fa5f29f0-0ddcd7e3-4aaf4106-bae48c04-68efb12f84a979fef7829ea4"><ac:plain-text-body><![CDATA[

[[API 2006

AA. Bibliography#API 06]]

[Class Calendar

http://download.oracle.com/javase/6/docs/api/java/util/Calendar.html]

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="fbff46ed74d5682d-5aa9b629-44754834-865bb673-cc85d12a4dc8188b578af60a"><ac:plain-text-body><![CDATA[

[[Bloch 2008

AA. Bibliography#Bloch 08]]

Item 16. Favor composition over inheritance

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="2325664210fd9875-b235f74a-4f624e8a-aba98dc2-a955a0fe6de9783e8eeda6ff"><ac:plain-text-body><![CDATA[

[[Gamma 1995

AA. Bibliography#Gamma 95]]

Design Patterns, Elements of Reusable Object-Oriented Software

]]></ac:plain-text-body></ac:structured-macro>

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="810fb6fd9aa255e5-347103d9-45854f6e-a300a719-dd27040c7a835631c7b9263e"><ac:plain-text-body><![CDATA[

[[Lieberman 1986

AA. Bibliography#Lieberman 86]]

Using prototypical objects to implement shared behavior in object-oriented systems

]]></ac:plain-text-body></ac:structured-macro>

...