-
Bug
-
Resolution: Unresolved
-
P4
-
1.4.1, 6u10
-
Cause Known
-
x86
-
linux_2.6, windows_2000
Name: gm110360 Date: 09/09/2002
FULL PRODUCT VERSION :
java version "1.4.1-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-rc-b19)
Java HotSpot(TM) Client VM (build 1.4.1-rc-b19, mixed mode)
FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195] (sp2)
A DESCRIPTION OF THE PROBLEM :
bug: InputStreamReader doesn't call CharsetDecoder.flush
when it reaches the end of stream.
This is a problem for decoders which keep internal state and
need to
know when the end of stream is reached to flush the final
characters to the char buffer.
See CharsetDecoder
http://java.sun.com/j2se/1.4/docs/api/java/nio/charset/CharsetDecoder.html
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
To verify this problem, run the code below. It uses a very
simple Charset that is instrumented to show calls to
implReset and implFlush.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Actual: In j2se1.4.1rc1, I get the following output.
Decoder receives call to implReset at end of input stream.
Expected: Decoder should receive a call to implFlush at end
of input stream.
<pre>
Testing Encoder...
before start: EncoderState: reset=true, flushed=true
between write and flush: EncoderState: reset=false,
flushed=false
after flush: EncoderState: reset=false, flushed=false
flushed encoder
after close: EncoderState: reset=false, flushed=true
Testing Decoder...
before start: DecoderState: reset=true, flushed=true
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
reset decoder <-----???
after done: DecoderState: reset=true, flushed=false
</pre>
ERROR MESSAGES/STACK TRACES THAT OCCUR :
This stack trace shows that reset is being called from read.
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1071)
at
TestReaderFlushesCharset$TestDecoder.implReset(TestReaderFlushesCharset.java:123)
at java.nio.charset.CharsetDecoder.reset(CharsetDecoder.java:656)
at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:464)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at TestReaderFlushesCharset.testDecoder(TestReaderFlushesCharset.java:63)
at TestReaderFlushesCharset.main(TestReaderFlushesCharset.java:37)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
/** bug: InputStreamReader doesn't call CharsetDecoder.flush.
<p>This is a problem for decoders which keep internal state and need to
know when the end of stream is reached.
<p>To verify this problem, run the code below.
In j2se1.4.1rc1, I get the following output. Notice decoder
receives call to implReset where it should receive a call to implFlush.
<pre>
Testing Encoder...
before start: EncoderState: reset=true, flushed=true
between write and flush: EncoderState: reset=false, flushed=false
after flush: EncoderState: reset=false, flushed=false
flushed encoder
after close: EncoderState: reset=false, flushed=true
Testing Decoder...
before start: DecoderState: reset=true, flushed=true
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
reset decoder <-----???
after done: DecoderState: reset=true, flushed=false
</pre>
**/
public class TestReaderFlushesCharset extends Charset{
static TestReaderFlushesCharset testCharset = new TestReaderFlushesCharset();
public static void main(String[] ignore) {
testEncoder();
testDecoder();
}
private static void testEncoder() {
System.out.println("\nTesting Encoder...");
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TestEncoder testEncoder = (TestEncoder) testCharset.newEncoder();
OutputStreamWriter writer = new OutputStreamWriter(outStream, testEncoder);
try {
System.out.println("before start: "+testEncoder.state());
writer.write("hello world");
System.out.println("between write and flush: "+testEncoder.state());
writer.flush();
System.out.println("after flush: "+testEncoder.state());
writer.close();
System.out.println("after close: "+testEncoder.state());
} catch (IOException e) { e.printStackTrace(); }
}
private static void testDecoder() {
System.out.println("\nTesting Decoder...");
ByteArrayInputStream inStream = new ByteArrayInputStream
(new byte[]{'h','i',' ','w','o','r','l','d'});
TestDecoder testDecoder = (TestDecoder) testCharset.newDecoder();
InputStreamReader reader = new InputStreamReader(inStream, testDecoder);
try {
System.out.println("before start: "+testDecoder.state());
char[] buf = new char[3];
while( reader.read(buf, 0, buf.length) > 0)
System.out.println("after read: "+testDecoder.state());
System.out.println("after done: "+testDecoder.state());
} catch (IOException e) { e.printStackTrace(); }
}
TestReaderFlushesCharset() { super("X-TestCharSet", new String[]{}); }
public boolean contains(Charset cs) {
return cs instanceof TestReaderFlushesCharset;
}
public CharsetEncoder newEncoder() {
return new TestEncoder();
}
public CharsetDecoder newDecoder() {
return new TestDecoder();
}
class TestEncoder extends CharsetEncoder {
// some dummy internal state;
boolean reset = true;
boolean flushed = true;
TestEncoder() {
super(TestReaderFlushesCharset.this, 1.0f, 2.0f);
}
public String state() {
return "EncoderState: reset="+reset+", flushed="+flushed; }
protected void implReset() {
reset = true;
System.err.println("reset encoder");
}
protected CoderResult implFlush(ByteBuffer out) {
flushed = true;
System.err.println("flushed encoder");
return CoderResult.UNDERFLOW;
}
protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
// System.err.println("encode loop in.remaining="+in.remaining());
while (in.hasRemaining()) {
if (!out.hasRemaining())
return CoderResult.OVERFLOW;
reset = false;
flushed = false;
out.put((byte) (in.get() & 0xff)); // test works only for latin-1.
}
return CoderResult.UNDERFLOW;
}
}
class TestDecoder extends CharsetDecoder {
// some dummy internal state;
boolean reset = true;
boolean flushed = true;
TestDecoder() {
super(TestReaderFlushesCharset.this, 1.0f, 1.0f);
}
public String state() {
return "DecoderState: reset="+reset+", flushed="+flushed; }
protected void implReset() {
//Thread.dumpStack();
reset = true;
System.err.println("reset decoder");
}
protected CoderResult implFlush(CharBuffer out) {
flushed = true;
System.err.println("flushed decoder");
return CoderResult.UNDERFLOW;
}
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
// System.err.println("decode loop in.remaining="+in.remaining());
while (in.hasRemaining()) {
if (!out.hasRemaining())
return CoderResult.OVERFLOW;
reset = false;
flushed = false;
out.put((char) in.get()); // test works only for latin-1.
}
return CoderResult.UNDERFLOW;
}
}
}
---------- END SOURCE ----------
(Review ID: 164238)
======================================================================
FULL PRODUCT VERSION :
java version "1.4.1-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1-rc-b19)
Java HotSpot(TM) Client VM (build 1.4.1-rc-b19, mixed mode)
FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195] (sp2)
A DESCRIPTION OF THE PROBLEM :
bug: InputStreamReader doesn't call CharsetDecoder.flush
when it reaches the end of stream.
This is a problem for decoders which keep internal state and
need to
know when the end of stream is reached to flush the final
characters to the char buffer.
See CharsetDecoder
http://java.sun.com/j2se/1.4/docs/api/java/nio/charset/CharsetDecoder.html
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
To verify this problem, run the code below. It uses a very
simple Charset that is instrumented to show calls to
implReset and implFlush.
EXPECTED VERSUS ACTUAL BEHAVIOR :
Actual: In j2se1.4.1rc1, I get the following output.
Decoder receives call to implReset at end of input stream.
Expected: Decoder should receive a call to implFlush at end
of input stream.
<pre>
Testing Encoder...
before start: EncoderState: reset=true, flushed=true
between write and flush: EncoderState: reset=false,
flushed=false
after flush: EncoderState: reset=false, flushed=false
flushed encoder
after close: EncoderState: reset=false, flushed=true
Testing Decoder...
before start: DecoderState: reset=true, flushed=true
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
reset decoder <-----???
after done: DecoderState: reset=true, flushed=false
</pre>
ERROR MESSAGES/STACK TRACES THAT OCCUR :
This stack trace shows that reset is being called from read.
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1071)
at
TestReaderFlushesCharset$TestDecoder.implReset(TestReaderFlushesCharset.java:123)
at java.nio.charset.CharsetDecoder.reset(CharsetDecoder.java:656)
at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:464)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at TestReaderFlushesCharset.testDecoder(TestReaderFlushesCharset.java:63)
at TestReaderFlushesCharset.main(TestReaderFlushesCharset.java:37)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
/** bug: InputStreamReader doesn't call CharsetDecoder.flush.
<p>This is a problem for decoders which keep internal state and need to
know when the end of stream is reached.
<p>To verify this problem, run the code below.
In j2se1.4.1rc1, I get the following output. Notice decoder
receives call to implReset where it should receive a call to implFlush.
<pre>
Testing Encoder...
before start: EncoderState: reset=true, flushed=true
between write and flush: EncoderState: reset=false, flushed=false
after flush: EncoderState: reset=false, flushed=false
flushed encoder
after close: EncoderState: reset=false, flushed=true
Testing Decoder...
before start: DecoderState: reset=true, flushed=true
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
after read: DecoderState: reset=false, flushed=false
reset decoder <-----???
after done: DecoderState: reset=true, flushed=false
</pre>
**/
public class TestReaderFlushesCharset extends Charset{
static TestReaderFlushesCharset testCharset = new TestReaderFlushesCharset();
public static void main(String[] ignore) {
testEncoder();
testDecoder();
}
private static void testEncoder() {
System.out.println("\nTesting Encoder...");
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TestEncoder testEncoder = (TestEncoder) testCharset.newEncoder();
OutputStreamWriter writer = new OutputStreamWriter(outStream, testEncoder);
try {
System.out.println("before start: "+testEncoder.state());
writer.write("hello world");
System.out.println("between write and flush: "+testEncoder.state());
writer.flush();
System.out.println("after flush: "+testEncoder.state());
writer.close();
System.out.println("after close: "+testEncoder.state());
} catch (IOException e) { e.printStackTrace(); }
}
private static void testDecoder() {
System.out.println("\nTesting Decoder...");
ByteArrayInputStream inStream = new ByteArrayInputStream
(new byte[]{'h','i',' ','w','o','r','l','d'});
TestDecoder testDecoder = (TestDecoder) testCharset.newDecoder();
InputStreamReader reader = new InputStreamReader(inStream, testDecoder);
try {
System.out.println("before start: "+testDecoder.state());
char[] buf = new char[3];
while( reader.read(buf, 0, buf.length) > 0)
System.out.println("after read: "+testDecoder.state());
System.out.println("after done: "+testDecoder.state());
} catch (IOException e) { e.printStackTrace(); }
}
TestReaderFlushesCharset() { super("X-TestCharSet", new String[]{}); }
public boolean contains(Charset cs) {
return cs instanceof TestReaderFlushesCharset;
}
public CharsetEncoder newEncoder() {
return new TestEncoder();
}
public CharsetDecoder newDecoder() {
return new TestDecoder();
}
class TestEncoder extends CharsetEncoder {
// some dummy internal state;
boolean reset = true;
boolean flushed = true;
TestEncoder() {
super(TestReaderFlushesCharset.this, 1.0f, 2.0f);
}
public String state() {
return "EncoderState: reset="+reset+", flushed="+flushed; }
protected void implReset() {
reset = true;
System.err.println("reset encoder");
}
protected CoderResult implFlush(ByteBuffer out) {
flushed = true;
System.err.println("flushed encoder");
return CoderResult.UNDERFLOW;
}
protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) {
// System.err.println("encode loop in.remaining="+in.remaining());
while (in.hasRemaining()) {
if (!out.hasRemaining())
return CoderResult.OVERFLOW;
reset = false;
flushed = false;
out.put((byte) (in.get() & 0xff)); // test works only for latin-1.
}
return CoderResult.UNDERFLOW;
}
}
class TestDecoder extends CharsetDecoder {
// some dummy internal state;
boolean reset = true;
boolean flushed = true;
TestDecoder() {
super(TestReaderFlushesCharset.this, 1.0f, 1.0f);
}
public String state() {
return "DecoderState: reset="+reset+", flushed="+flushed; }
protected void implReset() {
//Thread.dumpStack();
reset = true;
System.err.println("reset decoder");
}
protected CoderResult implFlush(CharBuffer out) {
flushed = true;
System.err.println("flushed decoder");
return CoderResult.UNDERFLOW;
}
protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
// System.err.println("decode loop in.remaining="+in.remaining());
while (in.hasRemaining()) {
if (!out.hasRemaining())
return CoderResult.OVERFLOW;
reset = false;
flushed = false;
out.put((char) in.get()); // test works only for latin-1.
}
return CoderResult.UNDERFLOW;
}
}
}
---------- END SOURCE ----------
(Review ID: 164238)
======================================================================
- relates to
-
JDK-6275027 (cs) StreamEncoder throws uninformative Error when encoding unpaired surrogates
-
- Resolved
-