The Adapter Pattern

I was recently working on a project where I wanted to read a file and send it directly onto a socket. I kind of assumed that Java would make this easy. And it does: InputStream.transferTo.

My code could therefore look like this:

InputStream inputStream = getInputStreamFromSomewhere();
OutputStream outputStream = getOutputStreamFromSomewhere();
inputStream.transferTo(outputStream);

Nice, simple and clean. Perfect! But, sadly, this is a Java 9 feature, and I was working on a project which (due to various incompatibility issues) could not use Java 9. So I was left with having to do this manually, which looked like this:

InputStream inputStream = getInputStreamFromSomewhere();
OutputStream outputStream = getOutputStreamFromSomewhere();
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer) != -1) {
outputStream.write(buffer, 0, length);
}

The difference here is stark.

The Java 9 code is very clear. It declares: take the input stream and transfer it to the output stream.

The Java 8 code describes the process of transferring the data from the input to the output stream. It therefore requires the reader to follow a series of steps in order to understand what is going on and then (in their head) give that process a name:

  1. Create a buffer (a 1kb byte array)
  2. Read from the input stream into the buffer
  3. Write the entire buffer to the output stream
  4. Repeat step 2 until all data has been read from the input stream

The Java 8 code could easily be improved by extracting this process into a method:

InputStream inputStream = getInputStreamFromSomewhere();
OutputStream outputStream = getOutputStreamFromSomewhere();
transferInputToOutput(inputStream, outputStream);
...
public void transferInputToOutput(
InputStream in, OutputStream out) {
  byte[] buffer = new byte[1024];
int length;
  while ((length = in.read(buffer) != -1) {
out.write(buffer, 0, length);
}
}

The limitation here is that this code needs to live somewhere. Should it be in a particular class that uses the transfer process? But what if this transfer were to be used in many different, unrelated places? It is, after all, a fairly generic process. So it could be a static method in a helper class: StreamHelper.transferInputToOutput perhaps?

But, given I knew that Java 9 has a baked-in solution to this problem, and this was implemented as an instance method on the InputStream class, it seemed to make most sense to mirror this interface.

However, as InputStream is a Java core class, I could not modify it directly even if I had wanted to. A better solution was to adapt the InputStream class by adding the transferTo functionality at runtime. This seemed a perfect opportunity for an Adapter.

Here’s my implementation:

Now, my code can look like this:

InputStream inputStream = getInputStreamFromSomewhere();
InputStreamAdapter adaptedInputStream = new InputStreamAdapter(
inputStream)
OutputStream outputStream = getOutputStreamFromSomewhere();
adaptedInputStream.transferTo(outputStream);

Which gets us most of the way to code as clean as the Java 9 example!