JDK-8220477 : Channels.newWriter() does not close if underlying channel throws an IOException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 8,11,12,13
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2019-02-28
  • Updated: 2019-04-24
  • Resolved: 2019-04-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 13
13 b17Fixed
Description
ADDITIONAL SYSTEM INFORMATION :
java -version:
openjdk version "13-ea" 2019-09-17
OpenJDK Runtime Environment (build 13-ea+9)
OpenJDK 64-Bit Server VM (build 13-ea+9, mixed mode, sharing)

Windows 10 Home, Version 1803, Build 17134.590

A DESCRIPTION OF THE PROBLEM :
If the underlying WritableByteChannel errors when closing a sun.nio.cs.StreamEncoder (as returned by Channels.newWriter), then the channel is not closed.

This is somewhat similar to JDK-6266377, but is not dependent on using a BufferedWriter.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
 - Create a subclass of WritableByteChannel which errors when calling .write, and prints some debugging message when closing.
 - Use Channels.newWriter to wrap an instance of this channel.
 - Write to the writer, and then close it.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The channel would be closed the exception thrown from .write() is propagated.
ACTUAL -
The channel is not closed, and the error from .write() is thrown.

---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.StandardCharsets;

class Scratch
{
    public static void main( String[] args )
    {
        ErroringByteChannel channel = new ErroringByteChannel();
        try( Writer writer = Channels.newWriter( channel, StandardCharsets.UTF_8.newEncoder(), -1 ) )
        {
            writer.write( "Test" );
        }
        catch( IOException e )
        {
            e.printStackTrace();
        }
    }

    private static class ErroringByteChannel implements WritableByteChannel
    {
        private boolean open = true;

        @Override
        public int write( ByteBuffer src ) throws IOException
        {
            throw new IOException();
        }

        @Override
        public boolean isOpen()
        {
            return open;
        }

        @Override
        public void close()
        {
            open = false;
            System.out.println( "Closing" );
        }
    }
}

---------- END SOURCE ----------


Comments
To reproduce the issue, run the attached test case. The print statement in close() method is not called as expected. JDK 8u201 - Fail JDK 11.0.1 - Fail JDK 12-ea + 30 - Fail JDK 13-ea+10- Fail Output: java.io.IOException at JI9059570$ErroringByteChannel.write(JI9059570.java:29) at java.base/sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:230) at java.base/sun.nio.cs.StreamEncoder.implClose(StreamEncoder.java:337) at java.base/sun.nio.cs.StreamEncoder.close(StreamEncoder.java:161) at JI9059570.main(JI9059570.java:15)
12-03-2019