Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: default method

Interfaces are used to group together all the methods that a class promises to publicly expose. The implementing classes are obliged to provide concrete implementations for all of these methods. Interfaces are a necessary ingredient of the most public API and APIs; once released, it flaws can be very hard to remediate any flaws fix without breaking any code that implements the older version. By far, the interface The repercussions include the following:

  • Interface changes resulting from security fixes can severely impair the

...

  • contracts of the implementing classes. For example, a fix introduced in a later version may be accompanied by modifications to an unrelated interface that must now be implemented by the client. The client may be prevented from implementing the fix because the new interface may impose additional implementation burden on it.
  • Implementers can provide default or skeletal implementations of interface methods for their clients to extend; however, such code can adversely affect the behavior of the subclasses. Conversely, when such default implementations are absent, the subclasses must provide dummy implementations. Such implementations  foster an environment where comments such as "ignore this code, does nothing" occur incessantly. Such code may never even get tested.
  • If there is a security flaw in a public API (see, for example, the discussion of ThreadGroup methods in THI01-J. Do not invoke ThreadGroup methods), it will persist throughout the lifetime of the API, affecting the security of any application or library that uses it. Even after the security flaw is mitigated, applications and libraries may continue using the insecure version until they are also updated.

Noncompliant Code Example

In this noncompliant code example, an interface User was is frozen with two methods: authenticate() and subscribe(). No Some time later, the providers released release a free service that did does not rely on authentication. The addition of the freeService() method, unfortunately, broke all the client code that implemented the interface.

Code Block
bgColor#ffcccc

public interface User {
  boolean authenticate(String username, char[] password);
  void subscribe(int noOfDays);
  void freeService(); // introducedIntroduced after the class is publicly released
}

Compliant Solution

A better design strategy would have been to anticipate the future evolution of the service. The core functionality should have been implemented in the User interface and in this case, only the premium service may be required to extend from it. To avail of the new free service, an existing class could then choose to simply implement the new interface FreeUser or just completely ignore it.

Code Block
bgColor#ccccff

public interface User {
  boolean authenticate(String username, char[] password);
}

public interface PremiumUser extends User {
  void subscribe(int noOfDays);
}

public interface FreeUser {
  void freeService();
}

Compliant Solution

The addition of the freeService() method, unfortunately, breaks all the client code that implements the interface. Moreover, the implementers who wish to use only freeService() have to face the onus of also providing the other two methods, which pollute the API, for reasons discussed earlier.

Noncompliant Code Example

An alternative idea An alternate recommendation is to prefer abstract classes for dealing with constant evolution, but this that comes at the cost of the loss in flexibility that interfaces offer . A preferable (a class may implement multiple interfaces but extend only one class). One notable pattern is for the provider to distribute an abstract skeletal class that implements the evolving interface. The skeletal class can selectively implement a few methods and force the extending classes to provide concrete implementations of the others. If a new method is added to the interface, the skeletal class can provide a non-abstract nonabstract default implementation that the extending class can optionally override. Thus, the new method need not be explicitly implemented by the This noncompliant code example shows such a skeletal class.

Code Block
bgColor#ccccff#ffcccc

public interface User {
  boolean authenticate(String username, char[] password);
  void subscribe(int noOfDays);
  void freeService(); // introducedIntroduced after the classAPI is publicly released
}

abstract class SkeletalUser implements User {
  public abstract boolean authenticate(String username, char[] password);
  public abstract void subscribe(int noOfDays);
  public void freeService() { 
    //* addedAdded later, provide implementation and re-release class*/ 
  }
}

class Client extends SkeletalUser {
  // implementsImplements authenticate() and subscribe(), not freeService()
}

Risk Assessment

Failing to publish stable, flaw-free interfaces can break the contracts of the implementing classes.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

MSC09-J

low

probable

high

P2

L3

References

Wiki Markup
\[[Bloch 08|AA. Java References#Bloch 08]\] Item 18: "Prefer interfaces to abstract classes"

Although useful, this pattern may be insecure because a provider who is unaware of the extending class's code may choose an implementation that introduces security weaknesses in the client API.

Compliant Solution (Modularize)

A better design strategy is to anticipate the future evolution of the service. The core functionality should be implemented in the User interface; in this case, only the premium service may be required to extend from it. To make use of the new free service, an existing class may then choose to implement the new interface FreeUser, or it may just completely ignore it.

Code Block
bgColor#ccccff
public interface User {
  boolean authenticate(String username, char[] password);
}

public interface PremiumUser extends User {
  void subscribe(int noOfDays);
}

public interface FreeUser {
  void freeService();
}

Compliant Solution (Make New Method Unusable)

Another compliant solution is to throw an exception from within the new freeService() method defined in the implementing subclass.

Code Block
bgColor#ccccff
class Client implements User {
  public void freeService() {
    throw new AbstractMethodError();
  } 
}

Compliant Solution (Delegate Implementation to Subclasses)

Although allowable, a less flexible compliant solution is to delegate the implementation of the method to subclasses of the client's core interface-implementing class.

Code Block
bgColor#ccccff
abstract class Client implements User  {
  public abstract void freeService(); 
  // Delegate implementation of new method to subclasses
  // Other concrete implementations
}

Compliant Solution (Java 8 Default Method)

Java versions 8 and newer allow an interface to provide a default method, which allows for extending interfaces without forcing the modification of preexisting classes which implement the interface.  Classes that implement this interface can ignore freeService() in which case the default implementation is used, or they can reimplement freeService() themselves, or they can declare it to be abstract, re-establishing the requirement for subclasses to to provide an implementation.

Code Block
bgColor#ccccff
public interface User {
  boolean authenticate(String username, char[] password);
  void subscribe(int noOfDays);
  default void freeService() {   // Introduced after the class is publicly released
    // ...
  }
}

Applicability

Failing to publish stable, flaw-free interfaces can break the contracts of the implementing classes, pollute the client API, and possibly introduce security weaknesses in the implementing classes.

Bibliography

[Bloch 2008]Item 18, "Prefer Interfaces to Abstract Classes"


...

Image Added Image Added Image AddedMSC05-J. Make sensitive classes noncloneable      49. Miscellaneous (MSC)      MSC30-J. Generate truly random numbers