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
                                          

Reply via email to