Java 8 FilterOutputStream.close() bug

Nathan Clement nathan.a.clement at hotmail.com
Tue Dec 2 23:36:03 UTC 2014


Hi,

I have encountered a bug in FilterOutputStream under Java 8.  The bug is that calling close() on the same stream twice can now result in an exception, whereas under Java 7 it did not.  The reason is that FilterOutputStream.close() calls flush() before calling close() on the underlying stream.  Calling close() twice on the FilterOutputStream will thus result in flush() being called twice.  Some streams (such as OracleBlobOutputStream) will throw an exception if flush() is called after the stream is closed.  In Java 7 any exceptions when calling flush() were ignored, but in Java 8 these exceptions are passed on to the caller.

This bug appears to have been introduced in "7015589: (spec) BufferedWriter.close leaves stream open if close of underlying Writer fails".  The FilterOutputStream.close() method now does not obey the contract of AutoClosable.close(): "If the stream is already closed then invoking this method has no effect."

Some sample code that illustrates the problem:

try( InputStream bis = new BufferedInputStream( inputStream );
     OutputStream outStream = payloadData.setBinaryStream( 0 );
     BufferedOutputStream bos = new BufferedOutputStream( outStream );
     DeflaterOutputStream deflaterStream = new DeflaterOutputStream(
         bos, new Deflater( 3 ) ) )
{
    fileSize = IOUtil.copy( bis, deflaterStream );
}
The try-with-resources mechanism will call close on the DeflaterOutputStream, which will in turn call close on the BufferedOutputStream, which will call flush() then close() on the blob output stream.  The try-with-resources mechanism will then call close on the BufferedOutputStream which again calls flush() on the blob output stream, resulting in an exception.

My proposed fix is to change FilterOutputStream.close() as follows:

    @Override
    @SuppressWarnings("try")
    public void close() throws IOException {
        if (!closed) {
            closed = true;
            try (OutputStream ostream = out) {
                flush();
            }
        }
    }

    private boolean closed = false;

This will prevent flush() being called on an already closed stream.

I have reported this issue via the Oracle bug tracker and got Review ID JI-9014085, however I never received any follow up from Oracle.  I have also discussed the issue on Stack Overflow: http://stackoverflow.com/questions/25175882/java-8-filteroutputstream-exception.  Do people agree that this is a bug?  If so, what is the process for fixing it?

Thanks,

Nathan Clement
 		 	   		  


More information about the core-libs-dev mailing list