Nathan, thanks a lot for reporting this. Sorry no one has replied to you
earlier,
but your bug report was actually entered into the JBS (JDK Bug System):
https://bugs.openjdk.java.net/browse/JDK-8054565
So don't worry, it won't get lost.
Now about the issue itself. It's indeed a bug. Though methods should be written
in
an atomic fashion [1] (where possible and where it makes sense), you are right
--
java.io.Closeable#close is certainly not one of these methods.
There is nothing you can do if 'close' fails. This method has a terminal
semantics.
Implementations cannot rely on some external retry strategy.
java.io.Closeable#close
should be called at most once in a lifetime of a Closeable object.
I skimmed through the JDK sources and found some more examples of this
behaviour.
They should be fixed as well. As for this particular issue, I see two options:
1. We just fix it and that's it
2. You sign OCA [2], provide a test, prepare a change review
and if everything is fine we push it with comment
'Contributed-by: [email protected]' (or whatever email
you choose)
---------------------------------------------------------------------------------
[1] Effective Java, Second Edition, Item 64: Strive for failure atomicity
[2] http://openjdk.java.net/contribute/
-Pavel
> On 2 Dec 2014, at 23:36, Nathan Clement <[email protected]> wrote:
>
> 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
>