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/14 19:22:39 UTC

[sis] branch geoapi-4.0 updated (7490457b36 -> fae2e06546)

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 7490457b36 Fix an exception when GeoTIFF metadata contains rational numbers.
     new 3301ebb61d Deprecate `CharSequences.trimWhitespaces(String)`, replaced by `String.strip()` in Java 11.
     new 56212495a0 Fix an integer overflow when the filename is the root directory or an empty path.
     new fae2e06546 Improve the error message when failing to open a connection on an AWS S3 bucket.

The 3 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:
 .../apache/sis/internal/gui/DataStoreOpener.java   |  7 +++--
 .../apache/sis/internal/gui/ExceptionReporter.java |  6 +++-
 .../apache/sis/cloud/aws/internal/Resources.java   |  5 ++++
 .../sis/cloud/aws/internal/Resources.properties    |  1 +
 .../sis/cloud/aws/internal/Resources_fr.properties |  1 +
 .../org/apache/sis/cloud/aws/s3/FileService.java   | 18 ++++++++++--
 .../java/org/apache/sis/cloud/aws/s3/KeyPath.java  |  6 ++--
 .../org/apache/sis/cloud/aws/s3/package-info.java  |  2 +-
 .../sis/internal/jaxb/gco/CharSequenceAdapter.java | 24 ++++++++--------
 .../org/apache/sis/internal/jaxb/lan/Country.java  |  6 ++--
 .../apache/sis/internal/metadata/Identifiers.java  | 33 +++++++++-------------
 .../internal/metadata/ImplementationHelper.java    |  5 ++--
 .../org/apache/sis/metadata/PropertyAccessor.java  |  3 +-
 .../sis/metadata/iso/citation/Citations.java       |  2 +-
 .../main/java/org/apache/sis/xml/NilReason.java    |  2 +-
 .../java/org/apache/sis/xml/ValueConverter.java    | 27 +++++++++---------
 .../apache/sis/test/xml/DocumentComparator.java    |  8 +++---
 .../gazetteer/MilitaryGridReferenceSystem.java     |  5 ++--
 .../org/apache/sis/geometry/CoordinateFormat.java  |  4 +--
 .../sis/internal/referencing/AxisDirections.java   |  2 +-
 .../main/java/org/apache/sis/io/wkt/Formatter.java |  4 +--
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |  5 ++--
 .../main/java/org/apache/sis/io/wkt/Symbols.java   |  6 ++--
 .../org/apache/sis/parameter/TensorValues.java     |  7 ++---
 .../sis/referencing/ImmutableIdentifier.java       | 15 ++++++----
 .../sis/referencing/cs/CoordinateSystems.java      |  5 ++--
 .../cs/DefaultCoordinateSystemAxis.java            | 28 ++++++++++--------
 .../factory/GeodeticAuthorityFactory.java          |  2 +-
 .../DefaultCoordinateOperationFactory.java         |  4 +--
 .../transform/DefaultMathTransformFactory.java     |  4 +--
 .../sis/internal/converter/StringConverter.java    |  6 ++--
 .../org/apache/sis/internal/util/CodeLists.java    |  8 +++---
 .../java/org/apache/sis/internal/util/Strings.java |  8 +++---
 .../java/org/apache/sis/internal/util/X364.java    |  3 +-
 .../main/java/org/apache/sis/io/DefaultFormat.java |  2 +-
 .../java/org/apache/sis/measure/UnitFormat.java    |  5 ++--
 .../java/org/apache/sis/util/CharSequences.java    |  3 +-
 .../main/java/org/apache/sis/util/Exceptions.java  |  4 +--
 .../src/main/java/org/apache/sis/util/Numbers.java |  4 +--
 .../src/main/java/org/apache/sis/util/Version.java |  2 +-
 .../sis/util/collection/DefaultTreeTable.java      |  5 ++--
 .../apache/sis/util/logging/MonolineFormatter.java |  2 +-
 .../org/apache/sis/util/CharSequencesTest.java     |  3 --
 .../sis/internal/storage/io/ChannelFactory.java    |  4 +--
 .../sis/internal/storage/io/IOUtilities.java       | 19 +++++++++----
 .../sis/internal/storage/io/package-info.java      |  2 +-
 .../org/apache/sis/storage/StorageConnector.java   | 11 ++++++--
 .../java/org/apache/sis/storage/package-info.java  |  2 +-
 .../sis/internal/storage/io/IOUtilitiesTest.java   |  4 ++-
 49 files changed, 187 insertions(+), 157 deletions(-)


[sis] 02/03: Fix an integer overflow when the filename is the root directory or an empty path.

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 56212495a059cc019f52fe39c5680124fa5ed3d1
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Dec 14 16:00:49 2022 +0100

    Fix an integer overflow when the filename is the root directory or an empty path.
---
 .../org/apache/sis/internal/storage/io/IOUtilities.java     | 13 ++++++++-----
 .../org/apache/sis/internal/storage/io/package-info.java    |  2 +-
 .../org/apache/sis/internal/storage/io/IOUtilitiesTest.java |  4 +++-
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
index 3df8039a40..fba5a3cd8d 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
@@ -59,7 +59,7 @@ import org.apache.sis.internal.storage.Resources;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   0.3
  * @module
  */
@@ -95,6 +95,7 @@ public final class IOUtilities extends Static {
      * instance. If the given argument is specialized type like {@code Path} or {@code File}, then this method uses
      * dedicated API like {@link Path#getFileName()}. Otherwise this method gets a string representation of the path
      * and returns the part after the last {@code '/'} or platform-dependent name separator character, if any.
+     * The returned string may be empty if the given path is empty or is the root directory.
      *
      * @param  path  the path as an instance of one of the above-cited types, or {@code null}.
      * @return the filename in the given path, or {@code null} if the given object is null or of unknown type.
@@ -149,13 +150,15 @@ public final class IOUtilities extends Static {
              */
             end = name.length();
             do {
-                fromIndex = name.lastIndexOf('/', --end) + 1;
+                if (--end < 0) return "";               // `end` is temporarily inclusive in this loop.
+                fromIndex = name.lastIndexOf('/', end);
                 if (separator != '/') {
                     // Search for platform-specific character only if the object is neither a URL or a URI.
-                    fromIndex = Math.max(fromIndex, CharSequences.lastIndexOf(name, separator, fromIndex, end+1) + 1);
+                    fromIndex = Math.max(fromIndex, name.lastIndexOf(separator, end));
                 }
-            } while (fromIndex > end);
-            end++;
+            } while (fromIndex == end);                 // Continue if '/' is the last character.
+            fromIndex++;                                // Character after the '/' separator.
+            end++;                                      // Make exclusive.
         }
         if (extension) {
             fromIndex = CharSequences.lastIndexOf(name, '.', fromIndex, end) + 1;
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java
index de0e699a69..c3f8ad2eae 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/package-info.java
@@ -24,7 +24,7 @@
  * may change in incompatible ways in any future version without notice.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   0.3
  * @module
  */
diff --git a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/IOUtilitiesTest.java b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/IOUtilitiesTest.java
index 4c2483388c..af7c998a7b 100644
--- a/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/IOUtilitiesTest.java
+++ b/storage/sis-storage/src/test/java/org/apache/sis/internal/storage/io/IOUtilitiesTest.java
@@ -35,7 +35,7 @@ import static org.junit.Assert.*;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Johann Sorel (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   0.3
  * @module
  */
@@ -53,6 +53,8 @@ public final strictfp class IOUtilitiesTest extends TestCase {
         assertEquals("Map.png", IOUtilities.filename(new URI ("file:/Users/name/Map.png")));
         assertEquals("Map.png", IOUtilities.filename(new URL ("file:/Users/name/Map.png")));
         assertEquals("name",    IOUtilities.filename(new URI ("file:/Users/name/")));
+        assertEquals("",        IOUtilities.filename("/"));
+        assertEquals("",        IOUtilities.filename(""));
         assertNull(IOUtilities.filename(Boolean.FALSE));
         assertNull(IOUtilities.filename(null));
     }


[sis] 03/03: Improve the error message when failing to open a connection on an AWS S3 bucket.

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 fae2e065467f5a89fccc9dd4c22065f6a79c29f3
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Dec 14 20:21:44 2022 +0100

    Improve the error message when failing to open a connection on an AWS S3 bucket.
---
 .../org/apache/sis/internal/gui/DataStoreOpener.java   |  7 +++++--
 .../org/apache/sis/internal/gui/ExceptionReporter.java |  6 +++++-
 .../org/apache/sis/cloud/aws/internal/Resources.java   |  5 +++++
 .../apache/sis/cloud/aws/internal/Resources.properties |  1 +
 .../sis/cloud/aws/internal/Resources_fr.properties     |  1 +
 .../java/org/apache/sis/cloud/aws/s3/FileService.java  | 18 ++++++++++++++++--
 .../main/java/org/apache/sis/cloud/aws/s3/KeyPath.java |  6 +++---
 .../java/org/apache/sis/cloud/aws/s3/package-info.java |  2 +-
 .../apache/sis/internal/storage/io/ChannelFactory.java |  4 ++--
 .../apache/sis/internal/storage/io/IOUtilities.java    |  6 ++++++
 .../java/org/apache/sis/storage/StorageConnector.java  | 11 ++++++++---
 .../main/java/org/apache/sis/storage/package-info.java |  2 +-
 12 files changed, 54 insertions(+), 15 deletions(-)

diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java
index 5eee24824c..ee57ad6dc2 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/DataStoreOpener.java
@@ -204,9 +204,12 @@ public final class DataStoreOpener extends Task<DataStore> {
         if (source instanceof StorageConnector) {
             return ((StorageConnector) source).getStorageName();
         }
-        String name = IOUtilities.filename(source);
+        String name = Strings.trimOrNull(IOUtilities.filename(source));
         if (name == null) {
-            name = Vocabulary.format(Vocabulary.Keys.Unknown);
+            name = Strings.trimOrNull(IOUtilities.toString(source));
+            if (name == null) {
+                name = Vocabulary.format(Vocabulary.Keys.Unknown);
+            }
         }
         return name;
     }
diff --git a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
index 42af7b15bf..b64d7b8f37 100644
--- a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
+++ b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/ExceptionReporter.java
@@ -293,7 +293,11 @@ public final class ExceptionReporter extends Widget {
             Platform.runLater(() -> show(owner, title, text, exception));
             return;
         }
-        String message = exception.getLocalizedMessage();
+        String message = null;
+        for (Throwable e = exception; e != null; e = e.getCause()) {
+            message = e.getLocalizedMessage();
+            if (message != null && !message.equalsIgnoreCase(text)) break;
+        }
         if (message == null) {
             message = Classes.getShortClassName(exception);
         }
diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
index a422154e41..f567e52c63 100644
--- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
+++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
@@ -71,6 +71,11 @@ public final class Resources extends IndexedResourceBundle {
          */
         public static final short FileSystemInitialized_2 = 4;
 
+        /**
+         * Invalid bucket name in “{0}”.
+         */
+        public static final short InvalidBucketName_1 = 8;
+
         /**
          * Missing {0,choice,0#public|1#secret} access key in “{1}” URI.
          */
diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties
index 5e0486617a..4fd28f876c 100644
--- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties
+++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.properties
@@ -22,6 +22,7 @@
 CanNotChangeToAbsolutePath        = Cannot change a relative path to an absolute path.
 EmptyPath                         = Empty path.
 FileSystemInitialized_2           = File system {0,choice,0#not|1#already} initialized for the \u201c{1}\u201d access key.
+InvalidBucketName_1               = Invalid bucket name in \u201c{0}\u201d.
 MissingAccessKey_2                = Missing {0,choice,0#public|1#secret} access key in \u201c{1}\u201d URI.
 MustBeAbsolutePath                = Specified path must be an absolute S3 path.
 MustHaveKeyComponent              = Specified path cannot be the root.
diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties
index 9086b8e853..110a56ad77 100644
--- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties
+++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.properties
@@ -27,6 +27,7 @@
 CanNotChangeToAbsolutePath        = Ne peut pas changer un chemin relatif en chemin absolu.
 EmptyPath                         = Le chemin est vide.
 FileSystemInitialized_2           = Le syst\u00e8me de fichier {0,choice,0#n\u2019a pas \u00e9t\u00e9|1#est d\u00e9j\u00e0} initialis\u00e9 pour la cl\u00e9 d\u2019acc\u00e8s \u00ab\u202f{1}\u202f\u00bb.
+InvalidBucketName_1               = Le nom du compartiment dans \u00ab\u202f{0}\u202f\u00bb est invalide.
 MissingAccessKey_2                = Il manque la cl\u00e9 d'acc\u00e8s {0,choice,0#publique|1#secr\u00e8te} dans l'URI \u00ab\u202f{1}\u202f\u00bb.
 MustBeAbsolutePath                = Le chemin sp\u00e9cifi\u00e9 doit \u00eatre un chemin S3 absolu.
 MustHaveKeyComponent              = Le chemin sp\u00e9cifi\u00e9 ne peut pas \u00eatre la racine.
diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java
index d1f7b63803..9b44d65de7 100644
--- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java
+++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/FileService.java
@@ -43,6 +43,7 @@ import java.nio.file.NotDirectoryException;
 import java.nio.file.AccessDeniedException;
 import java.nio.file.StandardOpenOption;
 import java.nio.file.attribute.BasicFileAttributeView;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.collection.Containers;
@@ -74,7 +75,7 @@ import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
  * instead of the data to access, and can be a global configuration for the server.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   1.2
  * @module
  */
@@ -290,7 +291,20 @@ public class FileService extends FileSystemProvider {
             // TODO: we may need a way to get password here.
             fs = fileSystems.computeIfAbsent(accessKey, (key) -> new ClientFileSystem(FileService.this, null, key, null, null));
         }
-        return new KeyPath(fs, uri.getHost(), new String[] {uri.getPath()}, true);
+        String host = uri.getHost();
+        if (host == null) {
+            /*
+             * The host is null if the authority contains characters that are invalid for a host name.
+             * For example if the host contains underscore character ('_'), then it is considered invalid.
+             * We could use the authority instead, but that authority may contain a user name, port number, etc.
+             * Current version do not try to parse that string.
+             */
+            host = uri.getAuthority();
+            if (host == null) host = uri.toString();
+            throw new IllegalArgumentException(Resources.format(Resources.Keys.InvalidBucketName_1, host));
+        }
+        final String path = uri.getPath();
+        return new KeyPath(fs, host, (path != null) ? new String[] {path} : CharSequences.EMPTY_ARRAY, true);
     }
 
     /**
diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java
index 87e10e774e..117c33a966 100644
--- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java
+++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/KeyPath.java
@@ -48,7 +48,7 @@ import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
  * The interpretation of {@link ClientFileSystem#separator} as a path separator is done by this class.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   1.2
  * @module
  */
@@ -338,8 +338,8 @@ final class KeyPath implements Path {
     /**
      * Returns a new path with the same file system than this path.
      */
-    private KeyPath newPath(final String path) {
-        return new KeyPath(fs, path, CharSequences.EMPTY_ARRAY, false);
+    private KeyPath newPath(final String other) {
+        return new KeyPath(fs, Objects.requireNonNull(other, "other"), CharSequences.EMPTY_ARRAY, false);
     }
 
     /**
diff --git a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java
index ba209f9fcb..92e86f5e6f 100644
--- a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java
+++ b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/s3/package-info.java
@@ -49,7 +49,7 @@
  * All classes provided by this package are safe of usage in multi-threading environment.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  *
  * @see <a href="https://sdk.amazonaws.com/java/api/latest/index.html">AWS SDK for Java</a>
  *
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
index 117f4035a4..943a8fe371 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelFactory.java
@@ -230,8 +230,8 @@ public abstract class ChannelFactory {
                 try {
                     storage = uri.toURL();
                 } catch (MalformedURLException ioe) {
-                    ioe.addSuppressed(e);
-                    throw ioe;
+                    e.addSuppressed(ioe);
+                    throw e;
                 }
                 /*
                  * We have been able to convert to URL, but the given OpenOptions may not be used.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
index fba5a3cd8d..60616119ad 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/IOUtilities.java
@@ -99,6 +99,9 @@ public final class IOUtilities extends Static {
      *
      * @param  path  the path as an instance of one of the above-cited types, or {@code null}.
      * @return the filename in the given path, or {@code null} if the given object is null or of unknown type.
+     *
+     * @see #extension(Object)
+     * @see #toString(Object)
      */
     public static String filename(final Object path) {
         return part(path, false);
@@ -176,6 +179,9 @@ public final class IOUtilities extends Static {
      *
      * @param  path  the path for which to return a string representation.
      * @return the string representation, or {@code null} if none.
+     *
+     * @see #filename(Object)
+     * @see #extension(Object)
      */
     public static String toString(final Object path) {
         /*
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 b5c6ea837d..0765ebb80e 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
@@ -100,7 +100,7 @@ import org.apache.sis.setup.OptionKey;
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Alexis Manin (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   0.3
  * @module
  */
@@ -227,6 +227,8 @@ public class StorageConnector implements Serializable {
     /**
      * A name for the input/output object, or {@code null} if none.
      * This field is initialized only when first needed.
+     *
+     * @see #getStorageName()
      */
     private transient String name;
 
@@ -639,9 +641,12 @@ public class StorageConnector implements Serializable {
      */
     public String getStorageName() {
         if (name == null) {
-            name = IOUtilities.filename(storage);
+            name = Strings.trimOrNull(IOUtilities.filename(storage));
             if (name == null) {
-                name = Classes.getShortClassName(storage);
+                name = Strings.trimOrNull(IOUtilities.toString(storage));
+                if (name == null) {
+                    name = Classes.getShortClassName(storage);
+                }
             }
         }
         return name;
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java b/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java
index e70c106729..b2be40c355 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/storage/package-info.java
@@ -26,7 +26,7 @@
  *
  * @author  Johann Sorel (Geomatys)
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   0.3
  * @module
  */


[sis] 01/03: Deprecate `CharSequences.trimWhitespaces(String)`, replaced by `String.strip()` in Java 11.

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 3301ebb61d37a43636a2ffcf4f681311c7181332
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Dec 14 12:08:30 2022 +0100

    Deprecate `CharSequences.trimWhitespaces(String)`, replaced by `String.strip()` in Java 11.
---
 .../sis/internal/jaxb/gco/CharSequenceAdapter.java | 24 ++++++++--------
 .../org/apache/sis/internal/jaxb/lan/Country.java  |  6 ++--
 .../apache/sis/internal/metadata/Identifiers.java  | 33 +++++++++-------------
 .../internal/metadata/ImplementationHelper.java    |  5 ++--
 .../org/apache/sis/metadata/PropertyAccessor.java  |  3 +-
 .../sis/metadata/iso/citation/Citations.java       |  2 +-
 .../main/java/org/apache/sis/xml/NilReason.java    |  2 +-
 .../java/org/apache/sis/xml/ValueConverter.java    | 27 +++++++++---------
 .../apache/sis/test/xml/DocumentComparator.java    |  8 +++---
 .../gazetteer/MilitaryGridReferenceSystem.java     |  5 ++--
 .../org/apache/sis/geometry/CoordinateFormat.java  |  4 +--
 .../sis/internal/referencing/AxisDirections.java   |  2 +-
 .../main/java/org/apache/sis/io/wkt/Formatter.java |  4 +--
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |  5 ++--
 .../main/java/org/apache/sis/io/wkt/Symbols.java   |  6 ++--
 .../org/apache/sis/parameter/TensorValues.java     |  7 ++---
 .../sis/referencing/ImmutableIdentifier.java       | 15 ++++++----
 .../sis/referencing/cs/CoordinateSystems.java      |  5 ++--
 .../cs/DefaultCoordinateSystemAxis.java            | 28 ++++++++++--------
 .../factory/GeodeticAuthorityFactory.java          |  2 +-
 .../DefaultCoordinateOperationFactory.java         |  4 +--
 .../transform/DefaultMathTransformFactory.java     |  4 +--
 .../sis/internal/converter/StringConverter.java    |  6 ++--
 .../org/apache/sis/internal/util/CodeLists.java    |  8 +++---
 .../java/org/apache/sis/internal/util/Strings.java |  8 +++---
 .../java/org/apache/sis/internal/util/X364.java    |  3 +-
 .../main/java/org/apache/sis/io/DefaultFormat.java |  2 +-
 .../java/org/apache/sis/measure/UnitFormat.java    |  5 ++--
 .../java/org/apache/sis/util/CharSequences.java    |  3 +-
 .../main/java/org/apache/sis/util/Exceptions.java  |  4 +--
 .../src/main/java/org/apache/sis/util/Numbers.java |  4 +--
 .../src/main/java/org/apache/sis/util/Version.java |  2 +-
 .../sis/util/collection/DefaultTreeTable.java      |  5 ++--
 .../apache/sis/util/logging/MonolineFormatter.java |  2 +-
 .../org/apache/sis/util/CharSequencesTest.java     |  3 --
 35 files changed, 121 insertions(+), 135 deletions(-)

diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java
index a4255e137f..59acb9c3ae 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/CharSequenceAdapter.java
@@ -21,6 +21,7 @@ import org.opengis.util.InternationalString;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.xml.XLink;
 import org.apache.sis.xml.ReferenceResolver;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.jaxb.gcx.Anchor;
@@ -118,8 +119,8 @@ public class CharSequenceAdapter extends XmlAdapter<GO_CharacterString, CharSequ
          * Substitute <gco:CharacterString> by <gcx:Anchor> if a linkage is found.
          */
         if (!(value instanceof Anchor)) {
-            final String key = CharSequences.trimWhitespaces(value.toString());
-            if (key != null && !key.isEmpty()) {
+            final String key = Strings.trimOrNull(value.toString());
+            if (key != null) {
                 final Context context = Context.current();
                 final XLink linkage = Context.resolver(context).anchor(context, value, key);
                 if (linkage != null) {
@@ -169,16 +170,15 @@ public class CharSequenceAdapter extends XmlAdapter<GO_CharacterString, CharSequ
      * @return the text value for the given character sequence, or {@code null}.
      */
     public static CharSequence value(final Context context, final Object object, String string) {
-        string = CharSequences.trimWhitespaces(string);
-        if (string == null || string.isEmpty()) {
-            return null;
-        }
-        final XLink linkage = Context.resolver(context).anchor(context, object, string);
-        if (linkage != null) {
-            if (linkage instanceof Anchor) {
-                return (Anchor) linkage;
-            } else {
-                return new Anchor(linkage, string);
+        string = Strings.trimOrNull(string);
+        if (string != null) {
+            final XLink linkage = Context.resolver(context).anchor(context, object, string);
+            if (linkage != null) {
+                if (linkage instanceof Anchor) {
+                    return (Anchor) linkage;
+                } else {
+                    return new Anchor(linkage, string);
+                }
             }
         }
         return string;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/Country.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/Country.java
index d45a2a0df7..f38c840d26 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/Country.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/lan/Country.java
@@ -26,6 +26,7 @@ import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.xml.LegacyNamespaces;
 import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
 import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.util.resources.Errors;
 
 
@@ -185,8 +186,9 @@ public final class Country extends GO_CharacterString {
         }
         if (country != null) {
             final CodeListUID identifier = country.identifier;
-            final String c = CharSequences.trimWhitespaces((identifier != null ? identifier : country).toString());
-            if (c != null && !c.isEmpty()) {
+            // Note: `CodeListUID.toString()` and `Country.toString()` may return null.
+            final String c = Strings.trimOrNull((identifier != null ? identifier : country).toString());
+            if (c != null) {
                 if (code == null) {
                     code = "";
                 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Identifiers.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Identifiers.java
index b7a6a4e98d..c44e16b01e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Identifiers.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Identifiers.java
@@ -20,6 +20,7 @@ import java.util.Locale;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.util.InternationalString;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.metadata.iso.citation.Citations;
@@ -34,7 +35,7 @@ import org.apache.sis.util.resources.Errors;
  * Methods working on {@link Identifier} instances.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @since   1.2
+ * @since   1.4
  * @version 1.0
  * @module
  */
@@ -74,12 +75,11 @@ public final class Identifiers extends Static {
 
     /**
      * Returns a "unlocalized" string representation of the given international string, or {@code null} if none
-     * or if the string is deprecated. This method is used by {@link #getIdentifier(Citation, boolean)}, which
-     * is why we don't want the localized string.
+     * or if the string is deprecated or empty. This method is used by {@link #getIdentifier(Citation, boolean)},
+     * which is why we don't want the localized string.
      */
-    private static String toString(final InternationalString title) {
-        return (title != null && !isDeprecated(title))
-               ? CharSequences.trimWhitespaces(title.toString(Locale.ROOT)) : null;
+    private static String trimOrNull(final InternationalString title) {
+        return (title != null && !isDeprecated(title)) ? Strings.trimOrNull(title.toString(Locale.ROOT)) : null;
     }
 
     /**
@@ -116,16 +116,15 @@ public final class Identifiers extends Static {
             String codeSpace  = null;       // Code space of the identifier, or null if none.
             for (final Identifier id : CollectionsExt.nonNull(citation.getIdentifiers())) {
                 if (id != null && !isDeprecated(id)) {
-                    final String candidate = CharSequences.trimWhitespaces(id.getCode());
-                    if (candidate != null && !candidate.isEmpty()) {
+                    final String candidate = Strings.trimOrNull(id.getCode());
+                    if (candidate != null) {
                         /*
                          * For a non-empty identifier, verify if both the code and its codespace are valid
                          * Unicode identifiers. If a codespace exists, then the code does not need to begin
                          * with a "Unicode identifier start" (it may be a "Unicode identifier part").
                          */
-                        String cs = CharSequences.trimWhitespaces(id.getCodeSpace());
-                        if (cs == null || cs.isEmpty()) {
-                            cs = null;
+                        final String cs = Strings.trimOrNull(id.getCodeSpace());
+                        if (cs == null) {
                             isUnicode = CharSequences.isUnicodeIdentifier(candidate);
                         } else {
                             isUnicode = CharSequences.isUnicodeIdentifier(cs);
@@ -163,18 +162,14 @@ public final class Identifiers extends Static {
              * which are typically alternate titles.
              */
             if (identifier == null) {
-                identifier = toString(citation.getTitle());     // Whitepaces removed by toString(…).
+                identifier = trimOrNull(citation.getTitle());       // Whitepaces removed by trimOrNull(…).
                 if (identifier != null) {
-                    if (identifier.isEmpty()) {
-                        identifier = null;
-                    } else {
-                        isUnicode = CharSequences.isUnicodeIdentifier(identifier);
-                    }
+                    isUnicode = CharSequences.isUnicodeIdentifier(identifier);
                 }
                 if (!isUnicode) {
                     for (final InternationalString i18n : CollectionsExt.nonNull(citation.getAlternateTitles())) {
-                        final String candidate = toString(i18n);
-                        if (candidate != null && !candidate.isEmpty()) {
+                        final String candidate = trimOrNull(i18n);
+                        if (candidate != null) {
                             isUnicode = CharSequences.isUnicodeIdentifier(candidate);
                             if (identifier == null || isUnicode) {
                                 identifier = candidate;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ImplementationHelper.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ImplementationHelper.java
index 417a67c9ef..a941c2a1d2 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ImplementationHelper.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ImplementationHelper.java
@@ -25,7 +25,6 @@ import org.apache.sis.xml.NilReason;
 import org.apache.sis.xml.IdentifierSpace;
 import org.apache.sis.xml.IdentifiedObject;
 import org.apache.sis.util.Static;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.util.Strings;
@@ -287,8 +286,8 @@ public final class ImplementationHelper extends Static {
      * @since 0.7
      */
     public static void setObjectID(final IdentifiedObject object, String id) {
-        id = CharSequences.trimWhitespaces(id);
-        if (id != null && !id.isEmpty()) {
+        id = Strings.trimOrNull(id);
+        if (id != null) {
             object.getIdentifierMap().putSpecialized(IdentifierSpace.ID, id);
             final Context context = Context.current();
             if (!Context.setObjectForID(context, object, id)) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
index cd2825b9cf..0ea2d55f13 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyAccessor.java
@@ -510,8 +510,7 @@ class PropertyAccessor {
              * most of the time the key name will have exactly the expected case and using
              * directly the given String instance allow usage of its cached hash code value.
              */
-            final String key = CharSequences.trimWhitespaces(
-                    CharSequences.replace(name, " ", "").toString().toLowerCase(Locale.ROOT));
+            final String key = CharSequences.replace(name, " ", "").toString().toLowerCase(Locale.ROOT).strip();
             if (key == name || (index = mapping.get(key)) == null) { // Identity comparison is okay here.
                 if (!mandatory) {
                     return -1;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java
index 515e2ca673..7c3e5aa5ac 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/Citations.java
@@ -507,7 +507,7 @@ public final class Citations extends Static {
      * @return a citation using the specified name, or {@code null} if the given title is null or empty.
      */
     public static Citation fromName(String identifier) {
-        if (identifier == null || ((identifier = CharSequences.trimWhitespaces(identifier)).isEmpty())) {
+        if (identifier == null || ((identifier = identifier.strip()).isEmpty())) {
             return null;
         }
         for (final CitationConstant citation : CITATIONS) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/NilReason.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/NilReason.java
index b9f13c9903..ab13c6e894 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/NilReason.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/NilReason.java
@@ -227,7 +227,7 @@ public final class NilReason implements Serializable {
      *         values and cannot be parsed as a URI.
      */
     public static NilReason valueOf(String reason) throws URISyntaxException {
-        reason = CharSequences.trimWhitespaces(reason);
+        reason = reason.strip();
         int i = reason.indexOf(':');
         if (i < 0) {
             for (final NilReason candidate : PREDEFINED) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
index 420e05cbc5..72404ba57e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/ValueConverter.java
@@ -28,11 +28,10 @@ import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
 import javax.measure.Unit;
 import javax.measure.format.ParserException;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.Locales;
 
-import static org.apache.sis.util.CharSequences.trimWhitespaces;
-
 
 /**
  * Performs conversions of XML element or attribute values encountered during XML (un)marshalling.
@@ -262,8 +261,8 @@ public class ValueConverter {
      * @see Locales#parse(String)
      */
     public Locale toLocale(final MarshalContext context, String value) throws IllformedLocaleException {
-        value = trimWhitespaces(value);
-        if (value != null && !value.isEmpty()) try {
+        value = Strings.trimOrNull(value);
+        if (value != null) try {
             return Locales.parse(value);
         } catch (IllformedLocaleException e) {
             if (!exceptionOccured(context, value, String.class, Locale.class, e)) {
@@ -289,8 +288,8 @@ public class ValueConverter {
      * @since 0.5
      */
     public Charset toCharset(final MarshalContext context, String value) throws IllegalCharsetNameException {
-        value = trimWhitespaces(value);
-        if (value != null && !value.isEmpty()) {
+        value = Strings.trimOrNull(value);
+        if (value != null) {
             value = LegacyCodes.toIANA(value);
             try {
                 return Charset.forName(value);
@@ -324,8 +323,8 @@ public class ValueConverter {
      * @see Units#valueOf(String)
      */
     public Unit<?> toUnit(final MarshalContext context, String value) throws IllegalArgumentException {
-        value = trimWhitespaces(value);
-        if (value != null && !value.isEmpty()) try {
+        value = Strings.trimOrNull(value);
+        if (value != null) try {
             /*
              * First, check for X-Paths like below:
              *
@@ -383,8 +382,8 @@ public class ValueConverter {
      * @see UUID#fromString(String)
      */
     public UUID toUUID(final MarshalContext context, String value) throws IllegalArgumentException {
-        value = trimWhitespaces(value);
-        if (value != null && !value.isEmpty()) try {
+        value = Strings.trimOrNull(value);
+        if (value != null) try {
             return UUID.fromString(value);
         } catch (IllegalArgumentException e) {
             if (!exceptionOccured(context, value, String.class, UUID.class, e)) {
@@ -412,8 +411,8 @@ public class ValueConverter {
      * @see URI#URI(String)
      */
     public URI toURI(final MarshalContext context, String value) throws URISyntaxException {
-        value = trimWhitespaces(value);
-        if (value != null && !value.isEmpty()) try {
+        value = Strings.trimOrNull(value);
+        if (value != null) try {
             return new URI(value);
         } catch (URISyntaxException e) {
             if (!exceptionOccured(context, value, String.class, URI.class, e)) {
@@ -497,8 +496,8 @@ public class ValueConverter {
      * @see NilReason#valueOf(String)
      */
     public NilReason toNilReason(final MarshalContext context, String value) throws URISyntaxException {
-        value = trimWhitespaces(value);
-        if (value != null && !value.isEmpty()) try {
+        value = Strings.trimOrNull(value);
+        if (value != null) try {
             return NilReason.valueOf(value);
         } catch (URISyntaxException e) {
             if (!exceptionOccured(context, value, String.class, URI.class, e)) {
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java
index df52743a0e..88c8130dfe 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/DocumentComparator.java
@@ -44,12 +44,12 @@ import org.w3c.dom.Text;
 import org.xml.sax.SAXException;
 import org.apache.sis.xml.Namespaces;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.internal.xml.LegacyNamespaces;
 
 import static java.lang.StrictMath.*;
 import static org.opengis.test.Assert.*;
 import static org.apache.sis.util.Characters.NO_BREAK_SPACE;
-import static org.apache.sis.util.CharSequences.trimWhitespaces;
 
 
 /**
@@ -590,8 +590,8 @@ public strictfp class DocumentComparator {
 
                     // For text node, continue the search if the node is empty.
                     case Node.TEXT_NODE: {
-                        final String text = trimWhitespaces(node.getTextContent());
-                        if (text == null || text.isEmpty()) {
+                        final String text = Strings.trimOrNull(node.getTextContent());
+                        if (text == null) {
                             continue;
                         }
                         break;
@@ -658,7 +658,7 @@ public strictfp class DocumentComparator {
      * if it is actually a {@link String} object.
      */
     private static Comparable<?> trim(final Comparable<?> property) {
-        return (property instanceof String) ? trimWhitespaces(((String) property)) : property;
+        return (property instanceof String) ? (((String) property)).strip() : property;
     }
 
     /**
diff --git a/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
index d80d5ca66d..1f0575558f 100644
--- a/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
+++ b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/referencing/gazetteer/MilitaryGridReferenceSystem.java
@@ -612,9 +612,8 @@ public class MilitaryGridReferenceSystem extends ReferencingByIdentifiers {
          * @param  separator  the separator to insert between each component of the MGRS identifier.
          */
         public void setSeparator(final String separator) {
-            ArgumentChecks.ensureNonNull("separator", separator);
-            this.separator = separator;
-            trimmedSeparator = CharSequences.trimWhitespaces(separator);
+            trimmedSeparator = separator.strip();       // Implicit null check.
+            this.separator   = separator;
         }
 
         /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java b/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
index ebd28b8b9d..116378e4e8 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
@@ -457,7 +457,7 @@ public class CoordinateFormat extends CompoundFormat<DirectPosition> {
     public void setSeparator(final String separator) {
         ArgumentChecks.ensureNonEmpty("separator", separator);
         this.separator = separator;
-        parseSeparator = CharSequences.trimWhitespaces(separator);
+        parseSeparator = separator.strip();
     }
 
     /**
@@ -1852,6 +1852,6 @@ checkDirection: if (direction != null) {
      * @throws ClassNotFoundException if the class serialized on the stream is not on the classpath.
      */
     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
-        parseSeparator = CharSequences.trimWhitespaces(separator);
+        parseSeparator = separator.strip();
     }
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
index e85dbdc805..5ce539a3ba 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
@@ -654,7 +654,7 @@ next:       for (int i=0; i <= limit; i++) {
      * @return the first axis direction having a name matching the given one, or {@code null} if none.
      */
     public static AxisDirection valueOf(String name) {
-        name = trimWhitespaces(name.replace('_', ' '));
+        name = name.replace('_', ' ').strip();
         final AxisDirection[] directions = AxisDirection.values();
         AxisDirection candidate = find(name, directions);
         if (candidate == null) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
index 02d8863e5a..8ac4b233fa 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Formatter.java
@@ -1039,8 +1039,8 @@ public class Formatter implements Localized {
     private void appendOnNewLine(final String keyword, final InternationalString text, final ElementKind type) {
         ArgumentChecks.ensureNonNull("keyword", keyword);
         if (text != null) {
-            final String localized = CharSequences.trimWhitespaces(text.toString(locale));
-            if (localized != null && !localized.isEmpty()) {
+            String localized = text.toString(locale);
+            if (localized != null && !(localized = localized.strip()).isEmpty()) {
                 openElement(true, keyword);
                 quote(localized, type);
                 closeElement(true);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
index 2efac7146e..8185465657 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@ -84,7 +84,6 @@ import org.apache.sis.internal.referencing.WKTKeywords;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.Strings;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.Types;
 
@@ -1057,8 +1056,8 @@ class GeodeticObjectParser extends MathTransformParser implements Comparator<Coo
                 }
                 start = c;
             }
-            abbreviation = CharSequences.trimWhitespaces(name.substring(start + 1, end));
-            name = CharSequences.trimWhitespaces(name.substring(0, start));
+            abbreviation = name.substring(start + 1, end).strip();
+            name = name.substring(0, start).strip();
             if (name.isEmpty()) {
                 name = abbreviation;
             }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
index 46dfffd574..dc5cc5735e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/Symbols.java
@@ -541,10 +541,8 @@ public class Symbols implements Localized, Cloneable, Serializable {
      */
     public void setSeparator(final String separator) {
         checkWritePermission();
-        final String s = CharSequences.trimWhitespaces(separator.trim());
-        ensureNonEmpty("separator", s);
+        ensureNonEmpty("separator", trimmedSeparator = separator.trim().strip());
         this.separator = separator;
-        trimmedSeparator = s;
     }
 
     /**
@@ -766,7 +764,7 @@ public class Symbols implements Localized, Cloneable, Serializable {
             if (equals(CURLY_BRACKETS))  return CURLY_BRACKETS;
         }
         quote = String.valueOf(Character.toChars(quotes[1]));
-        trimmedSeparator = CharSequences.trimWhitespaces(separator.trim());
+        trimmedSeparator = separator.trim().strip();
         return this;
     }
 }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
index 11b1e2eb86..9aec609956 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
@@ -41,7 +41,6 @@ import org.apache.sis.internal.util.UnmodifiableArrayList;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.Classes;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
@@ -201,8 +200,7 @@ final class TensorValues<E> extends AbstractParameterDescriptor
      */
     @Override
     public GeneralParameterDescriptor descriptor(String name) throws ParameterNotFoundException {
-        name = CharSequences.trimWhitespaces(name);
-        ArgumentChecks.ensureNonEmpty("name", name);
+        ArgumentChecks.ensureNonEmpty("name", name = name.strip());
         return descriptors.descriptor(this, name, size());
     }
 
@@ -215,8 +213,7 @@ final class TensorValues<E> extends AbstractParameterDescriptor
      */
     @Override
     public ParameterValue<?> parameter(String name) throws ParameterNotFoundException {
-        name = CharSequences.trimWhitespaces(name);
-        ArgumentChecks.ensureNonEmpty("name", name);
+        ArgumentChecks.ensureNonEmpty("name", name = name.strip());
         IllegalArgumentException cause = null;
         int[] indices = null;
         try {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java
index ee541e083a..7b7fff59c9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/ImmutableIdentifier.java
@@ -31,13 +31,13 @@ import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.internal.metadata.Identifiers;
 import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.referencing.WKTKeywords;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.io.wkt.ElementKind;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
-import static org.apache.sis.util.CharSequences.trimWhitespaces;
 import static org.apache.sis.util.collection.Containers.property;
 
 
@@ -122,6 +122,7 @@ public class ImmutableIdentifier extends FormattableObject implements Identifier
      *
      * @see #getAuthority()
      */
+    @SuppressWarnings("serial")         // Not statically typed as Serializable.
     private final Citation authority;
 
     /**
@@ -151,6 +152,7 @@ public class ImmutableIdentifier extends FormattableObject implements Identifier
     /**
      * Natural language description of the meaning of the code value.
      */
+    @SuppressWarnings("serial")         // Not statically typed as Serializable.
     private final InternationalString description;
 
     /**
@@ -265,8 +267,8 @@ public class ImmutableIdentifier extends FormattableObject implements Identifier
      */
     public ImmutableIdentifier(final Map<String,?> properties) throws IllegalArgumentException {
         ensureNonNull("properties", properties);
-        code        = trimWhitespaces(  property (properties, CODE_KEY,    String.class));
-        version     = trimWhitespaces(  property (properties, VERSION_KEY, String.class));
+        code        = Strings.trimOrNull(property(properties, CODE_KEY,    String.class));
+        version     = Strings.trimOrNull(property(properties, VERSION_KEY, String.class));
         description = Types.toInternationalString(properties, DESCRIPTION_KEY);
         /*
          * Map String authority to one of the predefined constants (typically EPSG or OGC).
@@ -289,7 +291,7 @@ public class ImmutableIdentifier extends FormattableObject implements Identifier
         if (value == null) {
             codeSpace = Citations.toCodeSpace(authority);
         } else if (value instanceof String) {
-            codeSpace = trimWhitespaces((String) value);
+            codeSpace = Strings.trimOrNull((String) value);
         } else {
             throw illegalPropertyType(properties, CODESPACE_KEY, value);
         }
@@ -301,9 +303,10 @@ public class ImmutableIdentifier extends FormattableObject implements Identifier
      */
     private void validate(final Map<String,?> properties) {
         if (code == null || code.isEmpty()) {
+            boolean missing = (code == null) || (properties != null && properties.get(CODE_KEY) == null);
             throw new IllegalArgumentException(Errors.getResources(properties)
-                    .getString((code == null) ? Errors.Keys.MissingValueForProperty_1
-                                              : Errors.Keys.EmptyProperty_1, CODE_KEY));
+                    .getString(missing ? Errors.Keys.MissingValueForProperty_1
+                                       : Errors.Keys.EmptyProperty_1, CODE_KEY));
         }
     }
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
index 31120f94a1..f259026dac 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
@@ -39,7 +39,6 @@ import org.apache.sis.measure.ElevationAngle;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Classes;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.NullArgumentException;
 import org.apache.sis.util.logging.Logging;
@@ -104,8 +103,8 @@ public final class CoordinateSystems extends Static {
      * @throws IllegalArgumentException if the given name is not a known axis direction.
      */
     public static AxisDirection parseAxisDirection(String name) throws IllegalArgumentException {
-        ArgumentChecks.ensureNonNull("name", name);
-        name = CharSequences.trimWhitespaces(name);
+        ArgumentChecks.ensureNonEmpty("name", name);
+        name = name.strip();
         AxisDirection candidate = AxisDirections.valueOf(name);
         if (candidate != null) {
             return candidate;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
index f3a3555422..d75f6e9690 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java
@@ -59,7 +59,6 @@ import static java.lang.Double.doubleToLongBits;
 import static java.lang.Double.NEGATIVE_INFINITY;
 import static java.lang.Double.POSITIVE_INFINITY;
 import static org.apache.sis.util.ArgumentChecks.*;
-import static org.apache.sis.util.CharSequences.trimWhitespaces;
 import static org.apache.sis.util.collection.Containers.property;
 
 /*
@@ -154,6 +153,13 @@ public class DefaultCoordinateSystemAxis extends AbstractIdentifiedObject implem
      * Do not add aliases for "x" and "y" in this map. See ALIASES_XY for more information.
      */
 
+    /**
+     * Returns a value of {@link #ALIASES} map for the given axis name.
+     */
+    private static Object getAliasType(final String name) {
+        return ALIASES.get(name.strip().toLowerCase(Locale.US));   // Our ALIASES are in English.
+    }
+
     /**
      * Aliases for the "x" and "y" abbreviations (special cases). "x" and "y" are sometimes used (especially in WKT)
      * for meaning "Easting" and "Northing". However, we shall not add "x" and "y" as aliases in the {@link #ALIASES}
@@ -522,12 +528,12 @@ public class DefaultCoordinateSystemAxis extends AbstractIdentifiedObject implem
         }
         /*
          * The standard comparisons didn't worked. Check for the aliases. Note: we don't test
-         * for  'isHeuristicMatchForNameXY(...)'  here because the "x" and "y" axis names are
-         * too generic.  We test them only in the 'equals' method, which has the extra-safety
+         * for `isHeuristicMatchForNameXY(…)` here because the "x" and "y" axis names are too
+         * generic. We test them only in the `equals(…)` method, which has the extra-safety
          * of units comparison (so less risk to treat incompatible axes as equivalent).
          */
-        final Object type = ALIASES.get(trimWhitespaces(name).toLowerCase(Locale.US)); // Our ALIASES are in English.
-        return (type != null) && (type == ALIASES.get(trimWhitespaces(getName().getCode()).toLowerCase(Locale.US)));
+        final Object type = getAliasType(name);
+        return (type != null) && (type == getAliasType(getName().getCode()));
     }
 
     /**
@@ -541,11 +547,11 @@ public class DefaultCoordinateSystemAxis extends AbstractIdentifiedObject implem
      *         (depending on the {@code xy} value), or {@code false} otherwise.
      */
     private static boolean isHeuristicMatchForNameXY(String xy, String name) {
-        xy = trimWhitespaces(xy);
+        xy = xy.strip();
         if (xy.length() == 1) {
             int i = Character.toLowerCase(xy.charAt(0)) - 'x';
             if (i >= 0 && i <= 1) {
-                name = trimWhitespaces(name);
+                name = name.strip();
                 if (!name.isEmpty()) do {
                     if (name.regionMatches(true, 0, ALIASES_XY[i], 0, name.length())) {
                         return true;
@@ -644,7 +650,7 @@ public class DefaultCoordinateSystemAxis extends AbstractIdentifiedObject implem
              *
              * Note: there is no need to execute this block if metadata are not ignored,
              *       because in this case a stricter check has already been performed by
-             *       the 'equals' method in the superclass.
+             *       the `equals(…)` method in the superclass.
              */
             final String thatCode = name.getCode();
             if (!isHeuristicMatchForName(thatCode)) {
@@ -653,8 +659,8 @@ public class DefaultCoordinateSystemAxis extends AbstractIdentifiedObject implem
                     /*
                      * The above test checked for special cases ("Lat" / "Lon" aliases, etc.).
                      * The next line may repeat the same check, so we may have a partial waste
-                     * of CPU.   But we do it anyway for checking the 'that' aliases, and also
-                     * because the user may have overridden 'that.isHeuristicMatchForName(…)'.
+                     * of CPU. But we do it anyway for checking the `that` aliases, and also
+                     * because the user may have overridden `that.isHeuristicMatchForName(…)`.
                      */
                     final String thisCode = name.getCode();
                     if (!IdentifiedObjects.isHeuristicMatchForName(that, thisCode)) {
@@ -878,7 +884,7 @@ public class DefaultCoordinateSystemAxis extends AbstractIdentifiedObject implem
         maximumValue = POSITIVE_INFINITY;
         /*
          * Direction and unit of measurement are mandatory for SIS working. We do not verify their presence here
-         * because the verification would have to be done in an 'afterMarshal(…)' method and throwing an exception
+         * because the verification would have to be done in an `afterMarshal(…)` method and throwing an exception
          * in that method causes the whole unmarshalling to fail. But the CD_CoordinateSystemAxis adapter does some
          * verifications.
          */
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
index 80569e125f..4707dff821 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
@@ -1289,7 +1289,7 @@ public abstract class GeodeticAuthorityFactory extends AbstractFactory implement
                 }
             }
         }
-        return CharSequences.trimWhitespaces(code);
+        return code.strip();
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index b49c6b475a..5aa369fa38 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -54,7 +54,6 @@ import org.apache.sis.util.collection.Cache;
 import org.apache.sis.util.iso.AbstractFactory;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.NullArgumentException;
 import org.apache.sis.util.Utilities;
@@ -278,8 +277,7 @@ public class DefaultCoordinateOperationFactory extends AbstractFactory implement
      */
     @Override
     public OperationMethod getOperationMethod(String name) throws FactoryException {
-        name = CharSequences.trimWhitespaces(name);
-        ArgumentChecks.ensureNonEmpty("name", name);
+        ArgumentChecks.ensureNonEmpty("name", name = name.strip());
         final MathTransformFactory mtFactory = getMathTransformFactory();
         if (mtFactory instanceof DefaultMathTransformFactory) {
             return ((DefaultMathTransformFactory) mtFactory).getOperationMethod(name);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index 6135a73afe..f495dfc6cc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -81,7 +81,6 @@ import org.apache.sis.referencing.operation.DefaultOperationMethod;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.Classes;
 import org.apache.sis.util.collection.WeakHashSet;
@@ -468,8 +467,7 @@ public class DefaultMathTransformFactory extends AbstractFactory implements Math
      * @see org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory#getOperationMethod(String)
      */
     public OperationMethod getOperationMethod(String identifier) throws NoSuchIdentifierException {
-        identifier = CharSequences.trimWhitespaces(identifier);
-        ArgumentChecks.ensureNonEmpty("identifier", identifier);
+        ArgumentChecks.ensureNonEmpty("identifier", identifier = identifier.strip());
         OperationMethod method = methodsByName.get(identifier);
         if (method == null) {
             synchronized (methods) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java b/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
index 94b137e624..0f8b663c54 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/converter/StringConverter.java
@@ -27,11 +27,11 @@ import javax.measure.format.ParserException;
 import org.apache.sis.math.FunctionProperty;
 import org.apache.sis.util.Locales;
 import org.apache.sis.util.Numbers;
-import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ObjectConverter;
 import org.apache.sis.util.UnconvertibleObjectException;
 import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.internal.util.CodeLists;
+import org.apache.sis.internal.util.Strings;
 import org.apache.sis.measure.Units;
 
 
@@ -127,8 +127,8 @@ abstract class StringConverter<T> extends SystemConverter<String, T> {
      */
     @Override
     public final T apply(String source) throws UnconvertibleObjectException {
-        source = CharSequences.trimWhitespaces(source);
-        if (source == null || source.isEmpty()) {
+        source = Strings.trimOrNull(source);
+        if (source == null) {
             return null;
         }
         try {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/CodeLists.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/CodeLists.java
index ee9d73d8b9..9d6fc01db7 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/CodeLists.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/CodeLists.java
@@ -94,8 +94,8 @@ public final class CodeLists implements Predicate<CodeList<?>> {
      * @see org.apache.sis.util.iso.Types#forCodeName(Class, String, boolean)
      */
     public static <T extends CodeList<T>> T forName(final Class<T> codeType, String name, final boolean canCreate) {
-        name = CharSequences.trimWhitespaces(name);
-        if (name == null || name.isEmpty()) {
+        name = Strings.trimOrNull(name);
+        if (name == null) {
             return null;
         }
         return CodeList.valueOf(codeType, new CodeLists(name), canCreate ? name : null);
@@ -112,8 +112,8 @@ public final class CodeLists implements Predicate<CodeList<?>> {
      * @see org.apache.sis.util.iso.Types#forEnumName(Class, String)
      */
     public static <T extends Enum<T>> T forName(final Class<T> enumType, String name) {
-        name = CharSequences.trimWhitespaces(name);
-        if (name != null && !name.isEmpty()) try {
+        name = Strings.trimOrNull(name);
+        if (name != null) try {
             return Enum.valueOf(enumType, name);
         } catch (IllegalArgumentException e) {
             final T[] values = enumType.getEnumConstants();
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 1a94992f88..a47e22ef63 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
@@ -101,12 +101,12 @@ public final class Strings extends Static {
      */
     public static String trimOrNull(String text) {
         if (text != null) {
-            text = CharSequences.trimWhitespaces(text.trim());
-            if (text.isEmpty()) {
-                return null;
+            text = text.trim().strip();
+            if (!text.isEmpty()) {
+                return text;
             }
         }
-        return text;
+        return null;
     }
 
     /**
diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java
index 47469fdc63..9a97c19939 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/X364.java
@@ -266,8 +266,7 @@ search: do {
      * @throws IllegalArgumentException if no code has been found for the given color name.
      */
     public static X364 forColorName(String color) throws IllegalArgumentException {
-        color = CharSequences.trimWhitespaces(color);
-        ArgumentChecks.ensureNonEmpty("color", color);
+        ArgumentChecks.ensureNonEmpty("color", color = color.strip());
         for (final X364 code : NAMED) {
             if (color.equalsIgnoreCase(code.color)) {
                 return code;
diff --git a/core/sis-utility/src/main/java/org/apache/sis/io/DefaultFormat.java b/core/sis-utility/src/main/java/org/apache/sis/io/DefaultFormat.java
index cc90aee106..86f26438a2 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/io/DefaultFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/io/DefaultFormat.java
@@ -111,7 +111,7 @@ final class DefaultFormat extends Format {
      */
     @Override
     public Object parseObject(String source) throws ParseException {
-        source = CharSequences.trimWhitespaces(source);
+        source = source.strip();
         try {
             return valueOf(source);
         } catch (NumberFormatException cause) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
index d393c4bdec..8c7a70f071 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
@@ -413,9 +413,8 @@ public class UnitFormat extends Format implements javax.measure.format.UnitForma
      */
     @Override
     public void label(final Unit<?> unit, String label) {
-        ArgumentChecks.ensureNonNull ("unit", unit);
-        label = CharSequences.trimWhitespaces(label);
-        ArgumentChecks.ensureNonEmpty("label", label);
+        ArgumentChecks.ensureNonNull("unit", unit);
+        ArgumentChecks.ensureNonEmpty("label", label = label.strip());
         for (int i=0; i < label.length();) {
             final int c = label.codePointAt(i);
             if (!AbstractUnit.isSymbolChar(c) && !Character.isSpaceChar(c)) {       // NOT Character.isWhitespace(int)
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java b/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
index 53d2d655cb..43678075cd 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java
@@ -961,8 +961,9 @@ search:     for (; fromIndex <= toIndex; fromIndex++) {
      * @return a string with leading and trailing whitespaces removed, or {@code null} is the given
      *         text was null.
      *
-     * @todo To be replaced by {@link String#strip()} in JDK 11.
+     * @deprecated Replaced by {@link String#strip()} in JDK 11.
      */
+    @Deprecated(since="1.4", forRemoval=true)
     public static String trimWhitespaces(String text) {
         if (text != null) {
             final int length = text.length();
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java b/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
index ba6c7fa14c..4185481bb1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/Exceptions.java
@@ -134,8 +134,8 @@ public final class Exceptions extends Static {
         StringBuilder buffer = null;
         Vocabulary resources = null;
         while (cause != null) {
-            final String message = CharSequences.trimWhitespaces(getLocalizedMessage(cause, locale));
-            if (message != null && !message.isEmpty()) {
+            String message = getLocalizedMessage(cause, locale);
+            if (message != null && !(message = message.strip()).isEmpty()) {
                 if (buffer == null) {
                     buffer = new StringBuilder(128);
                     if (header != null) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java b/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
index 96c3394e5e..228149b097 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/Numbers.java
@@ -524,10 +524,10 @@ public final class Numbers extends Static {
         for (int i=0; i<length; i++) {
             final char c = value.charAt(i);
             if (c == '.' || c == 'e' || c == 'E') {
-                return narrowestNumber(Double.parseDouble(value));
+                return narrowestNumber(Double.valueOf(value));
             }
         }
-        return narrowestNumber(Long.parseLong(value));
+        return narrowestNumber(Long.valueOf(value));
     }
 
     /**
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/Version.java b/core/sis-utility/src/main/java/org/apache/sis/util/Version.java
index 9c6980380d..cc1bcaeddd 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/Version.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/Version.java
@@ -212,7 +212,7 @@ public class Version implements CharSequence, Comparable<Version>, Serializable
         }
         Comparable<?> candidate = parsed[index];
         if (candidate == null) {
-            final String value = CharSequences.trimWhitespaces(components[index]);
+            final String value = components[index].strip();
             try {
                 candidate = Integer.valueOf(value);
             } catch (NumberFormatException e) {
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
index 835a940a36..d926ec6a3f 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java
@@ -29,7 +29,6 @@ import org.apache.sis.internal.util.Cloner;
 import org.apache.sis.internal.util.Acyclic;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
 
-import static org.apache.sis.util.CharSequences.trimWhitespaces;
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
 import static org.apache.sis.util.collection.Containers.hashMapCapacity;
 
@@ -777,8 +776,8 @@ public class DefaultTreeTable implements TreeTable, Cloneable, Serializable {
             if (values != null) {
                 for (final Object value : values) {
                     if (value instanceof CharSequence) {
-                        final String text = trimWhitespaces(value.toString());
-                        if (text != null && !text.isEmpty()) {
+                        String text = value.toString();
+                        if (text != null && !(text = text.strip()).isEmpty()) {
                             return text;
                         }
                     }
diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java b/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java
index 97bd7adc04..9d8159d966 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/logging/MonolineFormatter.java
@@ -512,7 +512,7 @@ loop:   for (int i=0; ; i++) {
             sourceFormat = NO_SOURCE;
             return;
         }
-        format = CharSequences.trimWhitespaces(format).toLowerCase(Locale.US);
+        format = format.strip().toLowerCase(Locale.US);
         for (int i=0; i<FORMAT_LABELS.length; i++) {
             if (format.equals(FORMAT_LABELS[i])) {
                 sourceFormat = i;
diff --git a/core/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java b/core/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
index e7a8e36ef9..6e68de5a1e 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/util/CharSequencesTest.java
@@ -256,12 +256,9 @@ public final strictfp class CharSequencesTest extends TestCase {
      */
     @Test
     public void testTrimWhitespaces() {
-        assertEquals("A text.", trimWhitespaces(               "  A text. "));
         assertEquals("A text.", trimWhitespaces((CharSequence) "  A text. "));
-        assertEquals("",        trimWhitespaces(               "          "));
         assertEquals("",        trimWhitespaces((CharSequence) "          "));
         assertNull  (           trimWhitespaces((CharSequence) null));
-        assertNull  (           trimWhitespaces((String)       null));
     }
 
     /**