JDK-5005419 : Repeated close() of Writers with nio charsets fails in 1.4.2 and tiger
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio.charsets
  • Affected Version: 1.4.2_03
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-03-01
  • Updated: 2010-02-17
  • Resolved: 2005-05-28
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.
Other
1.4.2_09 b02Fixed
Related Reports
Relates :  
Description
There is an incompatible behavior between 1.3.1_XX and 1.4.2_0X.


The attached test program works well in 1.3.1_0X(1.4.1_0X also),
but not in 1.4.2_0X(1.5.betab38).

REPRODUCE :
 (1) Compile test.java 
 (2) Launch "java test windows-31j" in 1.3.1_11
 
     You will see only the message, "2nd close"

K:\illegal-excp>java test windows-31j
2nd close


 (3) Launch "java test windows-31j" in 1.4.2_03

     You will see the stack trace as follows.

K:\illegal-excp>java test windows-31j     
2nd close
catch in main
java.lang.IllegalStateException: Current state = FLUSHED, new state = CODING_END


        at java.nio.charset.CharsetEncoder.throwIllegalStateException(CharsetEnc
oder.java:933)
        at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:529)
        at sun.nio.cs.StreamEncoder$CharsetSE.flushLeftoverChar(StreamEncoder.ja
va:358)
        at sun.nio.cs.StreamEncoder$CharsetSE.implClose(StreamEncoder.java:414)
        at sun.nio.cs.StreamEncoder.close(StreamEncoder.java:160)
        at java.io.OutputStreamWriter.close(OutputStreamWriter.java:222)
        at java.io.PrintWriter.close(PrintWriter.java:137)
        at test.main(test.java:10)


The java.lang.IllegalStateException occurs in 1.4.2( and Tiger b38 ),
not in 1.3.1(1.4.0).


INVESTIGATION:
  
===== Test Program ( test.java ) =========
import java.io.*;
class test {
    public static void main( String arg[] ) {
	try {
	    OutputStreamWriter osw = 
		new OutputStreamWriter( new MyOutputStream("file"), arg[0] );
	    PrintWriter pw = new PrintWriter( osw );
	    pw.close();                         // 1st close 
	    System.out.println("2nd close");
	    pw.close();                         // 2nd close
	}
	catch( Exception e ) {
	    System.out.println("catch in main");
	    e.printStackTrace();
	}

    }
}

class MyOutputStream extends FileOutputStream {
    MyOutputStream( String s ) throws FileNotFoundException {
	super(s);
    }
    public void close() throws IOException {
	throw new IOException("Dummy Exception");
    }
}
==========================================

The above program is implemented as an exception appears on PrintWriter close. 
 (Please don't consider the sample code has problem.)
Please consider the above behavior of MyOutputStream simulates "some exception"
in the 3rd line of followings.
     - OutputStreamWriter object is created with char. encoding
       which is supported by nio .
     - Printwriter object is created based on OutputStreamWriter object.
     - Some exception occurs in close() for PrintWriter (pw.close() in "1st close" line)
       and close() is launched again.(pw.close() in "2nd close" line.)

Indeed, the API specifications in java.nio.charset.CharsetEncoder#encode mentions
the IllegalStateException in "Throw" section.

The users can be only aware of the OutputStreamWriter and  PrintWriter. 
However, the API docs of those classes does not mention IllegalStateException.
As a result, Java users don't write the code which can catch IllegalStateException
and will be confused because of an unexpected exception.

It means that users can not port the programs written in 1.3.1 to environment
based on 1.4.2.


PROBLEM: 

-  losing portability from 1.3.1(1.4.0) to 1.4.2 (and Tiger)

===========================================================================

Comments
EVALUATION This bug looks essentially like a duplicate of 5005426 with similarly supplied test case and suggested fix. 5005426 has been evaluated and fix is in progress. What is probably required here for this bug is a statement regarding whether the behaviour described and observed with the supplied test case is in violation of the PrintWriter specification or not. Such a statement ought to provided in due course. ###@###.### 2004-04-27 I agree that this is likely a duplicate of 5005426. There may be a further bug that repeated close() should always be a no-op, regardless of the underlying stream. ###@###.### 2004-08-31
31-08-2004

SUGGESTED FIX The followings are sent by the licensee. Please evaluate. *** org/OutputStreamWriter.java 2 27 16:38:56 2004 --- OutputStreamWriter.java 3 1 10:08:58 2004 *************** *** 9,14 **** --- 9,18 ---- import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; + import java.nio.charset.CoderMalfunctionError; + import java.nio.charset.CharacterCodingException; + import java.nio.charset.MalformedInputException; + import java.nio.charset.UnmappableCharacterException; import sun.nio.cs.StreamEncoder; *************** *** 166,174 **** --- 170,193 ---- * be invoked by PrintStream. */ void flushBuffer() throws IOException { + try { se.flushBuffer(); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } + /** * Write a single character. * *************** *** 175,182 **** --- 194,215 ---- * @exception IOException If an I/O error occurs */ public void write(int c) throws IOException { + try { se.write(c); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Write a portion of an array of characters. *************** *** 188,195 **** --- 221,242 ---- * @exception IOException If an I/O error occurs */ public void write(char cbuf[], int off, int len) throws IOException { + try { se.write(cbuf, off, len); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Write a portion of a string. *************** *** 201,208 **** --- 248,269 ---- * @exception IOException If an I/O error occurs */ public void write(String str, int off, int len) throws IOException { + try { se.write(str, off, len); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Flush the stream. *************** *** 210,217 **** --- 271,292 ---- * @exception IOException If an I/O error occurs */ public void flush() throws IOException { + try { se.flush(); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Close the stream. *************** *** 219,225 **** --- 294,314 ---- * @exception IOException If an I/O error occurs */ public void close() throws IOException { + try { se.close(); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); + } } } *** org/InputStreamReader.java 2 27 16:39:20 2004 --- InputStreamReader.java 3 1 10:12:08 2004 *************** *** 9,14 **** --- 9,18 ---- import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; + import java.nio.charset.CoderMalfunctionError; + import java.nio.charset.CharacterCodingException; + import java.nio.charset.MalformedInputException; + import java.nio.charset.UnmappableCharacterException; import sun.nio.cs.StreamDecoder; *************** *** 148,155 **** --- 152,175 ---- * @exception IOException If an I/O error occurs */ public int read() throws IOException { + try { return sd.read(); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (UnsupportedOperationException e) { + throw new IOException("UnsupportedOperationException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Read characters into a portion of an array. *************** *** 164,171 **** --- 184,207 ---- * @exception IOException If an I/O error occurs */ public int read(char cbuf[], int offset, int length) throws IOException { + try { return sd.read(cbuf, offset, length); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (UnsupportedOperationException e) { + throw new IOException("UnsupportedOperationException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Tell whether this stream is ready to be read. An InputStreamReader is *************** *** 175,182 **** --- 211,234 ---- * @exception IOException If an I/O error occurs */ public boolean ready() throws IOException { + try { return sd.ready(); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (UnsupportedOperationException e) { + throw new IOException("UnsupportedOperationException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); } + } /** * Close the stream. *************** *** 184,190 **** --- 236,258 ---- * @exception IOException If an I/O error occurs */ public void close() throws IOException { + try { sd.close(); + } catch (IllegalStateException e) { + throw new IOException("IllegalStateException occurred. in java.nio"); + } catch (IllegalArgumentException e) { + throw new IOException("IllegalArgumentException occurred. in java.nio"); + } catch (MalformedInputException e) { + throw new IOException("MalformedInputException occurred. in java.nio"); + } catch (UnmappableCharacterException e) { + throw new IOException("UnmappableCharacterException occurred. in java.nio"); + } catch (CharacterCodingException e) { + throw new IOException("CharacterCodingException occurred. in java.nio"); + } catch (UnsupportedOperationException e) { + throw new IOException("UnsupportedOperationException occurred. in java.nio"); + } catch (CoderMalfunctionError e) { + throw new IOException("CoderMalfunctionError occurred. in java.nio"); + } } } ###@###.### 2004-03-01 ===========================================================================
01-03-2004