Question

I have a method which accepts an InputStream (of binary data) and serializes it to XML. In order to do so, it wraps the stream with a base64 encoder and a Reader to convert it to character data. However, since the InputStream is passed in as a parameter, I would consider it a harmful side effect to close the stream, and the contract for Reader.close() says it would do just that. If I don't close the reader, the compiler warns me that I have a

Resource leak: reader is never closed

So, I can add a @SuppressWarnings( "resource" ) to the reader declaration, but is that the right thing to do? Am I missing something?

Here is the actual code:

/**
 * Writes base64 encoded text read from the binary stream.
 * 
 * @param binaryStream
 *            The binary stream to write from
 * @return <code>this</code> XmlWriter (for chaining)
 * @throws IOException
 */
public XmlWriter binary( InputStream binaryStream ) throws IOException {
    Reader reader = new InputStreamReader( 
            new Base64InputStream( binaryStream, true, base64LineLength, base64LineSeparator.getBytes( charset ) ) );
    int bufferSize = 2048;
    int charsRead;
    char[] buffer = new char[bufferSize];
    while ( (charsRead = reader.read( buffer, 0, bufferSize )) >= 0 ) {
        writer.write( buffer, 0, charsRead );
    }

    return this;
}
Was it helpful?

Solution

If you are a happy Java 7 user, try this:

try(InputStream binaryStream = /* ... */) {
    xmlWriter.binary(binaryStream);
}

and stream is closed for you. If you can't use Java 7, I agree that it's not the responsibility of binary() method to close() the stream. Just ignore the warning and don't let tools drive your design. It's fine.

As a last resort you can write a lightweight Reader wrapper ignoring close(), but I don't advice it as it makes following the program flow harder.

Also let Apache Commons IO help you with IOUtils.copy():

public XmlWriter binary( InputStream binaryStream ) throws IOException {
    Reader reader = new InputStreamReader( 
            new Base64InputStream( binaryStream, true, base64LineLength, base64LineSeparator.getBytes( charset ) ) );
    IOUtils.copy(reader, writer);
    return this;
}

OTHER TIPS

This is a perhaps a "feature" in the way Base64InputStream work that even though you specify the length to read, it will close the underlying stream if you close it when clearly you intended not to read the whole stream.

You could wrap the binaryStream in an InputStream which ignores the close, or you could suppress the warning as you have.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top