JDK-8230344 : LineNumberReader.skipLF is not considered by all methods
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 11.0.4,13,14
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_10
  • CPU: x86_64
  • Submitted: 2019-08-27
  • Updated: 2019-08-30
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
tbdUnresolved
Related Reports
Relates :  
Relates :  
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
LineNumberRead.read() collapses \r\n into \n. To indicate that a following \n should be discarded, skipLF is set. This means the next encountered \n should be considered as already consumed.

However, not all methods of LineNumberRead consider this. mark() has already been adjusted, see JDK-8218280.

Currently the following methods do not properly discard the next \n:
- read(char[]): Reads the \n
- skip(long): Skips the \n (because implementation calls read(char[]))


---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.io.StringReader;

public class CollapsingLineTerminatorTest {
    private static final String STRING = "\r\ntest";
    
    public static void main(String[] args) throws IOException {
        System.out.println("Methods considering skipLF:");
        // All of these method calls read / skip one character
        // They should ignore the \n which was part of \r\n
        System.out.println("  read: " + successful(testRead()));
        System.out.println("  read(char[]): " + successful(testReadBuff()));
        System.out.println("  mark/reset: " + successful(testMarkReset()));
        System.out.println("  skip: " + successful(testSkip()));
    }
    
    private static boolean successful(Reader reader) throws IOException {
        // \r\n was read by initial read(), then specific test method should have 
        // read `t`, so next character is expected to be `e`
        return reader.read() == 'e';
    }
    
    private static LineNumberReader createReader() throws IOException {
        LineNumberReader reader = new LineNumberReader(new StringReader(STRING));
        // Collapses \r\n into \n, i.e. sets skipLF
        reader.read();
        
        return reader;
    }
    
    private static LineNumberReader testRead() throws IOException {
        LineNumberReader reader = createReader();
        reader.read();
        return reader;
    }
    
    private static LineNumberReader testReadBuff() throws IOException {
        LineNumberReader reader = createReader();
        reader.read(new char[1]);
        return reader;
    }
    
    private static LineNumberReader testMarkReset() throws IOException {
        LineNumberReader reader = createReader();
        // Mark / reset restored skipLF
        // readAheadLimit is also adjusted, see JDK-8218280
        reader.mark(1);
        reader.read();
        reader.reset();
        reader.read();
        return reader;
    }
    
    private static LineNumberReader testSkip() throws IOException {
        LineNumberReader reader = createReader();
        reader.skip(1);
        return reader;
    }
}

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

FREQUENCY : always



Comments
To reproduce the issue, run the attached test case : JDK 11.0.4 - Fail JDK 13-ea+32 - Fail JDK 14-ea+8 - Fail Output: Methods considering skipLF: read: true read(char[]): false mark/reset: true skip: false
29-08-2019