How to implement a custom FilterReader?

I’m trying to implement a custom FilterReader class. The class is supposed to transform what it reads (never mind how). The problem I’m having is that the string after transformation is longer than the original one read into the char buffer, so I get an ArrayIndexOutOfBoundsException when I try to cram the new string into the buffer.

Here’s the read() method of my custom FilterReader class:

@Override
public int read(char[] cbuf, int off, int len) throws IOException {
    int result = in.read(cbuf, off, len);

    if( result != -1 ){
        String str = new String(cbuf, off, len);
        str = someStringTranformationMethod(str);

        //cbuf = new char[str.length()];

        str.getChars(0, str.length(), cbuf, 0);

        result = str.length();
    }

    return result;
}

I thought I could solve it by reallocating a new char buffer for cbuf, which is what I tried to at the commented line. However, this doesn’t seem to work at all, because then my output from the reader is the original (untransformed) string.

I have a feeling I’m going about things completely backwards here, but it’s not easy to find any good examples of this stuff online. All the custom FilterReaders I have found have just done some basic upper/lowercasing of the characters, where the length of the new string is the same as the original one.

So how would I implement this with a string transformation function that results in a longer string than the original one?

Answer

You’ll need to make your implementation stateful and keep track of the “leftover” characters:

private String str = "";
private int pos = 0;

public int read(char[] cbuf, int off, int len) throws IOException {
  if (pos == str.length()) {
    // No leftovers from a previous call available, need to actully read more
    int result = in.read(cbuf, off, len);
    if( result <= 0 ){
      return -1;
    }
    str = new String(cbuf, off, result);
    str = someStringTranformationMethod(str);
    pos = 0;
  }

  // Return as much as we have available, but not more than len
  int available = Math.min(str.length() - pos, len);     
  str.getChars(pos, pos + available, cbuf, off);
  pos += available;
  return available;
}

Note that read() only needs to read only (at least) one character if the end of the stream has not been reached. This implementation takes advantage of this.

Leave a Reply

Your email address will not be published. Required fields are marked *