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 4ae8cc9c0d7a18dc2bb1f52d4f33c1819c2db9c5
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Sep 22 10:23:33 2025 +0200

    Avoid too long `AREA` description in WKT. In particular, the area of 
EPSG:4326
    is more than 3000 characters long because it enumerates all countries.
    
    This commit contains also opportunistic cleaning such as anticipating
    that `NamedExpression` may become a record in a future release.
---
 .../iso/extent/DefaultGeographicDescription.java   |  20 +++-
 .../apache/sis/metadata/iso/extent/Extents.java    |  44 ++++++++-
 .../apache/sis/metadata/MetadataCopierTest.java    |  16 +--
 .../sis/metadata/iso/extent/ExtentsTest.java       |  11 ++-
 .../main/org/apache/sis/io/wkt/Formatter.java      |   2 +-
 .../apache/sis/io/wkt/GeodeticObjectParser.java    |   3 +-
 .../main/org/apache/sis/referencing/Builder.java   |   2 +-
 .../sis/referencing/ImmutableIdentifier.java       |   4 +-
 .../referencing/factory/sql/EPSGDataAccess.java    | 110 +++++++++++++--------
 .../sis/referencing/internal/DeprecatedCode.java   |  45 ++++++---
 .../apache/sis/referencing/privy/WKTUtilities.java |  44 ++++++++-
 .../apache/sis/storage/netcdf/MetadataReader.java  |   2 +-
 .../main/org/apache/sis/storage/FeatureQuery.java  |  49 ++++++++-
 .../apache/sis/storage/base/MetadataBuilder.java   |  17 ++--
 .../main/org/apache/sis/util/Locales.java          |   5 +-
 .../sis/storage/shapefile/ShapefileStore.java      |   6 +-
 .../org/apache/sis/gui/coverage/CellFormat.java    |   5 +
 17 files changed, 284 insertions(+), 101 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
index 478a525e06..4b744cc6bf 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
@@ -57,7 +57,7 @@ import org.apache.sis.util.iso.Types;
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @author  Touraïvane (IRD)
  * @author  Cédric Briançon (Geomatys)
- * @version 1.4
+ * @version 1.5
  * @since   0.3
  */
 @XmlType(name = "EX_GeographicDescription_Type")
@@ -80,6 +80,19 @@ public class DefaultGeographicDescription extends 
AbstractGeographicExtent imple
     public DefaultGeographicDescription() {
     }
 
+    /**
+     * Constructs a geographic description initialized to the given identifier.
+     *
+     * @param  value  the new geographic identifier, or {@code null} if none.
+     *
+     * @see #setGeographicIdentifier(Identifier)
+     *
+     * @since 1.5
+     */
+    public DefaultGeographicDescription(final Identifier value) {
+        geographicIdentifier = value;
+    }
+
     /**
      * Creates an inclusive geographic description initialized to the given 
identifier.
      * This constructor sets the {@linkplain #getInclusion() inclusion} 
property to {@code true}.
@@ -118,11 +131,14 @@ public class DefaultGeographicDescription extends 
AbstractGeographicExtent imple
      * @param description  the natural language description of the meaning of 
the code value, or {@code null} if none.
      *
      * @since 0.6
+     *
+     * @deprecated This constructor applies too arbitrary rules.
      */
+    @Deprecated(since = "1.5", forRemoval = true)
     public DefaultGeographicDescription(final CharSequence description) {
         super(true);
         if (description != null) {
-            final DefaultIdentifier id = new DefaultIdentifier();
+            final var id = new DefaultIdentifier();
             if (CharSequences.isUnicodeIdentifier(description)) {
                 id.setCode(description.toString());
                 if (description instanceof InternationalString) {
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java
index e4a5d16c39..aafadf5498 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/extent/Extents.java
@@ -18,7 +18,6 @@ package org.apache.sis.metadata.iso.extent;
 
 import java.util.Date;
 import java.util.Locale;
-import java.util.List;
 import java.util.ArrayList;
 import java.util.Set;
 import java.util.LinkedHashSet;
@@ -58,6 +57,7 @@ import org.opengis.referencing.operation.CoordinateOperation;
 import org.apache.sis.metadata.InvalidMetadataException;
 import org.apache.sis.metadata.privy.ReferencingServices;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.measure.Latitude;
 import org.apache.sis.measure.Longitude;
 import org.apache.sis.measure.MeasurementRange;
 import org.apache.sis.measure.Range;
@@ -120,10 +120,14 @@ public final class Extents extends Static {
     /**
      * A geographic extent ranging from 180°W to 180°E and 90°S to 90°N.
      * This extent has no vertical and no temporal components.
+     *
+     * @see #isWorld(Extent)
      */
     public static final Extent WORLD;
     static {
-        final var box = new DefaultGeographicBoundingBox(-180, 180, -90, 90);
+        final var box = new DefaultGeographicBoundingBox(
+                Longitude.MIN_VALUE, Longitude.MAX_VALUE,
+                 Latitude.MIN_VALUE,  Latitude.MAX_VALUE);
         box.transitionTo(DefaultGeographicBoundingBox.State.FINAL);
         var world = new 
DefaultExtent(Vocabulary.formatInternational(Vocabulary.Keys.World), box, null, 
null);
         world.transitionTo(DefaultExtent.State.FINAL);
@@ -276,7 +280,7 @@ public final class Extents extends Static {
         if (extent == null) {
             return null;
         }
-        final Extents m = new Extents();
+        final var m = new Extents();
         try {
             m.addHorizontal(extent);
         } catch (TransformException e) {
@@ -294,14 +298,14 @@ public final class Extents extends Static {
      */
     private void addHorizontal(final Extent extent) throws TransformException {
         boolean useOnlyGeographicEnvelopes = false;
-        final List<Envelope> fallbacks = new ArrayList<>();
+        final var fallbacks = new ArrayList<Envelope>();
         for (final GeographicExtent element : 
nonNull(extent.getGeographicElements())) {
             /*
              * If a geographic bounding box can be obtained, add it to the 
previous boxes (if any).
              * All exclusion boxes before the first inclusion box are ignored.
              */
             if (element instanceof GeographicBoundingBox) {
-                final GeographicBoundingBox item = (GeographicBoundingBox) 
element;
+                final var item = (GeographicBoundingBox) element;
                 if (bounds == null) {
                     /*
                      * We use 
DefaultGeographicBoundingBox.getInclusion(Boolean) below because
@@ -846,4 +850,34 @@ public final class Extents extends Static {
         if (result.equals(e2, ComparisonMode.BY_CONTRACT)) return e2;
         return (I) result;
     }
+
+    /**
+     * Returns {@code true} if the given extent covers the world.
+     * The current implementation checks if at least one geographic bounding 
box has
+     * a latitude range of {@value Latitude#MIN_VALUE} to {@value 
Latitude#MAX_VALUE} and
+     * a longitude range of {@value Longitude#MIN_VALUE} to {@value 
Longitude#MAX_VALUE}.
+     *
+     * @param  extent  the extent to check, or {@code null} if none.
+     * @return whether the given extent covers the world.
+     *
+     * @see #WORLD
+     * @since 1.5
+     */
+    public static boolean isWorld(final Extent extent) {
+        if (extent != null) {
+            for (final GeographicExtent element : 
nonNull(extent.getGeographicElements())) {
+                if (element instanceof GeographicBoundingBox) {
+                    final var item = (GeographicBoundingBox) element;
+                    if (item.getWestBoundLongitude() <= Longitude.MIN_VALUE &&
+                        item.getEastBoundLongitude() >= Longitude.MAX_VALUE &&
+                        item.getSouthBoundLatitude() <=  Latitude.MIN_VALUE &&
+                        item.getNorthBoundLatitude() >=  Latitude.MAX_VALUE)
+                    {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/MetadataCopierTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/MetadataCopierTest.java
index e0609fc0de..61bfc965b1 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/MetadataCopierTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/MetadataCopierTest.java
@@ -56,9 +56,9 @@ public final class MetadataCopierTest extends TestCase {
      */
     @Test
     public void testCopy() {
-        final MetadataCopier copier = new 
MetadataCopier(MetadataStandard.ISO_19115);
+        final var copier = new MetadataCopier(MetadataStandard.ISO_19115);
         final DefaultCitation original = HardCodedCitations.EPSG;
-        final DefaultCitation copy = (DefaultCitation) copier.copy(original);
+        final var copy = (DefaultCitation) copier.copy(original);
         assertNotSame(original, copy);
         assertNotSame(getSingleton(original.getCitedResponsibleParties()),
                       getSingleton(copy.getCitedResponsibleParties()));
@@ -70,7 +70,7 @@ public final class MetadataCopierTest extends TestCase {
      */
     @Test
     public void testCopyWithType() {
-        final MetadataCopier copier = new 
MetadataCopier(MetadataStandard.ISO_19115);
+        final var copier = new MetadataCopier(MetadataStandard.ISO_19115);
         final DefaultCitation original = HardCodedCitations.EPSG;
         final Citation copy = copier.copy(Citation.class, original);
         assertNotSame(original, copy);
@@ -85,8 +85,8 @@ public final class MetadataCopierTest extends TestCase {
      */
     @Test
     public void testCopyWithSuperType() {
-        final MetadataCopier copier = new 
MetadataCopier(MetadataStandard.ISO_19115);
-        final DefaultGeographicDescription original = new 
DefaultGeographicDescription("Some area.");
+        final var copier = new MetadataCopier(MetadataStandard.ISO_19115);
+        final var original = new DefaultGeographicDescription(null, "Some 
area.");
         final GeographicExtent copy = copier.copy(GeographicExtent.class, 
original);
         assertNotSame(original, copy);
         assertEquals (original, copy);
@@ -97,7 +97,7 @@ public final class MetadataCopierTest extends TestCase {
      */
     @Test
     public void testWrongArgument() {
-        final MetadataCopier copier = new 
MetadataCopier(MetadataStandard.ISO_19115);
+        final var copier = new MetadataCopier(MetadataStandard.ISO_19115);
         final DefaultCitation original = HardCodedCitations.EPSG;
         var e = assertThrows(IllegalArgumentException.class, () -> 
copier.copy(DefaultCitation.class, original));
         assertMessageContains(e, "DefaultCitation");
@@ -109,8 +109,8 @@ public final class MetadataCopierTest extends TestCase {
      */
     @Test
     public void testLocaleAndCharsets() {
-        final MetadataCopier copier = new 
MetadataCopier(MetadataStandard.ISO_19115);
-        final DefaultMetadata original = new DefaultMetadata();
+        final var copier = new MetadataCopier(MetadataStandard.ISO_19115);
+        final var original = new DefaultMetadata();
         original.getLocalesAndCharsets().put(Locale.FRENCH,   
StandardCharsets.UTF_8);
         original.getLocalesAndCharsets().put(Locale.JAPANESE, 
StandardCharsets.UTF_16);
         final Metadata copy = copier.copy(Metadata.class, original);
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java
index 93928b1e3f..6a19364377 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/extent/ExtentsTest.java
@@ -62,6 +62,15 @@ public final class ExtentsTest extends TestCase {
     public ExtentsTest() {
     }
 
+    /**
+     * Tests the {@link Extents#isWorld(Extent)} method.
+     */
+    @Test
+    public void testIsWorld() {
+        assertTrue (Extents.isWorld(Extents.WORLD));
+        assertFalse(Extents.isWorld(new DefaultExtent(null, new 
DefaultGeographicBoundingBox(10, 20, 30, 40), null, null)));
+    }
+
     /**
      * Tests {@link Extents#getVerticalRange(Extent)}.
      *
@@ -198,7 +207,7 @@ public final class ExtentsTest extends TestCase {
      * because it has a dependency to a referencing implementation class.
      */
     public static void testCentroid() {
-        final DefaultGeographicBoundingBox bbox = new 
DefaultGeographicBoundingBox(140, 160, 30, 50);
+        final var bbox = new DefaultGeographicBoundingBox(140, 160, 30, 50);
         DirectPosition pos = Extents.centroid(bbox);
         assertEquals(150, pos.getCoordinate(0), "longitude");
         assertEquals( 40, pos.getCoordinate(1), "latitude");
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
index 608d66edd6..828d83f699 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/Formatter.java
@@ -954,7 +954,7 @@ public class Formatter implements Localized {
                 warning(e, WKTKeywords.BBox, WKTKeywords.Usage);
                 bbox = null;
             }
-            appendOnNewLine(WKTKeywords.Area, area.getDescription(), 
ElementKind.EXTENT);
+            appendOnNewLine(WKTKeywords.Area, 
WKTUtilities.descriptionOfMediumLength(area), ElementKind.EXTENT);
             append(bbox, BBOX_ACCURACY);
             appendVerticalExtent(area);
             appendTemporalExtent(area);
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
index 95e05df498..c8858f1611 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/GeodeticObjectParser.java
@@ -75,7 +75,6 @@ import 
org.apache.sis.referencing.internal.PositionalAccuracyConstant;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.extent.DefaultExtent;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
-import org.apache.sis.metadata.iso.extent.DefaultGeographicDescription;
 import org.apache.sis.metadata.iso.extent.DefaultVerticalExtent;
 import org.apache.sis.metadata.iso.extent.DefaultTemporalExtent;
 import org.apache.sis.metadata.privy.AxisNames;
@@ -573,7 +572,7 @@ class GeodeticObjectParser extends MathTransformParser 
implements Comparator<Coo
             if (extent == null) {
                 extent = new DefaultExtent(area, null, null, null);
             } else {
-                extent.getGeographicElements().add(new 
DefaultGeographicDescription(area));
+                extent.setDescription(Types.toInternationalString(area));
             }
         }
         /*
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/Builder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/Builder.java
index f091311567..b10504c51a 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/Builder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/Builder.java
@@ -343,7 +343,7 @@ public abstract class Builder<B extends Builder<B>> {
      */
     private Identifier createIdentifier(final Citation authority, final String 
codeSpace, final String identifier, final String version) {
         if (isDeprecated()) {
-            return new DeprecatedCode(authority, codeSpace, identifier, 
version, null, getRemarks());
+            return new DeprecatedCode(authority, codeSpace, identifier, 
version, getDescription(), null, getRemarks());
         } else {
             return new ImmutableIdentifier(authority, codeSpace, identifier, 
version, getDescription());
         }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
index 864357dacc..5ab09616c4 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/ImmutableIdentifier.java
@@ -435,7 +435,7 @@ public class ImmutableIdentifier extends FormattableObject 
implements Identifier
             return true;
         }
         if (object != null && object.getClass() == getClass()) {
-            final ImmutableIdentifier that = (ImmutableIdentifier) object;
+            final var that = (ImmutableIdentifier) object;
             return Objects.equals(code,        that.code)      &&
                    Objects.equals(codeSpace,   that.codeSpace) &&
                    Objects.equals(authority,   that.authority) &&
@@ -498,7 +498,7 @@ public class ImmutableIdentifier extends FormattableObject 
implements Identifier
              *     if the parameter value is the root element (in which case 
we will format full identifier).
              */
             final FormattableObject enclosing = 
formatter.getEnclosingElement(1);
-            final boolean              isRoot = 
formatter.getEnclosingElement(2) == null;
+            final boolean isRoot = (formatter.getEnclosingElement(2) == null);
             if (isRoot || !(enclosing instanceof ParameterValue<?>)) {
                 final String citation = Identifiers.getIdentifier(authority, 
false);
                 if (citation != null && !citation.equals(codeSpace)) {
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
index a18d39d05b..d4885dbd93 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
@@ -119,6 +119,7 @@ import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultOnlineResource;
 import org.apache.sis.metadata.iso.extent.DefaultExtent;
 import org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox;
+import org.apache.sis.metadata.iso.extent.DefaultGeographicDescription;
 import org.apache.sis.metadata.iso.extent.DefaultVerticalExtent;
 import org.apache.sis.metadata.iso.extent.DefaultTemporalExtent;
 import org.apache.sis.metadata.sql.privy.SQLUtilities;
@@ -1193,7 +1194,7 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
      * @param  code    the deprecated code.
      * @return the proposed replacement (may be the "(none)" text). Never 
empty.
      */
-    private String getReplacement(final TableInfo source, final Integer code, 
final Locale locale) throws SQLException {
+    private String getReplacement(final TableInfo source, final int code, 
final Locale locale) throws SQLException {
         String reason = null;
         String replacedBy;
 search: try (ResultSet result = executeMetadataQuery("Deprecation",
@@ -1233,7 +1234,43 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
     }
 
     /**
-     * Returns the name and aliases for the {@link IdentifiedObject} to 
construct.
+     * Returns the identifier for the {@link IdentifiedObject} to construct.
+     *
+     * @param  source       information about the table on which a query has 
been executed.
+     * @param  code         the <abbr>EPSG</abbr> code of the object to 
construct.
+     * @param  identifier   the code to assign to the identifier, usually 
{@code code.toString()}.
+     * @param  description  a description associated with the identifier. May 
be {@code null}.
+     * @param  deprecated   {@code true} if the object to create is deprecated.
+     * @return an identifier for the object to create.
+     */
+    private Identifier createIdentifier(final TableInfo source, final int 
code, final String identifier,
+            final InternationalString description, final Locale locale, final 
boolean deprecated)
+            throws SQLException, FactoryException
+    {
+        final Citation authority = owner.getAuthority();
+        final String version = Types.toString(authority.getEdition(), locale);
+        if (deprecated) {
+            final String replacedBy = getReplacement(source, code, locale);
+            return new DeprecatedCode(
+                    authority,
+                    Constants.EPSG,
+                    identifier,
+                    version,
+                    description,
+                    Character.isDigit(replacedBy.charAt(0)) ? replacedBy : 
null,
+                    
Vocabulary.formatInternational(Vocabulary.Keys.SupersededBy_1, replacedBy));
+        } else {
+            return new ImmutableIdentifier(
+                    authority,
+                    Constants.EPSG,
+                    identifier,
+                    version,
+                    description);
+        }
+    }
+
+    /**
+     * Returns the identifier, name and aliases for the {@link 
IdentifiedObject} to construct.
      *
      * <h4>Possible recursive calls</h4>
      * Invoking this method may cause a recursive call to {@link 
#createCoordinateReferenceSystem(String)}
@@ -1358,29 +1395,14 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
          */
         properties.clear();
         properties.put(IdentifiedObject.NAME_KEY, nameAsIdentifier);
+        properties.put(IdentifiedObject.IDENTIFIERS_KEY, createIdentifier(
+                source, code, code.toString(), 
scopedName.toInternationalString(), locale, deprecated));
         if (!aliases.isEmpty()) {
             properties.put(IdentifiedObject.ALIAS_KEY, 
aliases.toArray(GenericName[]::new));
         }
-        final ImmutableIdentifier identifier;
         if (deprecated) {
             properties.put(AbstractIdentifiedObject.DEPRECATED_KEY, 
Boolean.TRUE);
-            final String replacedBy = getReplacement(source, code, locale);
-            identifier = new DeprecatedCode(
-                    authority,
-                    Constants.EPSG,
-                    code.toString(),
-                    version,
-                    Character.isDigit(replacedBy.charAt(0)) ? replacedBy : 
null,
-                    
Vocabulary.formatInternational(Vocabulary.Keys.SupersededBy_1, replacedBy));
-        } else {
-            identifier = new ImmutableIdentifier(
-                    authority,
-                    Constants.EPSG,
-                    code.toString(),
-                    version,
-                    scopedName.toInternationalString());
         }
-        properties.put(IdentifiedObject.IDENTIFIERS_KEY, identifier);
         properties.put(IdentifiedObject.REMARKS_KEY, remarks);
         properties.put(AbstractIdentifiedObject.LOCALE_KEY, locale);
         properties.put(ReferencingFactoryContainer.MT_FACTORY, 
owner.mtFactory);
@@ -2320,29 +2342,35 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
         final QueryID previousSingletonQuery = currentSingletonQuery;
         try (ResultSet result = executeSingletonQuery(
                 TableInfo.EXTENT,
-                "SELECT"+ /* column  1 */ " EXTENT_DESCRIPTION,"
-                        + /* column  2 */ " BBOX_SOUTH_BOUND_LAT,"
-                        + /* column  3 */ " BBOX_NORTH_BOUND_LAT,"
-                        + /* column  4 */ " BBOX_WEST_BOUND_LON,"
-                        + /* column  5 */ " BBOX_EAST_BOUND_LON,"
-                        + /* column  6 */ " VERTICAL_EXTENT_MIN,"
-                        + /* column  7 */ " VERTICAL_EXTENT_MAX,"
-                        + /* column  8 */ " VERTICAL_EXTENT_CRS_CODE,"
-                        + /* column  9 */ " TEMPORAL_EXTENT_BEGIN,"
-                        + /* column 10 */ " TEMPORAL_EXTENT_END"
+                "SELECT"+ /* column  1 */ " EXTENT_CODE,"
+                        + /* column  2 */ " EXTENT_NAME,"
+                        + /* column  3 */ " EXTENT_DESCRIPTION,"
+                        + /* column  4 */ " BBOX_SOUTH_BOUND_LAT,"
+                        + /* column  5 */ " BBOX_NORTH_BOUND_LAT,"
+                        + /* column  6 */ " BBOX_WEST_BOUND_LON,"
+                        + /* column  7 */ " BBOX_EAST_BOUND_LON,"
+                        + /* column  8 */ " VERTICAL_EXTENT_MIN,"
+                        + /* column  9 */ " VERTICAL_EXTENT_MAX,"
+                        + /* column 10 */ " VERTICAL_EXTENT_CRS_CODE,"
+                        + /* column 11 */ " TEMPORAL_EXTENT_BEGIN,"
+                        + /* column 12 */ " TEMPORAL_EXTENT_END,"
+                        + /* column 13 */ " DEPRECATED"
                         + " FROM \"Extent\""
                         + " WHERE EXTENT_CODE = ?", code))
         {
             while (result.next()) {
-                final String description = getOptionalString(result, 1);
-                double   ymin = getOptionalDouble  (result,  2);
-                double   ymax = getOptionalDouble  (result,  3);
-                double   xmin = getOptionalDouble  (result,  4);
-                double   xmax = getOptionalDouble  (result,  5);
-                double   zmin = getOptionalDouble  (result,  6);
-                double   zmax = getOptionalDouble  (result,  7);
-                Temporal tmin = getOptionalTemporal(result,  9, 
"createExtent");
-                Temporal tmax = getOptionalTemporal(result, 10, 
"createExtent");
+                Integer  epsg        = getOptionalInteger (result,  1);
+                String   name        = getOptionalString  (result,  2);
+                String   description = getOptionalString  (result,  3);
+                double   ymin        = getOptionalDouble  (result,  4);
+                double   ymax        = getOptionalDouble  (result,  5);
+                double   xmin        = getOptionalDouble  (result,  6);
+                double   xmax        = getOptionalDouble  (result,  7);
+                double   zmin        = getOptionalDouble  (result,  8);
+                double   zmax        = getOptionalDouble  (result,  9);
+                Temporal tmin        = getOptionalTemporal(result, 11, 
"createExtent");
+                Temporal tmax        = getOptionalTemporal(result, 12, 
"createExtent");
+                boolean  deprecated  = getOptionalBoolean (result, 13);
                 DefaultGeographicBoundingBox bbox = null;
                 if (!(Double.isNaN(ymin) && Double.isNaN(ymax) && 
Double.isNaN(xmin) && Double.isNaN(xmax))) {
                     /*
@@ -2362,7 +2390,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                 DefaultVerticalExtent vertical = null;
                 if (!(Double.isNaN(zmin) && Double.isNaN(zmax))) {
                     vertical = new DefaultVerticalExtent(zmin, zmax, null);
-                    final Integer crs = getOptionalInteger(result, 8);
+                    final Integer crs = getOptionalInteger(result, 10);
                     if (crs != null) {
                         var c = new QueryID("Coordinate Reference System", new 
int[] {crs}, currentSingletonQuery);
                         if (!c.isAlreadyInProgress()) {
@@ -2375,6 +2403,10 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                     temporal = new DefaultTemporalExtent(tmin, tmax);
                 }
                 var extent = new DefaultExtent(description, bbox, vertical, 
temporal);
+                if (epsg != null && name != null) {     // Should never be 
null, but we don't need to be strict.
+                    var identifier = createIdentifier(TableInfo.EXTENT, epsg, 
name, null, getLocale(), deprecated);
+                    extent.getGeographicElements().add(new 
DefaultGeographicDescription(identifier));
+                }
                 if (!extent.isEmpty()) {
                     returnValue = ensureSingleton(extent, returnValue, code);
                 }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/DeprecatedCode.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/DeprecatedCode.java
index 710980a629..d5b62fe4be 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/DeprecatedCode.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/DeprecatedCode.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.referencing.internal;
 
+import java.util.Objects;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.referencing.ImmutableIdentifier;
@@ -27,12 +28,7 @@ import java.util.Optional;
 
 /**
  * An identifier which should not be used anymore.
- * This is used mostly for deprecated EPSG codes.
- *
- * <h2>Implementation note</h2>
- * This class opportunistically recycles the {@linkplain #getDescription() 
description} property into a
- * {@linkplain #getRemarks() remarks} property. This is a lazy way to inherit 
{@link #equals(Object)} and
- * {@link #hashCode()} implementations without adding code in this class for 
taking in account a new field.
+ * This is used mostly for deprecated <abbr>EPSG</abbr> codes.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
@@ -40,13 +36,19 @@ public final class DeprecatedCode extends 
ImmutableIdentifier implements Depreca
     /**
      * For cross-version compatibility.
      */
-    private static final long serialVersionUID = 357222258307746767L;
+    private static final long serialVersionUID = 8186104136524932846L;
 
     /**
      * The replacement for the deprecated object, or {@code null} if none.
      */
     public final String replacedBy;
 
+    /**
+     * Comments on or information about why this identifier is deprecated, or 
{@code null} if none.
+     */
+    @SuppressWarnings("serial")     // Most SIS implementations are 
serializable.
+    private final InternationalString remarks;
+
     /**
      * Creates a deprecated identifier.
      *
@@ -54,15 +56,17 @@ public final class DeprecatedCode extends 
ImmutableIdentifier implements Depreca
      * @param codeSpace   name or identifier of the person or organization 
responsible for namespace.
      * @param code        identifier code or name, optionally from a 
controlled list or pattern defined by a code space.
      * @param version     the version of the associated code space or code as 
specified by the code authority, or {@code null} if none.
+     * @param description a description associated with the identifier. May be 
{@code null}.
      * @param replacedBy  the replacement for the deprecated object, or {@code 
null} if none.
      * @param remarks     comments on or information about why this identifier 
is deprecated, or {@code null} if none.
      */
     public DeprecatedCode(final Citation authority, final String codeSpace,
-            final String code, final String version, final String replacedBy,
-            InternationalString remarks)
+            final String code, final String version, final InternationalString 
description,
+            final String replacedBy, final InternationalString remarks)
     {
         super(authority, codeSpace, code, version, remarks);
         this.replacedBy = replacedBy;
+        this.remarks = remarks;
     }
 
     /**
@@ -84,17 +88,26 @@ public final class DeprecatedCode extends 
ImmutableIdentifier implements Depreca
      */
     @Override
     public Optional<InternationalString> getRemarks() {
-        return Optional.ofNullable(super.getDescription());
+        return Optional.ofNullable(remarks);
     }
 
     /**
-     * Returns {@code null}, since we used the description for the superseded 
information.
-     * See <q>Implementation note</q> in class javadoc.
-     *
-     * @return {@code null}.
+     * Returns an hash code value for this identifier.
+     */
+    @Override
+    public int hashCode() {
+        return super.hashCode() + 37 * Objects.hash(replacedBy, remarks);
+    }
+
+    /**
+     * Tests whether this object is equal to the given object.
      */
     @Override
-    public InternationalString getDescription() {
-        return null;
+    public boolean equals(final Object obj) {
+        if (super.equals(obj)) {
+            final var other = (DeprecatedCode) obj;
+            return Objects.equals(replacedBy, other.replacedBy) && 
Objects.equals(remarks, other.remarks);
+        }
+        return false;
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/WKTUtilities.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/WKTUtilities.java
index 8bff5af18a..9b4c150fea 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/WKTUtilities.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/privy/WKTUtilities.java
@@ -22,6 +22,11 @@ import java.util.logging.Logger;
 import javax.measure.Unit;
 import javax.measure.Quantity;
 import javax.measure.quantity.Angle;
+import org.opengis.metadata.Identifier;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.extent.GeographicExtent;
+import org.opengis.metadata.extent.GeographicDescription;
+import org.opengis.util.InternationalString;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.GeneralParameterValue;
@@ -31,6 +36,7 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
+import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.crs.AbstractCRS;
 import org.apache.sis.referencing.datum.DatumOrEnsemble;
@@ -44,6 +50,7 @@ import org.apache.sis.io.wkt.FormattableObject;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.measure.Units;
 import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.util.privy.Constants;
 import org.apache.sis.util.privy.Numerics;
@@ -51,9 +58,6 @@ import org.apache.sis.math.DecimalFunctions;
 import org.apache.sis.math.Statistics;
 import org.apache.sis.math.Vector;
 
-// Specific to the geoapi-3.1 and geoapi-4.0 branches:
-import org.opengis.metadata.Identifier;
-
 
 /**
  * Utility methods for referencing WKT formatting.
@@ -467,4 +471,38 @@ fill:   for (;;) {
         }
         return numbers;
     }
+
+    /**
+     * Returns a description of the given extent. If the description is too 
long, tries to find a shorter one.
+     * In the particular case of extents created by {@link 
org.apache.sis.referencing.factory.sql.EPSGDataAccess},
+     * a shorter name is available as a geographic identifier in the 
<abbr>EPSG</abbr> namespace.
+     * This is a name similar to the name of an {@link IdentifiedObject}, 
which is also an {@link Identifier}.
+     * In the latter case, this method checks that the first character is a 
letter for avoiding to return a
+     * numerical <abbr>EPSG</abbr> code.
+     *
+     * @param  extent  the extent from which to get a description.
+     * @return description of medium length for the given extent, or {@code 
null} if none.
+     */
+    public static InternationalString descriptionOfMediumLength(final Extent 
extent) {
+        InternationalString description = extent.getDescription();
+        if (description != null && description.length() > 255) {    // 255 is 
the limit recommended by ISO 19162:2019.
+            if (Extents.isWorld(extent)) {
+                description = Extents.WORLD.getDescription();
+            } else {
+                for (GeographicExtent element : 
extent.getGeographicElements()) {
+                    if (element instanceof GeographicDescription) {
+                        Identifier id = ((GeographicDescription) 
element).getGeographicIdentifier();
+                        if (id != null && 
Constants.EPSG.equalsIgnoreCase(id.getCodeSpace())) {
+                            String name = id.getCode();
+                            if (name != null && !name.isEmpty() && 
Character.isLetter(name.codePointAt(0))) {
+                                description = new 
SimpleInternationalString(name);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return description;
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
index 46f308255b..135d8acb69 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/main/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -748,7 +748,7 @@ split:  while ((start = 
CharSequences.skipLeadingWhitespaces(value, start, lengt
      * @return {@code true} if at least one numerical value has been added.
      */
     private boolean addExtent() {
-        addExtent(stringValue(GEOGRAPHIC_IDENTIFIER));
+        addExtent(null, stringValue(GEOGRAPHIC_IDENTIFIER));
         final double[] extent = new double[4];
         /*
          * If at least one geographic coordinate is available, add a 
GeographicBoundingBox.
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
index 4412e94419..83ff095436 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/FeatureQuery.java
@@ -267,7 +267,8 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
             for (int i=0; i<properties.length; i++) {
                 final NamedExpression c = properties[i];
                 ArgumentChecks.ensureNonNullElement("properties", i, c);
-                Object key = (c.alias != null) ? c.alias : c.expression;
+                GenericName alias = c.alias();
+                Object key = (alias != null) ? alias : c.expression();
                 final Integer p = uniques.putIfAbsent(key, i);
                 if (p != null) {
                     if (key instanceof Expression) {
@@ -540,7 +541,7 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
      * @version 1.5
      * @since   1.1
      */
-    public static class NamedExpression implements Serializable {
+    public static final class NamedExpression implements Serializable {
         /**
          * For cross-version compatibility.
          */
@@ -549,13 +550,19 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
         /**
          * The literal, value reference or more complex expression to be 
retrieved by a {@code Query}.
          * Never {@code null}.
+         *
+         * @deprecated Replaced by {@link #expression()} in preparation for 
making {@code NamedExpression} a record.
          */
+        @Deprecated(since = "1.5")
         @SuppressWarnings("serial")
         public final Expression<? super Feature, ?> expression;
 
         /**
          * The name to assign to the expression result, or {@code null} if 
unspecified.
+         *
+         * @deprecated Replaced by {@link #alias()} in preparation for making 
{@code NamedExpression} a record.
          */
+        @Deprecated(since = "1.5")
         @SuppressWarnings("serial")                 // Most SIS 
implementations are serializable.
         public final GenericName alias;
 
@@ -565,8 +572,11 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
          * a feature {@link Operation}. The latter are commonly called 
"computed fields" and are equivalent
          * to SQL {@code GENERATED ALWAYS} keyword for columns.
          *
+         * @deprecated Replaced by {@link #type()} in preparation for making 
{@code NamedExpression} a record.
+         *
          * @since 1.4
          */
+        @Deprecated(since = "1.5")
         public final ProjectionType type;
 
         /**
@@ -638,6 +648,37 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
             return false;
         }
 
+        /**
+         * The literal, value reference or more complex expression to be 
retrieved by a {@code Query}.
+         * Never {@code null}.
+         *
+         * @since 1.5
+         */
+        public Expression<? super Feature, ?> expression() {
+            return expression;
+        }
+
+        /**
+         * The name to assign to the expression result, or {@code null} if 
unspecified.
+         *
+         * @since 1.5
+         */
+        public GenericName alias() {
+            return alias;
+        }
+
+        /**
+         * Whether the expression result should be stored or evaluated every 
times that it is requested.
+         * A stored value will exist as a feature {@link Attribute}, while a 
virtual value will exist as
+         * a feature {@link Operation}. The latter are commonly called 
"computed fields" and are equivalent
+         * to SQL {@code GENERATED ALWAYS} keyword for columns.
+         *
+         * @since 1.5
+         */
+        public ProjectionType type() {
+            return type;
+        }
+
         /**
          * Returns a hash code value for this column.
          *
@@ -732,7 +773,7 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
         Set<String> xpaths = ListingPropertyVisitor.xpaths(selection, null);
         if (projection != null) {
             for (NamedExpression e : projection) {
-                xpaths = ListingPropertyVisitor.xpaths(e.expression, xpaths);
+                xpaths = ListingPropertyVisitor.xpaths(e.expression(), xpaths);
             }
         }
         return xpaths;
@@ -763,7 +804,7 @@ public class FeatureQuery extends Query implements 
Cloneable, Emptiable, Seriali
         for (int column = 0; column < projection.length; column++) {
             final NamedExpression item = projection[column];
             if (!item.addTo(builder)) {
-                final var name = 
item.expression.getFunctionName().toInternationalString();
+                final var name = 
item.expression().getFunctionName().toInternationalString();
                 throw new 
InvalidFilterValueException(Resources.forLocale(locale)
                             .getString(Resources.Keys.InvalidExpression_2, 
column, name));
             }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
index 657102d957..08ecac8507 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
@@ -1729,22 +1729,19 @@ public class MetadataBuilder {
     }
 
     /**
-     * Adds a geographic extent described by an identifier. The given 
identifier is stored as-is as
-     * the natural language description, and possibly in a modified form as 
the geographic identifier.
-     * See {@link 
DefaultGeographicDescription#DefaultGeographicDescription(CharSequence)} for 
details.
-     * Storage locations are:
+     * Adds a geographic extent described by an identifier.
+     * Storage location is:
      *
      * <ul>
-     *   <li>{@code 
metadata/identificationInfo/extent/geographicElement/description}</li>
      *   <li>{@code 
metadata/identificationInfo/extent/geographicElement/identifier}</li>
      * </ul>
      *
-     * @param  identifier  identifier or description of spatial and temporal 
extent, or {@code null} for no-operation.
+     * @param authority  the authority of the identifier code, or {@code null} 
if none.
+     * @param code       the identifier code used to represent a geographic 
area, or {@code null} if none.
      */
-    public final void addExtent(final CharSequence identifier) {
-        final InternationalString i18n = trim(identifier);
-        if (i18n != null) {
-            addIfNotPresent(extent().getGeographicElements(), new 
DefaultGeographicDescription(identifier));
+    public final void addExtent(final Citation authority, final String 
identifier) {
+        if (authority != null || identifier != null) {
+            addIfNotPresent(extent().getGeographicElements(), new 
DefaultGeographicDescription(authority, identifier));
         }
     }
 
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Locales.java 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Locales.java
index f0ca82de40..439fdd0b05 100644
--- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Locales.java
+++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Locales.java
@@ -32,9 +32,8 @@ import static 
org.apache.sis.util.resources.IndexedResourceBundle.LOGGER;
 
 
 /**
- * Static methods working on {@link Locale} instances. While this class is 
documented as
- * providing static methods, a few methods are actually non-static. Those 
methods need to be
- * invoked on the {@link #ALL} or {@link #SIS} instance in order to specify 
the scope.
+ * Utility methods working on {@link Locale} instances.
+ * Non-static methods need to be invoked on the {@link #ALL} or {@link #SIS} 
instance in order to specify the scope.
  * Examples:
  *
  * {@snippet lang="java" :
diff --git 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
index 9c2559444b..ccccc16427 100644
--- 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
+++ 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
@@ -590,9 +590,9 @@ public final class ShapefileStore extends DataStore 
implements WritableFeatureSe
                 if (projection != null) {
                     properties = ListingPropertyVisitor.xpaths(selection, 
properties);
                     for (FeatureQuery.NamedExpression ne : projection) {
-                        properties = 
ListingPropertyVisitor.xpaths(ne.expression, properties);
-                        simpleSelection &= (ne.alias == null);
-                        simpleSelection &= 
(ne.expression.getFunctionName().tip().toString().equals(FunctionNames.ValueReference));
+                        properties = 
ListingPropertyVisitor.xpaths(ne.expression(), properties);
+                        simpleSelection &= (ne.alias() == null);
+                        simpleSelection &= 
(ne.expression().getFunctionName().tip().toString().equals(FunctionNames.ValueReference));
                     }
 
                     //if link fields are referenced, add target fields
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CellFormat.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CellFormat.java
index 8d1b562306..8259fc5d69 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CellFormat.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/coverage/CellFormat.java
@@ -158,10 +158,15 @@ final class CellFormat extends SimpleStringProperty {
     /**
      * Tries to reduce the size of the pattern used for formatting the numbers.
      * This method is invoked when the numbers are too large for the cell 
width.
+     * The method should be invoked soon after a call to a {@code format(…)} 
method,
+     * because its behavior depends on which value was formatted last time.
      *
      * @return whether the pattern has been made smaller.
      */
     final boolean shorterPattern() {
+        if (Double.isNaN(lastValue)) {
+            return false;
+        }
         int n = cellFormat.getMaximumFractionDigits() - 1;
         if (n >= 0) {
             cellFormat.setMaximumFractionDigits(n);

Reply via email to