Reimplement internals to use try-with-resources.
ADD
src/main/java/org/apache/commons/io/CloseableURLConnection.java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.Permission;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Delegates to a URLConnection while implementing AutoCloseable.
+ */
+class CloseableURLConnection extends URLConnection implements AutoCloseable {
+
+ static CloseableURLConnection open(final URI uri) throws IOException {
+ return open(Objects.requireNonNull(uri, "uri").toURL());
+ }
+
+ static CloseableURLConnection open(final URL url) throws IOException {
+ return new CloseableURLConnection(url.openConnection());
+ }
+
+ private final URLConnection urlConnection;
+
+ CloseableURLConnection(final URLConnection urlConnection) {
+ super(Objects.requireNonNull(urlConnection, "urlConnection").getURL());
+ this.urlConnection = urlConnection;
+ }
+
+ @Override
+ public void addRequestProperty(final String key, final String value) {
+ urlConnection.addRequestProperty(key, value);
+ }
+
+ @Override
+ public void close() {
+ IOUtils.close(urlConnection);
+ }
+
+ @Override
+ public void connect() throws IOException {
+ urlConnection.connect();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return urlConnection.equals(obj);
+ }
+
+ @Override
+ public boolean getAllowUserInteraction() {
+ return urlConnection.getAllowUserInteraction();
+ }
+
+ @Override
+ public int getConnectTimeout() {
+ return urlConnection.getConnectTimeout();
+ }
+
+ @Override
+ public Object getContent() throws IOException {
+ return urlConnection.getContent();
+ }
+
+ @Override
+ public Object getContent(final Class[] classes) throws IOException {
+ return urlConnection.getContent(classes);
+ }
+
+ @Override
+ public String getContentEncoding() {
+ return urlConnection.getContentEncoding();
+ }
+
+ @Override
+ public int getContentLength() {
+ return urlConnection.getContentLength();
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return urlConnection.getContentLengthLong();
+ }
+
+ @Override
+ public String getContentType() {
+ return urlConnection.getContentType();
+ }
+
+ @Override
+ public long getDate() {
+ return urlConnection.getDate();
+ }
+
+ @Override
+ public boolean getDefaultUseCaches() {
+ return urlConnection.getDefaultUseCaches();
+ }
+
+ @Override
+ public boolean getDoInput() {
+ return urlConnection.getDoInput();
+ }
+
+ @Override
+ public boolean getDoOutput() {
+ return urlConnection.getDoOutput();
+ }
+
+ @Override
+ public long getExpiration() {
+ return urlConnection.getExpiration();
+ }
+
+ @Override
+ public String getHeaderField(final int n) {
+ return urlConnection.getHeaderField(n);
+ }
+
+ @Override
+ public String getHeaderField(final String name) {
+ return urlConnection.getHeaderField(name);
+ }
+
+ @Override
+ public long getHeaderFieldDate(final String name, final long Default) {
+ return urlConnection.getHeaderFieldDate(name, Default);
+ }
+
+ @Override
+ public int getHeaderFieldInt(final String name, final int Default) {
+ return urlConnection.getHeaderFieldInt(name, Default);
+ }
+
+ @Override
+ public String getHeaderFieldKey(final int n) {
+ return urlConnection.getHeaderFieldKey(n);
+ }
+
+ @Override
+ public long getHeaderFieldLong(final String name, final long Default) {
+ return urlConnection.getHeaderFieldLong(name, Default);
+ }
+
+ @Override
+ public Map<String, List<String>> getHeaderFields() {
+ return urlConnection.getHeaderFields();
+ }
+
+ @Override
+ public long getIfModifiedSince() {
+ return urlConnection.getIfModifiedSince();
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return urlConnection.getInputStream();
+ }
+
+ @Override
+ public long getLastModified() {
+ return urlConnection.getLastModified();
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ return urlConnection.getOutputStream();
+ }
+
+ @Override
+ public Permission getPermission() throws IOException {
+ return urlConnection.getPermission();
+ }
+
+ @Override
+ public int getReadTimeout() {
+ return urlConnection.getReadTimeout();
+ }
+
+ @Override
+ public Map<String, List<String>> getRequestProperties() {
+ return urlConnection.getRequestProperties();
+ }
+
+ @Override
+ public String getRequestProperty(final String key) {
+ return urlConnection.getRequestProperty(key);
+ }
+
+ @Override
+ public URL getURL() {
+ return urlConnection.getURL();
+ }
+
+ @Override
+ public boolean getUseCaches() {
+ return urlConnection.getUseCaches();
+ }
+
+ @Override
+ public int hashCode() {
+ return urlConnection.hashCode();
+ }
+
+ @Override
+ public void setAllowUserInteraction(final boolean allowuserinteraction) {
+ urlConnection.setAllowUserInteraction(allowuserinteraction);
+ }
+
+ @Override
+ public void setConnectTimeout(final int timeout) {
+ urlConnection.setConnectTimeout(timeout);
+ }
+
+ @Override
+ public void setDefaultUseCaches(final boolean defaultusecaches) {
+ urlConnection.setDefaultUseCaches(defaultusecaches);
+ }
+
+ @Override
+ public void setDoInput(final boolean doinput) {
+ urlConnection.setDoInput(doinput);
+ }
+
+ @Override
+ public void setDoOutput(final boolean dooutput) {
+ urlConnection.setDoOutput(dooutput);
+ }
+
+ @Override
+ public void setIfModifiedSince(final long ifmodifiedsince) {
+ urlConnection.setIfModifiedSince(ifmodifiedsince);
+ }
+
+ @Override
+ public void setReadTimeout(final int timeout) {
+ urlConnection.setReadTimeout(timeout);
+ }
+
+ @Override
+ public void setRequestProperty(final String key, final String value) {
+ urlConnection.setRequestProperty(key, value);
+ }
+
+ @Override
+ public void setUseCaches(final boolean usecaches) {
+ urlConnection.setUseCaches(usecaches);
+ }
+
+ @Override
+ public String toString() {
+ return urlConnection.toString();
+ }
+
+}

MODIFY
src/main/java/org/apache/commons/io/FileUtils.java
src/main/java/org/apache/commons/io/FileUtils.java
import java.io.UncheckedIOException;
import java.math.BigInteger;
import java.net.URL;
-import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -1111,15 +1110,12 @@ public static void copyURLToFile(final URL source, final File destination) throw
*/
public static void copyURLToFile(final URL source, final File destination, final int connectionTimeoutMillis, final int readTimeoutMillis)
throws IOException {
- final URLConnection urlConnection = source.openConnection();
- try {
+ try (final CloseableURLConnection urlConnection = CloseableURLConnection.open(source)) {
urlConnection.setConnectTimeout(connectionTimeoutMillis);
urlConnection.setReadTimeout(readTimeoutMillis);
try (final InputStream stream = urlConnection.getInputStream()) {
copyInputStreamToFile(stream, destination);
}
- } finally {
- IOUtils.close(urlConnection);
}
}

MODIFY
src/main/java/org/apache/commons/io/IOUtils.java
src/main/java/org/apache/commons/io/IOUtils.java
@@ -2641,25 +2641,22 @@ public static BufferedReader toBufferedReader(final Reader reader, final int siz
* @since 2.4
*/
public static byte[] toByteArray(final URL url) throws IOException {
- final URLConnection conn = url.openConnection();
- try {
- return IOUtils.toByteArray(conn);
- } finally {
- close(conn);
+ try (final CloseableURLConnection urlConnection = CloseableURLConnection.open(url)) {
+ return IOUtils.toByteArray(urlConnection);
}
}
/**
* Gets the contents of a {@code URLConnection} as a {@code byte[]}.
*
- * @param urlConn the {@code URLConnection} to read.
+ * @param urlConnection the {@code URLConnection} to read.
* @return the requested byte array.
* @throws NullPointerException if the urlConn is null.
* @throws IOException if an I/O exception occurs.
* @since 2.4
*/
- public static byte[] toByteArray(final URLConnection urlConn) throws IOException {
- try (InputStream inputStream = urlConn.getInputStream()) {
+ public static byte[] toByteArray(final URLConnection urlConnection) throws IOException {
+ try (InputStream inputStream = urlConnection.getInputStream()) {
return IOUtils.toByteArray(inputStream);
}
}

MODIFY
src/main/java/org/apache/commons/io/input/XmlStreamReader.java
src/main/java/org/apache/commons/io/input/XmlStreamReader.java
@@ -507,6 +507,7 @@ public XmlStreamReader(final Path file) throws IOException {
* the URL.
*/
public XmlStreamReader(final URL url) throws IOException {
+ // TODO URLConnection leak.
this(Objects.requireNonNull(url, "url").openConnection(), null);
}

MODIFY
src/test/java/org/apache/commons/io/IOUtilsTest.java
src/test/java/org/apache/commons/io/IOUtilsTest.java
import java.net.Socket;
import java.net.URI;
import java.net.URL;
-import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.Selector;
@@ -1556,12 +1555,9 @@ public void testToByteArray_URL() throws Exception {
@Test
public void testToByteArray_URLConnection() throws Exception {
- final URLConnection urlConn = testFile.toURI().toURL().openConnection();
final byte[] actual;
- try {
- actual = IOUtils.toByteArray(urlConn);
- } finally {
- IOUtils.close(urlConn);
+ try (final CloseableURLConnection urlConnection = CloseableURLConnection.open(testFile.toURI())) {
+ actual = IOUtils.toByteArray(urlConnection);
}
assertEquals(FILE_SIZE, actual.length);
}

MODIFY
src/test/java/org/apache/commons/io/input/compatibility/XmlStreamReader.java
src/test/java/org/apache/commons/io/input/compatibility/XmlStreamReader.java
@@ -491,6 +491,7 @@ public XmlStreamReader(final InputStream inputStream, final String httpContentTy
* the URL.
*/
public XmlStreamReader(final URL url) throws IOException {
+ // TODO URLConnection leak.
this(url.openConnection());
}

Reimplement internals to use try-with-resources.