You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2022/09/20 14:21:12 UTC
[sis] 02/03: Workaround a misleading error message from ImageIO.
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 <ma...@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.