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 08331faee8372ef19ce2e5787abe1390b8fdd01c
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Tue Sep 20 14:36:56 2022 +0200

    Workaround a misleading error message from ImageIO.
---
 .../sis/internal/storage/image/FormatFinder.java   | 34 ++++++++++++++++++--
 .../org/apache/sis/storage/StorageConnector.java   | 36 ++++++++++++++++++++--
 2 files changed, 65 insertions(+), 5 deletions(-)

diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/FormatFinder.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/FormatFinder.java
index d4f7f83837..72a63613bf 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/FormatFinder.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/FormatFinder.java
@@ -26,6 +26,7 @@ import java.nio.file.Files;
 import javax.imageio.ImageIO;
 import javax.imageio.ImageReader;
 import javax.imageio.ImageWriter;
+import javax.imageio.IIOException;
 import javax.imageio.spi.ImageReaderSpi;
 import javax.imageio.spi.ImageWriterSpi;
 import javax.imageio.stream.ImageInputStream;
@@ -34,6 +35,7 @@ import javax.imageio.stream.FileImageOutputStream;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.internal.storage.io.IOUtilities;
+import org.apache.sis.util.Workaround;
 
 
 /**
@@ -42,7 +44,7 @@ import org.apache.sis.internal.storage.io.IOUtilities;
  * It also helps to choose which {@link WorldFileStore} subclass to 
instantiate.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.2
  * @module
  */
@@ -212,7 +214,7 @@ final class FormatFinder implements AutoCloseable {
                     ImageInputStream stream = null;
                     for (final Map.Entry<ImageReaderSpi,Boolean> entry : 
deferred.entrySet()) {
                         if (entry.getValue()) {
-                            if (stream == null) {
+                            if (stream == null) try {
                                 if (isWritable) {
                                     // ImageOutputStream is both read and 
write.
                                     stream = 
ImageIO.createImageOutputStream(storage);
@@ -221,6 +223,8 @@ final class FormatFinder implements AutoCloseable {
                                     stream = 
ImageIO.createImageInputStream(storage);
                                     if (stream == null) break;
                                 }
+                            } catch (IIOException e) {
+                                throw unwrap(e);
                             }
                             final ImageReaderSpi p = entry.getKey();
                             if (p.canDecodeInput(stream)) {
@@ -259,9 +263,11 @@ final class FormatFinder implements AutoCloseable {
                                 final File file = 
connector.getStorageAs(File.class);
                                 if (file != null) {
                                     stream = new FileImageOutputStream(file);
-                                } else {
+                                } else try {
                                     stream = 
ImageIO.createImageOutputStream(storage);
                                     if (stream == null) break;
+                                } catch (IIOException e) {
+                                    throw unwrap(e);
                                 }
                             }
                             final ImageWriterSpi p = entry.getKey();
@@ -277,6 +283,28 @@ final class FormatFinder implements AutoCloseable {
         return writer;
     }
 
+    /**
+     * Returns the cause of given exception if it exists, or the exception 
itself otherwise.
+     * This method is invoked in the {@code catch} block of a {@code try} 
block invoking
+     * {@link ImageIO#createImageInputStream(Object)} or
+     * {@link ImageIO#createImageOutputStream(Object)}.
+     *
+     * <h4>Rational</h4>
+     * As of Java 18, above-cited methods systematically catch all {@link 
IOException}s and wrap
+     * them in an {@link IIOException} with <cite>"Can't create cache 
file!"</cite> error message.
+     * This is conform to Image I/O specification but misleading if the stream 
provider throws an
+     * {@link IOException} for another reason. Even when the failure is really 
caused by a problem
+     * with cache file, we want to propagate the original exception to user 
because its message
+     * may tell that there is no space left on device or no write permission.
+     *
+     * @see org.apache.sis.storage.StorageConnector#unwrap(IIOException)
+     */
+    @Workaround(library = "JDK", version = "18")
+    private static IOException unwrap(final IIOException e) {
+        final Throwable cause = e.getCause();
+        return (cause instanceof IOException) ? (IOException) cause : e;
+    }
+
     /**
      * Closes all unused resources. Keep open only the find of objects needed 
by the image reader or writer.
      * This method must be invoked after by {@link WorldFileStore} 
construction.
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
index 5560158acd..9ba807bbb7 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/storage/StorageConnector.java
@@ -38,12 +38,14 @@ import java.nio.channels.SeekableByteChannel;
 import java.nio.file.NoSuchFileException;
 import javax.imageio.stream.ImageInputStream;
 import javax.imageio.stream.ImageOutputStream;
+import javax.imageio.IIOException;
 import javax.imageio.ImageIO;
 import java.sql.Connection;
 import java.sql.SQLException;
 import javax.sql.DataSource;
 import org.apache.sis.util.Debug;
 import org.apache.sis.util.Classes;
+import org.apache.sis.util.Workaround;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.resources.Errors;
@@ -1037,7 +1039,11 @@ public class StorageConnector implements Serializable {
             views.put(DataInput.class, c);                          // Share 
the same Coupled instance.
         } else {
             reset();
-            asDataInput = ImageIO.createImageInputStream(storage);
+            try {
+                asDataInput = ImageIO.createImageInputStream(storage);
+            } catch (IIOException e) {
+                throw unwrap(e);
+            }
             addView(DataInput.class, asDataInput, null, (byte) 
(CASCADE_ON_RESET | CASCADE_ON_CLOSE));
             /*
              * Note: Java Image I/O wrappers for Input/OutputStream do NOT 
close the underlying streams.
@@ -1361,7 +1367,11 @@ public class StorageConnector implements Serializable {
             views.put(DataOutput.class, c);                         // Share 
the same Coupled instance.
         } else {
             reset();
-            asDataOutput = ImageIO.createImageOutputStream(storage);
+            try {
+                asDataOutput = ImageIO.createImageOutputStream(storage);
+            } catch (IIOException e) {
+                throw unwrap(e);
+            }
             addView(DataOutput.class, asDataOutput, null, (byte) 
(CASCADE_ON_RESET | CASCADE_ON_CLOSE));
             /*
              * Note: Java Image I/O wrappers for Input/OutputStream do NOT 
close the underlying streams.
@@ -1598,6 +1608,28 @@ public class StorageConnector implements Serializable {
         }
     }
 
+    /**
+     * Returns the cause of given exception if it exists, or the exception 
itself otherwise.
+     * This method is invoked in the {@code catch} block of a {@code try} 
block invoking
+     * {@link ImageIO#createImageInputStream(Object)} or
+     * {@link ImageIO#createImageOutputStream(Object)}.
+     *
+     * <h4>Rational</h4>
+     * As of Java 18, above-cited methods systematically catch all {@link 
IOException}s and wrap
+     * them in an {@link IIOException} with <cite>"Can't create cache 
file!"</cite> error message.
+     * This is conform to Image I/O specification but misleading if the stream 
provider throws an
+     * {@link IOException} for another reason. Even when the failure is really 
caused by a problem
+     * with cache file, we want to propagate the original exception to user 
because its message
+     * may tell that there is no space left on device or no write permission.
+     *
+     * @see 
org.apache.sis.internal.storage.image.FormatFinder#unwrap(IIOException)
+     */
+    @Workaround(library = "JDK", version = "18")
+    private static IOException unwrap(final IIOException e) {
+        final Throwable cause = e.getCause();
+        return (cause instanceof IOException) ? (IOException) cause : e;
+    }
+
     /**
      * Returns a string representation of this {@code StorageConnector} for 
debugging purpose.
      * This string representation is for diagnostic and may change in any 
future version.

Reply via email to