[ 
https://issues.apache.org/jira/browse/IO-729?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17420328#comment-17420328
 ] 

Rob Spoor commented on IO-729:
------------------------------

[~ggregory] I hadn't thought of a solution yet, I merely stated an issue. The 
throwing of the {{exception}} field in {{close()}} is the root of this issue.

Possible solutions:
* Add a flag, set in the constructor and defaulting to {{false}}, to omit 
throwing from {{close()}}. This would mean that {{close()}} would never throw 
an exception if the flag is set.
* Add a flag, set by any other method, to omit throwing from {{close}}. This 
would mean that {{close}} would only throw an exception if no other method 
caused an exception. This may break expected behaviour.
* Replace the {{exception}} field with a {{Supplier<IOException>}}. A new 
constructor needs to be added that takes a {{Supplier<IOException>}} instead of 
an {{IOException}}. The existing constructors need to be updated, for example:
{code}    public BrokenOutputStream(final IOException exception) {
        this(() -> exception);
    }

    public BrokenOutputStream() {
        this(() -> new IOException("Broken output stream")); // causes a new 
exception to be used for each method call
    }{code}

----

The first option is the simplest, but requires calling a different constructor 
when try-with-resources is used.
The second option is my least favourite, as it may cause issues with people 
expecting {{close()}} to throw an exception even if another method already 
threw one (these people are then not using try-with-resources).
The third option is my preferred choice, as provides the most flexibility. 
There is a change in behaviour if the non-argument constructor is called; each 
method will throw a different exception. Except when the constructor that takes 
an {{IOException}} is used, it does lead to a working try-with-resources block 
though, that will fail with an {{IOException}} and not an 
{{IllegalArgumentException}}. The {{IOException}} will have a suppressed 
{{IOException}} from the call to {{close()}}.

I'd like to hear your thoughts on this.

> BrokenReader, BrokenWriter, BrokenInputStream, BrokenOutputStream can cause 
> IllegalArgumentException in combination with try-with-resources
> -------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: IO-729
>                 URL: https://issues.apache.org/jira/browse/IO-729
>             Project: Commons IO
>          Issue Type: Bug
>          Components: Streams/Writers
>    Affects Versions: 2.8.0
>            Reporter: Rob Spoor
>            Priority: Minor
>
> The following little code snippet can cause an IllegalArgumentException with 
> message "Self-suppression not permitted":
> {code}        try (Writer writer = new BrokenWriter()) {
>             writer.write('a');
>         }{code}
> The try-with-resources mechanism will try to add the exception thrown from 
> {{close}} as suppress exception to the exception thrown from {{write}}. Since 
> those are the same, an exception is thrown. From the source of 
> java.lang.Throwable:
> {code}    public final synchronized void addSuppressed(Throwable exception) {
>         if (exception == this)
>             throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, 
> exception);{code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to