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/12/09 15:30:12 UTC

[sis] branch geoapi-4.0 updated (3d5020c294 -> e6382ae953)

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

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


    from 3d5020c294 Replace the `Optional` in `GridExtent.intersect(…)`  by `DisjointExtentException` for more consistency with other API doing similar work. It allows us to provide more helpful error message.
     new a09032ea36 `NumberFormatException` thrown when parsing an invalid code should be wrapped in a `NoSuchAuthorityCodeException`.
     new e6382ae953 Fix NullPointerException when auxiliary PRJ, TFW or HDR file can not be found. Improve test stability.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../referencing/factory/CommonAuthorityCode.java   | 10 ++++++-
 .../factory/CommonAuthorityFactory.java            | 35 +++++++++++-----------
 .../java/org/apache/sis/internal/util/Strings.java |  2 +-
 .../apache/sis/internal/storage/PRJDataStore.java  | 11 +++++--
 .../sis/internal/storage/esri/RawRasterStore.java  | 16 ++++++----
 .../sis/internal/storage/image/WorldFileStore.java | 18 ++++++-----
 .../internal/storage/csv/StoreProviderTest.java    |  5 +++-
 7 files changed, 60 insertions(+), 37 deletions(-)


[sis] 02/02: Fix NullPointerException when auxiliary PRJ, TFW or HDR file can not be found. Improve test stability.

Posted by de...@apache.org.
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 e6382ae9538c2f0c1530261f6747f3b6b7675ff5
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Fri Dec 9 16:29:35 2022 +0100

    Fix NullPointerException when auxiliary PRJ, TFW or HDR file can not be found.
    Improve test stability.
---
 .../org/apache/sis/internal/storage/PRJDataStore.java  | 11 ++++++++---
 .../sis/internal/storage/esri/RawRasterStore.java      | 16 ++++++++++------
 .../sis/internal/storage/image/WorldFileStore.java     | 18 +++++++++++-------
 .../sis/internal/storage/csv/StoreProviderTest.java    |  5 ++++-
 4 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
index 52029b56ed..38b510889f 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/PRJDataStore.java
@@ -66,7 +66,7 @@ import org.apache.sis.util.Classes;
  * be null and the CRS defined by the {@code DataOptionKey} will be used.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
  * @since   1.2
  * @module
  */
@@ -146,7 +146,12 @@ public abstract class PRJDataStore extends URIDataStore {
     protected final void readPRJ() throws DataStoreException {
         Exception cause = null;
         try {
-            final String wkt = readAuxiliaryFile(PRJ).toString();
+            final AuxiliaryContent content = readAuxiliaryFile(PRJ);
+            if (content == null) {
+                listeners.warning(Resources.format(Resources.Keys.CanNotReadAuxiliaryFile_1, PRJ));
+                return;
+            }
+            final String wkt = content.toString();
             final StoreFormat format = new StoreFormat(locale, timezone, null, listeners);
             format.setConvention(Convention.WKT1_COMMON_UNITS);         // Ignored if the format is WKT 2.
             final ParsePosition pos = new ParsePosition(0);
@@ -177,7 +182,7 @@ public abstract class PRJDataStore extends URIDataStore {
      * An arbitrary size limit is applied for safety.
      *
      * @param  extension    the filename extension of the auxiliary file to open.
-     * @return the file content together with the source. Should be short-lived.
+     * @return the file content together with the source, or {@code null} if none. Should be short-lived.
      * @throws NoSuchFileException if the auxiliary file has not been found (when opened from path).
      * @throws FileNotFoundException if the auxiliary file has not been found (when opened from URL).
      * @throws IOException if another error occurred while opening the stream.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterStore.java
index 7af2e2f21b..22b186f4bf 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterStore.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/esri/RawRasterStore.java
@@ -358,6 +358,10 @@ final class RawRasterStore extends RasterStore {
         RawRasterLayout layout = RawRasterLayout.BIL;
         ByteOrder byteOrder    = ByteOrder.nativeOrder();
         final AuxiliaryContent header = readAuxiliaryFile(RawRasterStoreProvider.HDR);
+        if (header == null) {
+            throw new DataStoreException(Resources.forLocale(getLocale())
+                    .getString(Resources.Keys.CanNotReadAuxiliaryFile_1, RawRasterStoreProvider.HDR));
+        }
         for (CharSequence line : CharSequences.splitOnEOL(header)) {
             final int length   = line.length();
             final int keyStart = CharSequences.skipLeadingWhitespaces(line, 0, length);
@@ -381,12 +385,12 @@ final class RawRasterStore extends RasterStore {
                         case BANDROWBYTES:  bandRowBytes  = parseStrictlyPositive(keyword, value); break;
                         case TOTALROWBYTES: totalRowBytes = parseStrictlyPositive(keyword, value); break;
                         case BANDGAPBYTES:  bandGapBytes  = Integer.parseInt(value); break;
-                        case SKIPBYTES:     skipBytes     = Long.valueOf(value); break;
-                        case ULXMAP:        ulxmap        = Double.valueOf(value); geomask |= 1; break;
-                        case ULYMAP:        ulymap        = Double.valueOf(value); geomask |= 2; break;
-                        case XDIM:          xdim          = Double.valueOf(value); geomask |= 4; break;
-                        case YDIM:          ydim          = Double.valueOf(value); geomask |= 8; break;
-                        case NODATA:        nodataValue   = Double.valueOf(value); break;
+                        case SKIPBYTES:     skipBytes     = Long.parseLong(value); break;
+                        case ULXMAP:        ulxmap        = Double.parseDouble(value); geomask |= 1; break;
+                        case ULYMAP:        ulymap        = Double.parseDouble(value); geomask |= 2; break;
+                        case XDIM:          xdim          = Double.parseDouble(value); geomask |= 4; break;
+                        case YDIM:          ydim          = Double.parseDouble(value); geomask |= 8; break;
+                        case NODATA:        nodataValue   = Double.parseDouble(value); break;
                         case PIXELTYPE:     signed        = indexOf(keyword, value, "SIGNED", "SIGNEDINT") >= 0; break;
                         case LAYOUT:        layout        = RawRasterLayout.valueOf(value.toUpperCase(Locale.US)); break;
                         case BYTEORDER: {
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
index cdfc09d1bd..251dfae3fe 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/image/WorldFileStore.java
@@ -370,17 +370,21 @@ loop:   for (int convention=0;; convention++) {
      * Reads the "World file" by parsing an auxiliary file with the given suffix.
      *
      * @param  wld  suffix of the auxiliary file.
-     * @return the "World file" content as an affine transform.
+     * @return the "World file" content as an affine transform, or {@code null} if none was found.
      * @throws IOException if an I/O error occurred.
      * @throws DataStoreException if the file content cannot be parsed.
      */
     private AffineTransform2D readWorldFile(final String wld) throws IOException, DataStoreException {
-        final AuxiliaryContent content  = readAuxiliaryFile(wld);
-        final String           filename = content.getFilename();
-        final CharSequence[]   lines    = CharSequences.splitOnEOL(readAuxiliaryFile(wld));
-        final int              expected = 6;        // Expected number of elements.
-        int                    count    = 0;        // Actual number of elements.
-        final double[]         elements = new double[expected];
+        final AuxiliaryContent content = readAuxiliaryFile(wld);
+        if (content == null) {
+            listeners.warning(Resources.format(Resources.Keys.CanNotReadAuxiliaryFile_1, wld));
+            return null;
+        }
+        final String         filename = content.getFilename();
+        final CharSequence[] lines    = CharSequences.splitOnEOL(content);
+        final int            expected = 6;        // Expected number of elements.
+        int                  count    = 0;        // Actual number of elements.
+        final double[]       elements = new double[expected];
         for (int i=0; i<expected; i++) {
             final String line = lines[i].toString().trim();
             if (!line.isEmpty() && line.charAt(0) != '#') {
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreProviderTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreProviderTest.java
index 9a3e17c9e6..41a69d1e48 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreProviderTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/csv/StoreProviderTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.sis.internal.storage.csv;
 
+import org.apache.sis.setup.OptionKey;
+import org.apache.sis.setup.GeometryLibrary;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.ProbeResult;
@@ -29,7 +31,7 @@ import static org.junit.Assert.*;
  * Tests {@link StoreProvider}.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
  * @since   0.8
  * @module
  */
@@ -43,6 +45,7 @@ public final strictfp class StoreProviderTest extends TestCase {
     public void testProbeContent() throws DataStoreException {
         final StoreProvider p = new StoreProvider();
         final StorageConnector c = new StorageConnector(StoreTest.testData());
+        c.setOption(OptionKey.GEOMETRY_LIBRARY, GeometryLibrary.ESRI);
         assertEquals(ProbeResult.SUPPORTED, p.probeContent(c));
     }
 }


[sis] 01/02: `NumberFormatException` thrown when parsing an invalid code should be wrapped in a `NoSuchAuthorityCodeException`.

Posted by de...@apache.org.
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 a09032ea36c8bf76d16f2f166ac55669873c3600
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Fri Dec 9 15:01:51 2022 +0100

    `NumberFormatException` thrown when parsing an invalid code should be wrapped in a `NoSuchAuthorityCodeException`.
---
 .../referencing/factory/CommonAuthorityCode.java   | 10 ++++++-
 .../factory/CommonAuthorityFactory.java            | 35 +++++++++++-----------
 .../java/org/apache/sis/internal/util/Strings.java |  2 +-
 3 files changed, 27 insertions(+), 20 deletions(-)

diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityCode.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityCode.java
index 8aa66bd213..7c1650b78d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityCode.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityCode.java
@@ -117,7 +117,7 @@ final class CommonAuthorityCode {
         int end = CharSequences.skipTrailingWhitespaces(code, s, length);
         final int startOfParameters = code.indexOf(SEPARATOR, s);
         if (startOfParameters >= 0) {
-            complement = code.substring(startOfParameters + 1, end);
+            complement = code.substring(CharSequences.skipLeadingWhitespaces(code, startOfParameters + 1, end), end);
             end = CharSequences.skipTrailingWhitespaces(code, s, startOfParameters);
         }
         localCode = code.substring(s, end);
@@ -135,12 +135,20 @@ final class CommonAuthorityCode {
         return legacy ? (versionOfAuto == 1) : (versionOfAuto >= 1 && versionOfAuto <= 2);
     }
 
+    /**
+     * Returns whether there is no parameters.
+     */
+    final boolean isParameterless() {
+        return (complement == null) || complement.isEmpty();
+    }
+
     /**
      * Returns the result of parsing the comma-separated list of optional parameters after the code.
      * If there is no parameter, then this method returns an empty array.
      * Caller should not modify the returned array.
      *
      * @return the parameters after the code, or an empty array if none.
+     * @throws NumberFormatException if at least one number cannot be parsed.
      */
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
     final double[] parameters() {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
index fbb893350e..86c9907966 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/CommonAuthorityFactory.java
@@ -422,11 +422,11 @@ public class CommonAuthorityFactory extends GeodeticAuthorityFactory implements
     @Override
     public InternationalString getDescriptionText(final String code) throws FactoryException {
         final CommonAuthorityCode parsed = new CommonAuthorityCode(code);
-        if (parsed.isNumeric && parsed.parameters().length == 0) {
+        if (parsed.isNumeric && parsed.isParameterless()) {
             /*
              * For codes in the "AUTO(2)" namespace without parameters, we cannot rely on the default implementation
              * because it would fail to create the ProjectedCRS instance. Instead, we return a generic description.
-             * Note that we do not execute this block if parametes were specified. If there is parameters,
+             * Note that we do not execute this block if parametes were specified. If there are parameters,
              * then we instead rely on the default implementation for a more accurate description text.
              * Note also that we do not restrict to "AUTOx" namespaces because erroneous namespaces exist
              * in practice and the numerical codes are non-ambiguous (at least in current version).
@@ -498,26 +498,25 @@ public class CommonAuthorityFactory extends GeodeticAuthorityFactory implements
     private CoordinateReferenceSystem createCoordinateReferenceSystem(final String code, final CommonAuthorityCode parsed)
             throws FactoryException
     {
-        /*
-         * First, handled the case of non-numerical parameterless codes ("OGC:JulianDate", etc.)
-         * We accept also SIS-specific codes (e.g. "OGC:ModifiedJulianDate", "OGC:JavaTime") if
-         * the namespace is the more neutral "CRS" instead of "OGC". The SIS-specific codes are
-         * never listed in `getAuthorityCodes(…)`.
-         */
         final String localCode = parsed.localCode;
-        final double[] parameters = parsed.parameters();
-        if (!parsed.isNumeric && !parsed.isAuto(false) && parameters.length == 0) try {
-            return CommonCRS.Temporal.forIdentifier(localCode, parsed.isOGC).crs();
-        } catch (IllegalArgumentException e) {
-            throw noSuchAuthorityCode(localCode, code, e);
-        }
-        /*
-         * In current version, all non-temporal CRS have a numerical code.
-         */
+        final double[] parameters;
         final int codeValue;
         try {
+            parameters = parsed.parameters();
+            /*
+             * First, handled the case of non-numerical parameterless codes ("OGC:JulianDate", etc.)
+             * We accept also SIS-specific codes (e.g. "OGC:ModifiedJulianDate", "OGC:JavaTime") if
+             * the namespace is the more neutral "CRS" instead of "OGC". The SIS-specific codes are
+             * never listed in `getAuthorityCodes(…)`.
+             */
+            if (!parsed.isNumeric && !parsed.isAuto(false) && parameters.length == 0) {
+                return CommonCRS.Temporal.forIdentifier(localCode, parsed.isOGC).crs();
+            }
+            /*
+             * In current version, all non-temporal CRS have a numerical code.
+             */
             codeValue = Integer.parseInt(localCode);
-        } catch (NumberFormatException exception) {
+        } catch (IllegalArgumentException exception) {                  // Include `NumberFormatException`.
             throw noSuchAuthorityCode(localCode, code, exception);
         }
         /*
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Strings.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Strings.java
index 09bf00c464..1a94992f88 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Strings.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Strings.java
@@ -70,7 +70,7 @@ public final class Strings extends Static {
     }
 
     /**
-     * Returns the given text is non-null, or the empty string otherwise.
+     * Returns the given text if non-null, or the empty string otherwise.
      *
      * @param  text  text or null.
      * @return given text or empty string (never null).