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

Bruno P. Kinoshita commented on IO-554:
---------------------------------------

TL;DR;
 * *2.5 did not close the stream*
 * *2.6 closed the stream after the introduction of try-with-resources*
 * *This issue is about the changed behaviour, with a pull request to revert it 
back to 2.5 behaviour*

Recapitulating;

I believe the *copyToFile* method was released with Release 2.5 – 2016-04-22, 
added in this commit from IO-381 from May 2013 
[https://github.com/apache/commons-io/commit/ee2f71d9fd2ce253f53de137950fa90087b9f565]

The code from the 2.5 released tag reads:
{code:java}
    /**
     * Copies bytes from an {@link InputStream} <code>source</code> to a file
     * <code>destination</code>. The directories up to <code>destination</code>
     * will be created if they don't already exist. <code>destination</code>
     * will be overwritten if it already exists.
     * The {@code source} stream is left open, e.g. for use with {@link 
java.util.zip.ZipInputStream ZipInputStream}.
     * See {@link #copyInputStreamToFile(InputStream, File)} for a method that 
closes the input stream.
     *
     * @param source      the <code>InputStream</code> to copy bytes from, must 
not be {@code null}
     * @param destination the non-directory <code>File</code> to write bytes to
     *                    (possibly overwriting), must not be {@code null}
     * @throws IOException if <code>destination</code> is a directory
     * @throws IOException if <code>destination</code> cannot be written
     * @throws IOException if <code>destination</code> needs creating but can't 
be
     * @throws IOException if an IO error occurs during copying
     * @since 2.5
     */
    public static void copyToFile(final InputStream source, final File 
destination) throws IOException {
        final FileOutputStream output = openOutputStream(destination);
        try {
            IOUtils.copy(source, output);
            output.close(); // don't swallow close Exception if copy completes 
normally
        } finally {
            IOUtils.closeQuietly(output);
        }
    }
{code}
NB the Javadocs states "*The \{@code source} stream is left open*". I had a 
look at the code, and tested in Eclipse, and it is indeed left open.
 
 But on this commit from May 2016, released later with Release 2.6 – 
2017-10-15, we added try-with-resources, which changed the behaviour of the 
code.
 
 The code from IO-505 from the 2.6 released tag_**_ reads:
{code:java}
    /**
     * Copies bytes from an {@link InputStream} <code>source</code> to a file
     * <code>destination</code>. The directories up to <code>destination</code>
     * will be created if they don't already exist. <code>destination</code>
     * will be overwritten if it already exists.
     * The {@code source} stream is left open, e.g. for use with {@link 
java.util.zip.ZipInputStream ZipInputStream}.
     * See {@link #copyInputStreamToFile(InputStream, File)} for a method that 
closes the input stream.
     *
     * @param source      the <code>InputStream</code> to copy bytes from, must 
not be {@code null}
     * @param destination the non-directory <code>File</code> to write bytes to
     *                    (possibly overwriting), must not be {@code null}
     * @throws IOException if <code>destination</code> is a directory
     * @throws IOException if <code>destination</code> cannot be written
     * @throws IOException if <code>destination</code> needs creating but can't 
be
     * @throws IOException if an IO error occurs during copying
     * @since 2.5
     */
    public static void copyToFile(final InputStream source, final File 
destination) throws IOException {
        try (InputStream in = source;
             OutputStream out = openOutputStream(destination)) {
            IOUtils.copy(in, out);
        }
    }
{code}
NB the Javadocs states "*The \{@code source} stream is left open*". But the 
try-with-resources closes the in/source input stream. I think this change in 
the behaviour was not intentional.

The pull request for this issue is proposing to revert what was added in 2.6. I 
would not use commons-io-2.6 `copyToFile`, as I would normally handle the 
stream myself, or use the other method that already closed the stream before.

[~tmortagne],

>I agree that behavior should not change but that's actually an argument for a 
>bugfix release as fast as possible, not to keep a regression.

+1

In a similar case, Commons Pool 2.4.3 kept binary compatibility but changed the 
way the code worked when iterating stack traces (see POOL-320), which caused an 
issue and prevented us from using this version in Commons DBCP. Instead of 
keeping the method and adding a new one, or updating documentation, we reverted 
the change in 2.5.0 (see POOL-335).

In my opinion we should revert the regression added in 2.6, with [~mmariotti] 
's pull request suggested, which also includes a unit test to prevent the 
regression from happening again.

Cheers

Bruno

(**) There is a tag commons-io-2.5, but no commons-io-2.6, only RC1, RC2, and 
commons-io-2.6-RC3.

> FileUtils.copyToFile(InputStream source, File destination) closes input stream
> ------------------------------------------------------------------------------
>
>                 Key: IO-554
>                 URL: https://issues.apache.org/jira/browse/IO-554
>             Project: Commons IO
>          Issue Type: Bug
>          Components: Streams/Writers
>    Affects Versions: 2.6
>            Reporter: Michele Mariotti
>            Assignee: Bruno P. Kinoshita
>            Priority: Blocker
>              Labels: regression
>             Fix For: 2.7
>
>
> In 2.6 this method is closing the input stream, while the javadoc states the 
> opposite.
> The correct behavior is to leave the stream open, as stated in the javadoc.
> I assigned a high priority because this incorrect behavior breaks existing 
> code, especially when used in combination with ZipInputStream.
> {code:java}
> /**
>  * Copies bytes from an {@link InputStream} <code>source</code> to a file
>  * <code>destination</code>. The directories up to <code>destination</code>
>  * will be created if they don't already exist. <code>destination</code>
>  * will be overwritten if it already exists.
>  * The {@code source} stream is left open, e.g. for use with {@link 
> java.util.zip.ZipInputStream ZipInputStream}.
>  * See {@link #copyInputStreamToFile(InputStream, File)} for a method that 
> closes the input stream.
>  *
>  * @param source      the <code>InputStream</code> to copy bytes from, must 
> not be {@code null}
>  * @param destination the non-directory <code>File</code> to write bytes to
>  *                    (possibly overwriting), must not be {@code null}
>  * @throws IOException if <code>destination</code> is a directory
>  * @throws IOException if <code>destination</code> cannot be written
>  * @throws IOException if <code>destination</code> needs creating but can't be
>  * @throws IOException if an IO error occurs during copying
>  * @since 2.5
>  */
> public static void copyToFile(final InputStream source, final File 
> destination) throws IOException {
>       try (InputStream in = source;
>                OutputStream out = openOutputStream(destination)) {
>               IOUtils.copy(in, out);
>       }
> }
> {code}
> instead it should be:
> {code:java}
> public static void copyToFile(final InputStream source, final File 
> destination) throws IOException {
>       try (OutputStream out = openOutputStream(destination)) {
>               IOUtils.copy(source, out);
>       }
> }{code}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to