pre-RFR (s): 8049847: Enhance PrintWriter line.separator handling

Claes Redestad claes.redestad at oracle.com
Sun Jan 4 14:10:32 UTC 2015


On 2015-01-04 11:06, Alan Bateman wrote:
> On 02/01/2015 15:38, Claes Redestad wrote:
>> Hi,
>>
>>  this is a proposal to resolve concerns that 
>> PrintWriter/BufferedWriter behave
>> inconsistently with j.u.Formatter when setting the line.separator 
>> property to override
>> system-appropriate line breaks.
>>
>>  Instead of providing a set of new constructors, I propose to simply 
>> add a new default
>> method j.l.Appendable#lineSeparator, which by default delegates to 
>> System.lineSeparator().
>> This allows classes such as PrintWriter/BufferedWriter to provide 
>> overrides which
>> communicate to j.u.Formatter their intended behavior.
> In the bug report then I assume the inconsistency only arises because 
> the test case attempts to change the line separator in the main 
> method, which is too late. It should work if set on the command-line 
> but this of course sets it system-wide.

Right, the PrintWriter inconsistency detailed:
- methods format/printf uses j.u.Formatter, which uses 
System.lineSeparator() internally if it
encounters an "%n" in the format string. Only responds to when changing 
line.separator on
command-line or similar.
- methods println and newLine use the PrintWriter internal lineSeparator 
value evaluated at
object creation time:

     public PrintWriter(Writer out,
                        boolean autoFlush) {
         super(out);
         this.out = out;
         this.autoFlush = autoFlush;
         lineSeparator = java.security.AccessController.doPrivileged(
             new sun.security.action.GetPropertyAction("line.separator"));
     }

This leads to hacks existing in the wild which sets line.separator 
before creating the PrintWriter,
as exemplified here: 
http://stackoverflow.com/questions/1014287/is-there-a-way-to-make-printwriter-output-to-unix-format

Removing this functionality could break compatibility with some 
applications where developers
are intentionally changing the line.separator, while it'd be nice if 
there was a better way to facilitate
this, which I think my proposal would allow with minimal

>
> Your proposal to add a lineSeperator() method to Appendable would 
> allow for customization but I'm not sure that it's the right place (as 
> Appendable is a very general interface and would require every 
> Appendable implementation that writes lines to be updated to make use 
> of the new method).

Yes, this can seem an awkward place to add this method, but the only 
place where we'd be able
to as easily make java.util.Formatter use the custom lineSeparator, 
without which we wouldn't
be able to resolve the inconsistency above nor provide a more convenient 
way for developers
to avoid the line.separator hack.

However, since Appendable is defined rather strictly-coupled with 
java.util.Formatter ("The Appendable
interface must be implemented by any class whose instances are intended 
to receive formatted
output from a java.util.Formatter.") and Formatter provides a 
higher-order mechanism to print new-lines
("%n") to the Appendable, it doesn't feel entirely arbitrary that the 
lineSeparator behavior should be
accessible via Appendable.

>
> An alternative to consider is adding the notion of lines to 
> java.io.Writer and update it to define newLine() and lineSeperator() 
> methods (i.e. move the BufferWriter::newLine method up to Writer). 
> It's a bit of extra work to update BufferedWriter's spec, adjust a few 
> things in PrintWriter/PrintStream, and special-case Writers in 
> Formatter but something to consider.

I need to think about what that would mean, and especially how to solve 
it on the Formatter side.
I worry shoehorning Writer or upcasts into Formatter might be more 
complex that it's worth.
Any ideas?

/Claes

>
> -Alan




More information about the core-libs-dev mailing list