This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 53a36ee267887d253dd95f924747847a940815d6
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Feb 1 13:22:29 2024 +0100

    Reduce the amount of magic in `IOUtilities` relative to the conversion from 
URL to Path.
    This is consequence of URL constuctors being deprecated in Java 20. If URLs 
can only be
    created via URI, a consequence is that the encoding must be UTF-8 and some 
`IOUtilities`
    methods become obsolete.
---
 .../org/apache/sis/io/stream/ChannelFactory.java   |   5 +-
 .../main/org/apache/sis/io/stream/IOUtilities.java | 206 ++++-----------------
 .../org/apache/sis/io/stream/IOUtilitiesTest.java  |  76 +-------
 3 files changed, 46 insertions(+), 241 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelFactory.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelFactory.java
index 38e1d64089..b0fa01ae17 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelFactory.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/ChannelFactory.java
@@ -31,6 +31,7 @@ import java.io.IOException;
 import java.net.URI;
 import java.net.URL;
 import java.net.MalformedURLException;
+import java.net.URISyntaxException;
 import java.nio.file.Path;
 import java.nio.file.Files;
 import java.nio.file.InvalidPathException;
@@ -174,8 +175,8 @@ public abstract class ChannelFactory {
          */
         if (storage instanceof URL) {
             try {
-                storage = IOUtilities.toPath((URL) storage, encoding);
-            } catch (IOException e) {
+                storage = Path.of(((URL) storage).toURI());
+            } catch (IllegalArgumentException | URISyntaxException | 
FileSystemNotFoundException e) {
                 /*
                  * This is normal if the URL uses HTTP or FTP protocol for 
instance. Log the exception at FINE
                  * level without stack trace. We will open the channel later 
using the URL instead of the Path.
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
index f3d786aca5..d03c9b5ad0 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/IOUtilities.java
@@ -27,6 +27,7 @@ import java.io.DataOutput;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URL;
 import java.net.URLDecoder;
@@ -314,7 +315,7 @@ public final class IOUtilities extends Static {
      * @param  path  the path to encode, or {@code null}.
      * @return the encoded path, or {@code null} if and only if the given path 
was null.
      */
-    public static String encodeURI(final String path) {
+    static String encodeURI(final String path) {
         if (path == null) {
             return null;
         }
@@ -354,161 +355,6 @@ public final class IOUtilities extends Static {
         return (buffer != null) ? buffer.toString() : path;
     }
 
-    /**
-     * Converts a path specified as a character string to an URL.
-     * This method can be used as a replacement for the deprecated {@link URL} 
constructors.
-     *
-     * @param  url       the path to convert, or {@code null}.
-     * @param  encoding  if the URL is encoded in a {@code 
application/x-www-form-urlencoded} MIME format,
-     *                   the character encoding (normally {@code "UTF-8"}).
-     *                   If the URL is not encoded, then {@code null}.
-     * @return the path converted to an uRL, or {@code null} if the given path 
was null.
-     * @throws MalformedURLException if the path cannot be parsed as an URL.
-     * @throws IOException if a non-null {@code encoding} was specified and an 
encoding error is found.
-     */
-    public static URL toURL(String url, final String encoding) throws 
IOException {
-        if (url == null) {
-            return null;
-        }
-        if (encoding != null) {
-            url = URLDecoder.decode(url, encoding);
-        }
-        url = encodeURI(url);
-        try {
-            return new URI(url).parseServerAuthority().toURL();
-        } catch (IllegalArgumentException | URISyntaxException cause) {
-            throw (MalformedURLException) new 
MalformedURLException(malformed(url, cause)).initCause(cause);
-        }
-    }
-
-    /**
-     * Converts a {@link URL} to a {@link URI}. This is equivalent to a call 
to the standard {@link URL#toURI()}
-     * method, except for the following functionalities:
-     *
-     * <ul>
-     *   <li>Optionally decodes the {@code "%XX"} sequences, where {@code 
"XX"} is a number.</li>
-     *   <li>Escape spaces and a some other reserved characters.</li>
-     *   <li>Converts exceptions into subclasses of {@link IOException}.</li>
-     * </ul>
-     *
-     * @param  url       the URL to convert, or {@code null}.
-     * @param  encoding  if the URL is encoded in a {@code 
application/x-www-form-urlencoded} MIME format,
-     *                   the character encoding (normally {@code "UTF-8"}). If 
the URL is not encoded,
-     *                   then {@code null}.
-     * @return the URI for the given URL, or {@code null} if the given URL was 
null.
-     * @throws IOException if the URL cannot be converted to a URI.
-     *
-     * @see URI#URI(String)
-     * @see URL#toURI()
-     */
-    public static URI toURI(final URL url, final String encoding) throws 
IOException {
-        if (url == null) {
-            return null;
-        }
-        /*
-         * Convert the URL to a URI, taking in account the encoding if any. We 
want to escape
-         * spaces with `encodeURI(…)` before to convert. Invoking 
`URL.toURI()` is preferable
-         * to `new URI(String)` because the former performs more checks, but 
is possible only
-         * if the decoding and escaping resulted in no change.
-         */
-        final String specified = url.toExternalForm();
-        String path = specified;
-        if (encoding != null) {
-            path = URLDecoder.decode(path, encoding);
-        }
-        path = encodeURI(path);
-        try {
-            return path.equals(specified) ? url.toURI() : new URI(path);
-        } catch (URISyntaxException cause) {
-            /*
-             * Occurs only if the URL is not compliant with RFC 2396. 
Otherwise every URL
-             * should succeed, so a failure can actually be considered as a 
malformed URL.
-             */
-            throw (MalformedURLException) new 
MalformedURLException(malformed(url, cause)).initCause(cause);
-        }
-    }
-
-    /**
-     * Converts a {@link URL} to a {@link File}. This is equivalent to a call 
to the standard
-     * {@link URL#toURI()} method followed by a call to the {@link 
File#File(URI)} constructor,
-     * except that exceptions are converted to {@link IOException}:
-     *
-     * @param  url  the URL to convert, or {@code null}.
-     * @return the file for the given URL, or {@code null} if the given URL 
was null.
-     * @throws IOException if the URL cannot be converted to a file.
-     *
-     * @see File#File(URI)
-     */
-    public static File toFile(final URL url) throws IOException {
-        if (url == null) {
-            return null;
-        } else try {
-            return new File(url.toURI());
-        } catch (IllegalArgumentException | URISyntaxException cause) {
-            /*
-             * Typically happen when the URI scheme is not "file". But may 
also happen if the
-             * URI contains fragment that cannot be represented in a File 
(e.g. a Query part).
-             * The IllegalArgumentException does not allow us to distinguish 
those cases.
-             */
-            throw new IOException(malformed(url, cause), cause);
-        }
-    }
-
-    /**
-     * Prepares a message for a malformed URL.
-     *
-     * @param url    the malformed URL.
-     * @param cause  the exception thrown.
-     */
-    private static String malformed(final Object url, final Exception cause) {
-        return Exceptions.formatChainedMessages(null,
-                Errors.format(Errors.Keys.IllegalArgumentValue_2, "URL", url), 
cause);
-    }
-
-    /**
-     * Converts a {@link URL} to a {@link Path}. This is equivalent to a call 
to the standard
-     * {@link URL#toURI()} method followed by a call to the {@link 
Path#of(URI)} static method,
-     * except for the following functionalities:
-     *
-     * <ul>
-     *   <li>Optionally decodes the {@code "%XX"} sequences, where {@code 
"XX"} is a number.</li>
-     *   <li>Converts various exceptions into subclasses of {@link 
IOException}.</li>
-     * </ul>
-     *
-     * @param  url       the URL to convert, or {@code null}.
-     * @param  encoding  if the URL is encoded in a {@code 
application/x-www-form-urlencoded} MIME format,
-     *                   the character encoding (normally {@code "UTF-8"}). If 
the URL is not encoded,
-     *                   then {@code null}.
-     * @return the path for the given URL, or {@code null} if the given URL 
was null.
-     * @throws IOException if the URL cannot be converted to a path.
-     *
-     * @see Path#of(URI)
-     */
-    public static Path toPath(final URL url, final String encoding) throws 
IOException {
-        if (url == null) {
-            return null;
-        }
-        final URI uri = toURI(url, encoding);
-        try {
-            return Path.of(uri);
-        } catch (IllegalArgumentException | FileSystemNotFoundException cause) 
{
-            final String message = malformed(url, cause);
-            /*
-             * If the exception is IllegalArgumentException, then the URI 
scheme has been recognized
-             * but the URI syntax is illegal for that file system. So we can 
consider that the URL is
-             * malformed in regard to the rules of that particular file system.
-             */
-            final IOException e;
-            if (cause instanceof IllegalArgumentException) {
-                e = new MalformedURLException(message);
-                e.initCause(cause);
-            } else {
-                e = new IOException(message, cause);
-            }
-            throw e;
-        }
-    }
-
     /**
      * Parses the following path as a {@link File} if possible, or a {@link 
URL} otherwise.
      * In the special case where the given {@code path} is a URL using the 
{@code "file"} protocol,
@@ -521,13 +367,15 @@ public final class IOUtilities extends Static {
      *
      * @param  path      the path to convert, or {@code null}.
      * @param  encoding  if the URL is encoded in a {@code 
application/x-www-form-urlencoded} MIME format,
-     *                   the character encoding (normally {@code "UTF-8"}). If 
the URL is not encoded,
-     *                   then {@code null}. This argument is ignored if the 
given path does not need
-     *                   to be converted from URL to {@code File}.
-     * @return the path as a {@link File} if possible, or a {@link URL} 
otherwise.
-     * @throws IOException if the given path is not a file and cannot be 
parsed as a URL.
+     *         the character encoding (normally {@code "UTF-8"}). If the URL 
is not encoded, then {@code null}.
+     *         This argument is ignored if the given path does not need to be 
converted from URL to {@code File}.
+     * @return the path as a {@link File} if possible, or as a {@link URL} 
otherwise.
+     * @throws UnsupportedEncodingException if the specified encoding is 
invalid.
+     * @throws MalformedURLException if the given path is not a file and 
cannot be parsed as a URL.
      */
-    public static Object toFileOrURL(final String path, final String encoding) 
throws IOException {
+    public static Object toFileOrURL(String path, final String encoding)
+            throws UnsupportedEncodingException, MalformedURLException
+    {
         if (path == null) {
             return null;
         }
@@ -546,17 +394,31 @@ public final class IOUtilities extends Static {
                 return new File(path);
             }
         }
-        final URL url = toURL(path, encoding);
-        final String scheme = url.getProtocol();
-        if (scheme != null && scheme.equalsIgnoreCase("file")) {
-            return toFile(url);
+        if (encoding != null) {
+            path = URLDecoder.decode(path, encoding);       // Replace 
sequences of the form "%xy".
         }
-        /*
-         * Leave the URL in its original encoding on the assumption that this 
is the encoding expected by
-         * the server. This is different than the policy for URI, because the 
latter are always in UTF-8.
-         * If a URI is needed, callers should use toURI(url, encoding).
-         */
-        return url;
+        path = encodeURI(path);                     // Re-encode spaces and a 
few other characters.
+        MalformedURLException ex;
+        IllegalArgumentException suppressed = null;
+        try {
+            final URI uri = new URI(path);
+            final String scheme = uri.getScheme();
+            if (scheme != null && scheme.equalsIgnoreCase("file")) try {
+                return new File(uri);
+            } catch (IllegalArgumentException e) {
+                suppressed = e;
+            }
+            return uri.parseServerAuthority().toURL();
+        } catch (MalformedURLException cause) {
+            ex = cause;
+        } catch (IllegalArgumentException | URISyntaxException cause) {
+            ex = (MalformedURLException) new 
MalformedURLException(Exceptions.formatChainedMessages(null,
+                    Errors.format(Errors.Keys.IllegalArgumentValue_2, "path", 
path), cause)).initCause(cause);
+        }
+        if (suppressed != null) {
+            ex.addSuppressed(suppressed);
+        }
+        throw ex;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
index bd9ee4a692..59146b4cc1 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/io/stream/IOUtilitiesTest.java
@@ -22,7 +22,6 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.io.File;
 import java.io.IOException;
-import org.apache.sis.util.CharSequences;
 
 // Test dependencies
 import org.junit.Test;
@@ -154,74 +153,10 @@ public final class IOUtilitiesTest extends TestCase {
         assertNull(IOUtilities.encodeURI(null));
     }
 
-    /**
-     * Tests {@link IOUtilities#toURI(URL, String)}.
-     *
-     * @throws IOException if a URL cannot be parsed.
-     * @throws URISyntaxException if a URI cannot be parsed.
-     */
-    @Test
-    @DependsOnMethod("testEncodeURI")
-    @SuppressWarnings("deprecation")
-    public void testToURI() throws IOException, URISyntaxException {
-        assertEquals(new URI("file:/Users/name/Map.png"),
-                IOUtilities.toURI(new URL("file:/Users/name/Map.png"), null));
-        assertEquals(new URI("file:/Users/name/Map%20with%20spaces.png"),
-                IOUtilities.toURI(new URL("file:/Users/name/Map with 
spaces.png"), null));
-        assertEquals(new URI("file:/Users/name/Map%20with%20spaces.png"),
-                IOUtilities.toURI(new 
URL("file:/Users/name/Map%20with%20spaces.png"), "UTF-8"));
-        assertEquals(new URI("file:/Users/name/Map%20with%20spaces.png"),
-                IOUtilities.toURI(new 
URL("file:/Users/name/Map%20with%20spaces.png"), "ISO-8859-1"));
-
-        // Here the URL is considered non-encoded, so the method shall encode 
the % sign.
-        assertEquals(new URI("file:/Users/name/Map%2520with%2520spaces.png"),
-                IOUtilities.toURI(new 
URL("file:/Users/name/Map%20with%20spaces.png"), null));
-    }
-
-    /**
-     * Tests the {@link IOUtilities#toFile(URL)} method. Do not test a 
Windows-specific path
-     * (e.g. {@code "file:///C:/some/path/Map.png"}), since the result is 
different on Windows or
-     * Unix platforms.
-     *
-     * @throws IOException if a URL cannot be parsed.
-     */
-    @Test
-    @DependsOnMethod("testToURI")
-    public void testToFile() throws IOException {
-        testToFile(null, "+");
-    }
-
-    /**
-     * Same test as {@link #testToFile()}, but using the UTF-8 encoding.
-     *
-     * @throws IOException if a URL cannot be parsed.
-     */
-    @Test
-    @DependsOnMethod("testToFile")
-    public void testToFileFromUTF8() throws IOException {
-        testToFile("UTF-8", "%2B");
-    }
-
-    /**
-     * Implementation of {@link #testToURL()} using the given encoding.
-     * If the encoding is null, then the {@code URLDecoder} will not be used.
-     *
-     * @param  encoding  the encoding, or {@code null} if none.
-     * @param  plus      the representation for the {@code '+'} sign.
-     * @throws IOException if a URL cannot be parsed.
-     */
-    private void testToFile(final String encoding, final String plus) throws 
IOException {
-        assertEquals(new File("/Users/name/Map.png"),                   // 
Unix absolute path.
-                
IOUtilities.toFile(IOUtilities.toURL("file:/Users/name/Map.png", encoding)));
-        assertEquals(new File("/Users/name/Map with spaces.png"),       // 
Path with space.
-                IOUtilities.toFile(IOUtilities.toURL("file:/Users/name/Map 
with spaces.png", encoding)));
-        assertEquals(new File("/Users/name/++t--++est.shp"),            // 
Path with + sign.
-                IOUtilities.toFile(IOUtilities.toURL(
-                        
CharSequences.replace("file:/Users/name/++t--++est.shp", "+", plus).toString(), 
encoding)));
-    }
-
     /**
      * Tests {@link IOUtilities#toFileOrURL(String)}.
+     * Do not test a Windows-specific path (e.g. {@code 
"file:///C:/some/path/Map.png"}),
+     * because the result is different on Windows or Unix platforms.
      *
      * @throws IOException if a URL cannot be parsed.
      */
@@ -233,5 +168,12 @@ public final class IOUtilitiesTest extends TestCase {
         assertEquals(URI.create("http://localhost";).toURL(), 
IOUtilities.toFileOrURL("http://localhost";, null));
         assertEquals(new File("/Users/name/Map with spaces.png"),
                 
IOUtilities.toFileOrURL("file:/Users/name/Map%20with%20spaces.png", "UTF-8"));
+
+        String path = "file:/Users/name/++t--++est.shp";
+        var expected = new File("/Users/name/++t--++est.shp");
+        assertEquals(expected, IOUtilities.toFileOrURL(path, null));
+
+        path = path.replace("+", "%2B");
+        assertEquals(expected, IOUtilities.toFileOrURL(path, "UTF-8"));
     }
 }

Reply via email to