What is a backward compatibility?

– Deepthi Halbhavi-

Backward or downward compatibility in Java API is a property of an API that allows older API usages to function without breaking their existing implementation when an API is modified.

An API Interface

Let’s look at the simple API example below.

Example:

The API consists of only one interface Foo with one method bar(), so the user that implements this API will need to implement the interface Foo.

The following class FooImpl implements Foo and implements bar() method.

Simple implementation for a simple API. But the things get trickier when a simple API is modified to accommodate new requirements.

Let’s check that out.

Modifying an interface

Now, let’s modify the Foo interface and add a new method fooBar() and see what are its implications on the implementation which is FooImpl!

A new method is added in the Foo interface and if the implementation is using the same API then it will fail in two ways.

  1. The existing implementation will not
  2. The existing implementation will not be able to use the new API and may not be able to use new features. Hence the implementation is stuck with the older version because of no backward

Approaches to overcome the above issues

Implement new API

Just implement the new API.

As we saw above, the API is modified so, FooImpl will just implement the newly added method fooBar().

Pros:

  • Keep up-to-date with the API

Cons:

  • Enforces implementation to be added for new the API which may not be required at the time of upgrade
  • Not all the API users would want to implement the new API
  • It is not backward compatible

Interface versioning

In this approach, any new modifications to an interface are put in a new interface. Which means create a new interface that extends the existing one and suffix it with, say _V1

Let’s consider the previous example and apply this approach.

This is the original interface:

A versioned interface extends the previous one

Now the implementation has a choice of how to implement when to implement. For ex:

  1. FooImpl implements new interface which is Foo_V1
  2. FooImpl implements Foo and FooImpl_V2 extends FooImpl and implements Foo_V1

 

  1. Do not implement the new interface Foo_V1 at all if there is no requirement to implement it yet

Pros:

  • Both of the aforementioned issues are resolved
  • Implementations have choice which version to use
  • Implementations have choice whether they want to implement new version at all
  • Fully backward compatible
  • Extend the previous implementation for the new API version

Cons:

  • Increase in the number of interfaces
  • If FooImpl_V1 is versioned and extends previous implementation then it cannot extend any other class even if you wanted it
  • May not keep up-to-date with the new
  • Need to be aware of the new API changes because it won’t complain in a form of compilation errors, hence leading to missing API

Using default method (Java 8 and above)

Java 8 introduce default methods in interfaces to provide backward compatibility. default methods allow interfaces to have implementation without affecting classes that implement such interfaces.

So, let’s use this in our example API to make it backward compatible

The default void fooBar() method provide default implementation and it won’t affect the FooImpl

class that implements Foo.

Pros:

  • Both of the aforementioned issues are resolved
  • Fully backward compatible
  • Keeps up-to-date with the new API with default implementation
  • Implementations have choice whether they want to implement new version at all
  • The implementation can extend another class

Cons:

  • Need to be aware of the new API changes because it won’t complain in a form of compilation errors, hence leading to missing API features