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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new ed8a9d3277 Sort coordinate operations by domain of validity in Java 
code instead of in the SQL query. It makes easier to handle the new way that 
extent are declared in EPSG version 10+. It also seems to fix a bug in the 
ordering of coordinate operations.
ed8a9d3277 is described below

commit ed8a9d327722c70b726faee7484fabf416392ff6
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Aug 4 20:04:00 2025 +0200

    Sort coordinate operations by domain of validity in Java code instead of in 
the SQL query.
    It makes easier to handle the new way that extent are declared in EPSG 
version 10+.
    It also seems to fix a bug in the ordering of coordinate operations.
---
 .../apache/sis/metadata/iso/extent/Extents.java    |   6 +-
 .../referencing/factory/IdentifiedObjectSet.java   |  77 ++++-----
 .../factory/sql/CoordinateOperationSet.java        |  19 +--
 .../referencing/factory/sql/EPSGCodeFinder.java    |  16 +-
 .../referencing/factory/sql/EPSGDataAccess.java    | 178 ++++++++++++++-------
 .../referencing/factory/sql/ObjectPertinence.java  | 154 ++++++++++++++++++
 .../sis/referencing/factory/sql/TableInfo.java     |  30 ++--
 .../referencing/factory/sql/EPSGFactoryTest.java   |  16 +-
 8 files changed, 350 insertions(+), 146 deletions(-)

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 8458017128..e4a5d16c39 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
@@ -681,9 +681,9 @@ public final class Extents extends Static {
     }
 
     /**
-     * Returns the union of the given geographic bounding boxes. If any of the 
arguments is {@code null},
-     * then this method returns the other argument (which may be null). 
Otherwise this method returns a box
-     * which is the union of the two given boxes.
+     * Returns the union of the given geographic bounding boxes.
+     * If any of the arguments is {@code null}, then this method returns the 
other argument (which may be null).
+     * Otherwise, this method returns a box which is the union of the two 
given boxes.
      *
      * <p>This method never modify the given boxes, but may return directly 
one of the given arguments
      * if it already represents the union result.</p>
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
index 3c57d1fbf4..9056d04d0a 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/IdentifiedObjectSet.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.referencing.factory;
 
-import java.util.Set;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -53,26 +52,28 @@ import org.apache.sis.util.collection.CheckedContainer;
  * {@linkplain #createObject(String) object creation}, or to {@link 
#add(IdentifiedObject)} for objects
  * that are already instantiated. This collection cannot contain two {@code 
IdentifiedObject} instances
  * having the same identifier. However, the identifiers used by this class can 
be controlled by overriding
- * {@link #getAuthorityCode(IdentifiedObject)}.</p>
+ * the {@link #getAuthorityCode(IdentifiedObject)} method.</p>
  *
  * <p>Iterations over elements in this collection preserve insertion order.</p>
  *
  * <h2>Purpose</h2>
- * {@code IdentifiedObjectSet} can be used as the set returned by 
implementations of the
- * {@link 
GeodeticAuthorityFactory#createFromCoordinateReferenceSystemCodes(String, 
String)} method.
- * Deferred creation can have great performance impact since some set may 
contain as much as 40 entries
- * (e.g. transformations from <q>ED50</q> (EPSG:4230) to <q>WGS 84</q> 
(EPSG:4326))
- * while some users only want to look for the first entry.
+ * {@code IdentifiedObjectSet} is useful mostly for implementers of authority 
factories rather than users.
+ * When used as the implementation of the
+ * {@linkplain 
GeodeticAuthorityFactory#createFromCoordinateReferenceSystemCodes(String, 
String)
+ * set of coordinate operations between a pair of <abbr>CRS</abbr>}, {@code 
IdentifiedObjectSet}
+ * can improve significantly the performances because some sets contain tens 
of entries
+ * (e.g., transformations from <q>ED50</q> (EPSG:4230) to <q>WGS 84</q> 
(EPSG:4326)),
+ * while users typically want to look for only the first entry.
  *
  * <h2>Exception handling</h2>
  * If the underlying factory failed to creates an object because of an 
unsupported operation method
- * ({@link NoSuchIdentifierException}), the exception is logged at {@link 
Level#WARNING} and the iteration continue.
+ * ({@link NoSuchIdentifierException}), the exception is logged at {@link 
Level#WARNING} and the iteration continues.
  * If the operation creation failed for any other kind of reason ({@link 
FactoryException}), then the exception is
  * re-thrown as an unchecked {@link BackingStoreException}. This default 
behavior can be changed by overriding
  * the {@link #isRecoverableFailure(FactoryException)} method.
  *
  * <h2>Thread safety</h2>
- * This class is thread-safe is the underlying {@linkplain #factory} is also 
thread-safe.
+ * This class is thread-safe if the underlying {@linkplain #factory} is also 
thread-safe.
  * However, implementers are encouraged to wrap in {@linkplain 
java.util.Collections#unmodifiableSet unmodifiable set}
  * if they intent to cache {@code IdentifiedObjectSet} instances.
  *
@@ -91,14 +92,7 @@ public class IdentifiedObjectSet<T extends IdentifiedObject> 
extends AbstractSet
      * <p><b>Note:</b> using {@code ConcurrentHahMap} would be more efficient.
      * But the latter does not support null values and does not preserve 
insertion order.</p>
      */
-    final Map<String,T> objects = new LinkedHashMap<>();
-
-    /**
-     * The {@link #objects} keys, created for iteration purpose when first 
needed and cleared when the map is modified.
-     * We need to use such array as a snapshot of the map state at the time 
the iterator was created because the map
-     * may be modified during iteration or by concurrent threads.
-     */
-    private transient String[] codes;
+    final Map<String,T> objects;
 
     /**
      * The factory to use for creating {@code IdentifiedObject}s when first 
needed.
@@ -131,6 +125,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
         this.factory = Objects.requireNonNull(factory);
         this.type    = Objects.requireNonNull(type);
         this.proxy   = AuthorityFactoryProxy.getInstance(type);
+        this.objects = new LinkedHashMap<>();
     }
 
     /**
@@ -160,7 +155,6 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
     @Override
     public void clear() {
         synchronized (objects) {
-            codes = null;
             objects.clear();
         }
     }
@@ -185,27 +179,15 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      * @return the authority codes in iteration order.
      */
     public String[] getAuthorityCodes() {
-        return codes().clone();
-    }
-
-    /**
-     * Returns the {@code codes} array, creating it if needed. This method 
does not clone the array.
-     */
-    @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    final String[] codes() {
         synchronized (objects) {
-            if (codes == null) {
-                final Set<String> keys = objects.keySet();
-                codes = keys.toArray(String[]::new);
-            }
-            return codes;
+            return objects.keySet().toArray(String[]::new);
         }
     }
 
     /**
      * Sets the content of this collection to the object identified by the 
given codes.
      * For any code in the given sequence, this method will preserve the 
corresponding {@code IdentifiedObject}
-     * instance if it was already created. Otherwise objects will be 
{@linkplain #createObject(String) created}
+     * instance if it was already created. Otherwise, objects will be 
{@linkplain #createObject(String) created}
      * only when first needed.
      *
      * <h4>Use case</h4>
@@ -220,8 +202,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      */
     public void setAuthorityCodes(final String... codes) {
         synchronized (objects) {
-            this.codes = null;
-            final Map<String,T> copy = new HashMap<>(objects);
+            final var copy = new HashMap<String,T>(objects);
             objects.clear();
             for (final String code : codes) {
                 objects.put(code, copy.get(code));
@@ -233,15 +214,13 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      * Ensures that this collection contains an object for the specified 
authority code.
      * If this collection does not contain any element for the given code, 
then this method
      * will instantiate an {@code IdentifiedObject} for the given code only 
when first needed.
-     * Otherwise this collection is unchanged.
+     * Otherwise, this collection is unchanged.
      *
      * @param  code  the code authority code of the {@code IdentifiedObject} 
to include in this set.
      */
     public void addAuthorityCode(final String code) {
         synchronized (objects) {
-            if (objects.putIfAbsent(code, null) == null) {
-                codes = null;
-            }
+            objects.putIfAbsent(code, null);
         }
     }
 
@@ -261,7 +240,6 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
         final String code = getAuthorityCode(object);
         final T previous;
         synchronized (objects) {
-            codes = null;
             previous = objects.put(code, object);
         }
         return !Objects.equals(previous, object);
@@ -274,7 +252,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      *
      * @see #createObject(String)
      */
-    final T get(final String code) throws BackingStoreException {
+    private T get(final String code) throws BackingStoreException {
         T object;
         boolean success;
         synchronized (objects) {
@@ -304,7 +282,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
                      * The check for `containsKey` is a paranoiac check in 
case the element has been removed
                      * in another thread while we were creating the object. 
This is likely to be unnecessary
                      * in the vast majority of cases where the set of codes is 
never modified after this set
-                     * has been published. However if someone decided to do 
such concurrent modifications,
+                     * has been published. However, if someone decided to do 
such concurrent modifications,
                      * not checking for concurrent removal could be a subtle 
and hard-to-find bug, so we are
                      * better to be safe. Note that if a concurrent removal 
happened, we still return the non-null
                      * object but we do not put it in this 
IdentifiedObjectSet. This behavior is as if this method
@@ -316,8 +294,8 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
                             object = c;                     // The object has 
been created concurrently.
                         }
                     }
-                } else if (objects.remove(code, null)) {    // Do not remove 
if a concurrent thread succeeded.
-                    codes = null;
+                } else {                                    // Do not remove 
if a concurrent thread succeeded.
+                    objects.remove(code, null);
                 }
             }
         }
@@ -329,6 +307,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      *
      * @param  object  the {@code IdentifiedObject} to test for presence in 
this set.
      * @return {@code true} if the given object is presents in this set.
+     * @throws ClassCastException if the given object is non-null and not an 
instance of {@code <T>}.
      */
     @Override
     public boolean contains(final Object object) {
@@ -340,10 +319,9 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      *
      * @param  code  the code of the object to remove.
      */
-    final void removeAuthorityCode(final String code) {
+    private void removeAuthorityCode(final String code) {
         synchronized (objects) {
             objects.remove(code);
-            codes = null;
         }
     }
 
@@ -352,6 +330,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      *
      * @param  object  the {@code IdentifiedObject} to remove from this set.
      * @return {@code true} if this set changed as a result of this call.
+     * @throws ClassCastException if the given object is non-null and not an 
instance of {@code <T>}.
      */
     @Override
     public boolean remove(final Object object) {
@@ -361,7 +340,6 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
             if (object.equals(current)) {
                 synchronized (objects) {
                     objects.remove(code);
-                    codes = null;
                 }
                 return true;
             }
@@ -374,8 +352,10 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      *
      * @param  collection  the {@code IdentifiedObject}s to remove from this 
set.
      * @return {@code true} if this set changed as a result of this call.
+     * @throws ClassCastException if the given collection contains an object 
which is not an instance of {@code <T>}.
      */
     @Override
+    @SuppressWarnings("element-type-mismatch")
     public boolean removeAll(final Collection<?> collection) {
         boolean modified = false;
         for (final Object object : collection) {
@@ -403,7 +383,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
              * We need to take a snapshot because the underlying {@link 
IdentifiedObjectSet#objects} map may be
              * modified concurrently in other threads.
              */
-            private final String[] keys = codes();
+            private final String[] keys = getAuthorityCodes();
 
             /**
              * Index of the next element to obtain by a call to {@link 
IdentifiedObjectSet#get(String)}.
@@ -524,6 +504,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      * @param  code  the code for which to create the identified object.
      * @return the identified object created from the given code.
      * @throws FactoryException if the object creation failed.
+     * @throws ClassCastException if the object created from the given object 
is not an instance of {@code <T>}.
      */
     protected T createObject(final String code) throws FactoryException {
         return type.cast(proxy.createFromAPI(factory, code));
@@ -563,7 +544,7 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      */
     private static String getCause(Throwable cause) {
         final String lineSeparator = System.lineSeparator();
-        final StringBuilder trace = new StringBuilder(180);
+        final var trace = new StringBuilder(180);
         while (cause != null) {
             trace.append(lineSeparator).append("  • 
").append(Classes.getShortClassName(cause));
             final String message = cause.getMessage();      // Prefer the 
local of system administrator.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
index 6002437391..f289b0f33e 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/CoordinateOperationSet.java
@@ -34,14 +34,13 @@ import org.opengis.referencing.crs.DerivedCRS;
 
 
 /**
- * A lazy set of {@link CoordinateOperation} objects to be returned by the
- * {@link EPSGDataAccess#createFromCoordinateReferenceSystemCodes(String, 
String)} method.
- * There are two different ways in which {@link EPSGDataAccess} get coordinate 
operations:
+ * A lazy set of coordinate operations identified by their <abbr>EPSG</abbr> 
codes.
+ * There are two different ways in which {@link EPSGDataAccess} gets 
coordinate operations:
  *
  * <ol>
- *   <li>The coordinate operation may be the <i>conversion from base</i> 
property of a projected CRS.
- *       Those conversions are obtained by a SQL query like below (note that 
this query can return at most
- *       one result, because {@code COORD_REF_SYS_CODE} is a primary key):
+ *   <li>The coordinate operation may be the <i>conversion from base</i> 
property of a projected <abbr>CRS</abbr>.
+ *       Those conversions are obtained by a <abbr>SQL</abbr> query like below 
(note that this query can return at
+ *       most one result, because {@code COORD_REF_SYS_CODE} is a primary key):
  *
  *       {@snippet lang="sql" :
  *         SELECT PROJECTION_CONV_CODE FROM "Coordinate Reference System" 
WHERE BASE_CRS_CODE = ? AND COORD_REF_SYS_CODE = ?
@@ -49,7 +48,7 @@ import org.opengis.referencing.crs.DerivedCRS;
  *   </li>
  *
  *   <li>The coordinate operation may be standalone. This is the case of 
coordinate transformations having stochastic errors.
- *       Those transformations are obtained by a SQL query like below (note 
that this query can return many results):
+ *       Those transformations are obtained by a <abbr>SQL</abbr> query like 
below (note that it may return many results):
  *
  *       {@snippet lang="sql" :
  *         SELECT COORD_OP_CODE FROM "Coordinate_Operation" … WHERE … AND 
SOURCE_CRS_CODE = ? AND TARGET_CRS_CODE = ?
@@ -60,6 +59,8 @@ import org.opengis.referencing.crs.DerivedCRS;
  * We distinguish those two cases by the presence or absence of a coordinate 
operation code in the {@link #projections} map.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
+ *
+ * @see EPSGDataAccess#createFromCoordinateReferenceSystemCodes(String, String)
  */
 final class CoordinateOperationSet extends 
IdentifiedObjectSet<CoordinateOperation> {
     /**
@@ -73,7 +74,7 @@ final class CoordinateOperationSet extends 
IdentifiedObjectSet<CoordinateOperati
      * </ul>
      *
      * This map does <strong>not</strong> contain all operations to be 
returned by this {@code CoordinateOperationSet},
-     * but only the ones to be returned by the first SQL query documented in 
the class Javadoc.
+     * but only the ones to be returned by the first <abbr>SQL</abbr> query 
documented in the class Javadoc.
      */
     private final Map<String,Integer> projections;
 
@@ -109,7 +110,7 @@ final class CoordinateOperationSet extends 
IdentifiedObjectSet<CoordinateOperati
     }
 
     /**
-     * Creates a coordinate operation for the specified EPSG code.
+     * Creates a coordinate operation for the specified <abbr>EPSG</abbr> code.
      */
     @Override
     protected CoordinateOperation createObject(final String code) throws 
FactoryException {
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
index d2f4d66493..47975c6b37 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGCodeFinder.java
@@ -42,6 +42,7 @@ import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.privy.CollectionsExt;
+import org.apache.sis.pending.jdk.JDK16;
 import org.apache.sis.pending.jdk.JDK19;
 import org.apache.sis.metadata.privy.ReferencingServices;
 import org.apache.sis.metadata.sql.privy.SQLUtilities;
@@ -465,16 +466,11 @@ crs:    if (isInstance(CoordinateReferenceSystem.class, 
object)) {
                     result.add(r.getString(1));
                 }
             }
-            result.remove(null);                    // Should not have null 
element, but let be safe.
-            if (result.size() > 1) {
-                final Object[] id = result.toArray();
-                if (dao.sort(table.unquoted(), id)) {
-                    result.clear();
-                    for (final Object c : id) {
-                        result.add((String) c);
-                    }
-                }
-            }
+            result.remove(null);    // Should not have null element, but let 
be safe.
+            dao.sort(table.unquoted(), result).ifPresent((sorted) -> {
+                result.clear();
+                result.addAll(JDK16.toList(sorted));
+            });
             return result;
         } catch (SQLException exception) {
             throw dao.databaseFailure(Identifier.class, 
String.valueOf(CollectionsExt.first(filters[0].values)), exception);
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 11e88bfd25..44aff1352a 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
@@ -24,11 +24,13 @@ import java.util.LinkedHashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.Date;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.stream.Stream;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
@@ -81,7 +83,6 @@ import 
org.apache.sis.referencing.factory.IdentifiedObjectFinder;
 import org.apache.sis.referencing.privy.WKTKeywords;
 import org.apache.sis.referencing.privy.CoordinateOperations;
 import org.apache.sis.referencing.privy.ReferencingFactoryContainer;
-import org.apache.sis.referencing.privy.Formulas;
 import org.apache.sis.referencing.internal.DeferredCoordinateOperation;
 import org.apache.sis.referencing.internal.DeprecatedCode;
 import org.apache.sis.referencing.internal.EPSGParameterDomain;
@@ -1129,6 +1130,8 @@ next:   for (int i=0; i<codes.length; i++) {
 
     /**
      * Returns the scope from the given authority code.
+     * The given code is a value of the {@code scopes} list
+     * after a call to {@link #getUsages getUsages(…)}.
      *
      * @param  code  the <abbr>EPSG</code> code.
      * @return the scope, or {@code null} if none.
@@ -1150,6 +1153,34 @@ next:   for (int i=0; i<codes.length; i++) {
         return scope;
     }
 
+    /**
+     * Gets the codes of extents and scopes of the object identified by the 
given code in the given table.
+     * The {@code actualTable} argument must be the result of {@code 
translator.toActualTableName(table)}.
+     * The {@code extents} and {@code scopes} collections should be initially 
empty and will be filled by
+     * this method. The same number of codes will be added in both of them.
+     *
+     * @param  actualTable  actual name of the table of the object for which 
to get the usages.
+     * @param  code         <abbr>EPSG</abbr> code of the object for which to 
get the usages.
+     * @param  extents      where to store extent codes, or {@code null} for 
ignoring extents.
+     * @param  scopes       where to store usage codes, or {@code null} for 
ignoring scopes.
+     */
+    private void getUsages(final String actualTable,
+                           final int code,
+                           final Collection<String>  extents,
+                           final Collection<Integer> scopes) throws 
SQLException, FactoryDataException
+    {
+        try (ResultSet result = executeMetadataQuery("Usage",
+                "SELECT EXTENT_CODE, SCOPE_CODE FROM \"Usage\""
+                        + " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?",
+                actualTable, code))
+        {
+            while (result.next()) {
+                if (extents != null) extents.add(getString (code, result, 1));
+                if (scopes  != null) scopes .add(getInteger(code, result, 2));
+            }
+        }
+    }
+
     /**
      * Logs a warning saying that the given code is deprecated and returns the 
code of the proposed replacement.
      *
@@ -1157,7 +1188,7 @@ next:   for (int i=0; i<codes.length; i++) {
      * @param  code    the deprecated code.
      * @return the proposed replacement (may be the "(none)" text). Never 
empty.
      */
-    private String getSupersession(final String table, final Integer code, 
final Locale locale) throws SQLException {
+    private String getReplacement(final String table, final Integer code, 
final Locale locale) throws SQLException {
         String reason = null;
         String replacedBy;
 search: try (ResultSet result = executeMetadataQuery("Deprecation",
@@ -1239,6 +1270,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
          * se we need to fetch and store the extent before to populate the 
`properties` map.
          */
         final Extent extent = (extentCode == null) ? null : 
createExtent(extentCode);
+        final String actualTable = translator.toActualTableName(table);
         /*
          * Get all domains for the object identified by the given code.
          * The table used nere is new in version 10 of EPSG database.
@@ -1248,21 +1280,14 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
         ObjectDomain[] domains = null;
         if (translator.isUsageTableFound()) {
             final var extents = new ArrayList<String>();
-            final var scopes  = new ArrayList<InternationalString>();
-            try (ResultSet result = executeMetadataQuery("Usage",
-                    "SELECT EXTENT_CODE, SCOPE_CODE FROM \"Usage\""
-                            + " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?",
-                    translator.toActualTableName(table), code))
-            {
-                while (result.next()) {
-                    extents.add(getString(code, result, 1));
-                    scopes .add(getScope(getInteger(code, result, 2)));
-                }
-            }
+            final var scopes  = new ArrayList<Integer>();
+            getUsages(actualTable, code, extents, scopes);
             if (!extents.isEmpty()) {
                 domains = new ObjectDomain[extents.size()];
                 for (int i=0; i<domains.length; i++) {
-                    domains[i] = new DefaultObjectDomain(scopes.get(i), 
owner.createExtent(extents.get(i)));
+                    domains[i] = new DefaultObjectDomain(
+                            getScope(scopes.get(i)),
+                            owner.createExtent(extents.get(i)));
                 }
             }
         }
@@ -1285,7 +1310,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
                         + " FROM \"Alias\" INNER JOIN \"Naming System\""
                         + " ON \"Alias\".NAMING_SYSTEM_CODE = \"Naming 
System\".NAMING_SYSTEM_CODE"
                         + " WHERE OBJECT_TABLE_NAME=? AND OBJECT_CODE=?",
-                translator.toActualTableName(table), code))
+                actualTable, code))
         {
             while (result.next()) {
                 final String naming = getOptionalString(result, 1);
@@ -1334,7 +1359,7 @@ search: try (ResultSet result = 
executeMetadataQuery("Deprecation",
         final ImmutableIdentifier identifier;
         if (deprecated) {
             properties.put(AbstractIdentifiedObject.DEPRECATED_KEY, 
Boolean.TRUE);
-            final String replacedBy = getSupersession(table, code, locale);
+            final String replacedBy = getReplacement(table, code, locale);
             identifier = new DeprecatedCode(
                     authority,
                     Constants.EPSG,
@@ -3342,15 +3367,11 @@ next:                   while (r.next()) {
                 if (searchTransformations) {
                     key = "TransformationFromCRS";
                     sql = "SELECT COORD_OP_CODE"
-                            + " FROM \"Coordinate_Operation\" AS CO"
-                            + " JOIN \"Area\" ON AREA_OF_USE_CODE = AREA_CODE"
-                            + " WHERE CO.DEPRECATED=0"   // Do not put spaces 
around "=" - SQLTranslator searches for this exact match.
+                            + " FROM \"Coordinate_Operation\""
+                            + " WHERE DEPRECATED=0"  // Do not put spaces 
around "=" - SQLTranslator searches for this exact match.
                             + " AND SOURCE_CRS_CODE = ?"
                             + " AND TARGET_CRS_CODE = ?"
-                            + " ORDER BY COORD_OP_ACCURACY ASC NULLS LAST, "
-                            + " (AREA_EAST_BOUND_LON - AREA_WEST_BOUND_LON + 
CASE WHEN AREA_EAST_BOUND_LON < AREA_WEST_BOUND_LON THEN 360 ELSE 0 END)"
-                            + " * (AREA_NORTH_BOUND_LAT - 
AREA_SOUTH_BOUND_LAT)"
-                            + " * COS(RADIANS(AREA_NORTH_BOUND_LAT + 
AREA_SOUTH_BOUND_LAT)/2) DESC";
+                            + " ORDER BY COORD_OP_ACCURACY ASC NULLS LAST";
                 } else {
                     key = "ConversionFromCRS";
                     sql = "SELECT PROJECTION_CONV_CODE"
@@ -3368,12 +3389,13 @@ next:                   while (r.next()) {
             /*
              * Search finished. We may have a lot of coordinate operations
              * (e.g. about 40 for "ED50" (EPSG:4230) to "WGS 84" (EPSG:4326)).
-             * Alter the ordering using the information supplied in the 
supersession table.
+             * Alter the ordering using the information supplied in the extents
+             * and supersession tables.
              */
-            final String[] codes = set.getAuthorityCodes();
-            if (codes.length > 1 && sort("Coordinate_Operation", codes)) {
-                set.setAuthorityCodes(codes);
-            }
+            List<String> codes = Arrays.asList(set.getAuthorityCodes());
+            sort("Coordinate_Operation", codes).ifPresent((sorted) -> {
+                set.setAuthorityCodes(sorted.toArray(String[]::new));
+            });
         } catch (SQLException exception) {
             throw databaseFailure(CoordinateOperation.class, label, exception);
         }
@@ -3408,60 +3430,92 @@ next:                   while (r.next()) {
     }
 
     /**
-     * Sorts an array of codes in preference order. This method orders 
pairwise the codes according the information
-     * provided in the supersession table. If the same object is superseded by 
more than one object, then the most
-     * recent one is inserted first. Except for the codes moved as a result of 
pairwise ordering, this method tries
-     * to preserve the old ordering of the supplied codes (since deprecated 
operations should already be last).
-     * The ordering is performed in place.
+     * Sorts a collection of codes in preference order.
+     * This method orders pairwise the codes according the information 
provided in the supersession table.
+     * If the same object is superseded by more than one object, then the most 
recent one is inserted first.
+     * Except for the codes moved as a result of pairwise ordering, this 
method tries to preserve the old
+     * ordering of the supplied codes (since deprecated operations should 
already be last).
      *
-     * @param table  the table of the objects for which to check for 
supersession.
-     * @param codes  the codes, usually as an array of {@link String}. If the 
array do not contains string objects,
-     *               then the {@link Object#toString()} method must return the 
code for each element.
-     * @return {@code true} if the array changed as a result of this method 
call.
+     * @param  table  the table of the objects for which to check for 
supersession.
+     * @param  codes  the codes to sort. This collection will not be modified 
by this method.
+     * @return codes of sorted elements, or empty if this method did not 
changed the codes order.
      */
-    final synchronized boolean sort(final String table, final Object[] codes) 
throws SQLException, FactoryException {
-        int iteration = 0;
-        do {
-            boolean changed = false;
-            for (int i=0; i<codes.length; i++) {
-                final int code;
+    final synchronized Optional<Stream<String>> sort(final String table, final 
Collection<String> codes)
+            throws SQLException, FactoryException
+    {
+        final int size = codes.size();
+        if (size > 1) try {
+            final var elements = new ObjectPertinence[size];
+            final var extents = new ArrayList<String>();
+            final String actualTable = translator.toActualTableName(table);
+            int count = 0;
+            for (final String code : codes) {
+                final int key;
                 try {
-                    code = Integer.parseInt(codes[i].toString());
+                    key = Integer.parseInt(code);
                 } catch (NumberFormatException e) {
                     unexpectedException("sort", e);
                     continue;
                 }
+                if (translator.isUsageTableFound()) {
+                    getUsages(actualTable, key, extents, null);
+                } else {
+                    /*
+                     * For compatibility with EPSG database before version 10.
+                     * We may delete this block in a future Apache SIS version.
+                     * Note: if this block is deleted, consider deleting also
+                     * the finally block and the `TableInfo.areaOfUse` flag.
+                     */
+                    for (final TableInfo info : TableInfo.EPSG) {
+                        if (table.equals(info.unquoted())) {
+                            if (info.areaOfUse) {
+                                try (ResultSet result = executeQueryForCodes(
+                                        "Area",     // Table from EPSG version 
9. Does not exist anymore in version 10.
+                                        "SELECT AREA_OF_USE_CODE FROM \"" + 
table + "\" WHERE " + info.codeColumn + "=?",
+                                        key))
+                                {
+                                    while (result.next()) {
+                                        extents.add(getString(code, result, 
1));
+                                    }
+                                }
+                            }
+                            break;
+                        }
+                    }
+                }
+                final ObjectPertinence element = new ObjectPertinence(key, 
extents, owner);
+                extents.clear();
                 try (ResultSet result = executeMetadataQuery(
                         "Supersession",
                         "SELECT SUPERSEDED_BY FROM \"Supersession\""
                                 + " WHERE OBJECT_TABLE_NAME=? AND 
OBJECT_CODE=?"
                                 + " ORDER BY SUPERSESSION_YEAR DESC",
-                        translator.toActualTableName(table), code))
+                        actualTable, key))
                 {
                     while (result.next()) {
-                        final String replacement = result.getString(1);
-                        if (replacement != null) {
-                            for (int j=i+1; j<codes.length; j++) {
-                                final Object candidate = codes[j];
-                                if (replacement.equals(candidate.toString())) {
-                                    /*
-                                     * Found a code to move in front of the 
superceded one.
-                                     */
-                                    System.arraycopy(codes, i, codes, i+1, 
j-i);
-                                    codes[i++] = candidate;
-                                    changed = true;
-                                }
-                            }
+                        final int replacement = result.getInt(1);
+                        if (!result.wasNull()) {
+                            element.replacedBy.add(replacement);
                         }
                     }
                 }
+                elements[count++] = element;
             }
-            if (!changed) {
-                return iteration != 0;
+            if (ObjectPertinence.sort(elements)) {
+                return 
Optional.of(Arrays.stream(elements).map(ObjectPertinence::code));
+            }
+        } finally {
+            /*
+             * Remove from the cache because the table name may change.
+             * Note: this is for compatibility with EPSG before version 10.
+             * This block may be deleted in a future Apache SIS version.
+             */
+            PreparedStatement stmt = statements.remove("Area");
+            if (stmt != null) {
+                stmt.close();
             }
         }
-        while (++iteration < Formulas.MAXIMUM_ITERATIONS);      // Arbitrary 
limit for avoiding never-ending loop.
-        return true;
+        return Optional.empty();
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/ObjectPertinence.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/ObjectPertinence.java
new file mode 100644
index 0000000000..82da6646a7
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/ObjectPertinence.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.factory.sql;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import org.opengis.util.FactoryException;
+import org.opengis.metadata.extent.Extent;
+import org.opengis.metadata.extent.GeographicBoundingBox;
+import org.apache.sis.metadata.iso.extent.Extents;
+import org.apache.sis.referencing.privy.Formulas;
+import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
+import org.apache.sis.util.privy.CollectionsExt;
+import org.apache.sis.util.privy.Strings;
+
+
+/**
+ * Collect information needed for evaluating the pertinence of an object.
+ * The criteria are, in order:
+ *
+ * <ol>
+ *   <li>Superseded objects are last.</li>
+ *   <li>Largest domain of validity (after intersection with <abbr>AOI</abbr> 
are first.</li>
+ * </ol>
+ *
+ * This class defines a {@link #compareTo(ObjectPertinence)} method which is 
inconsistent
+ * with {@link #equals(Object)}, but this is okay for the purpose of this 
internal class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+final class ObjectPertinence implements Comparable<ObjectPertinence> {
+    /**
+     * Code of the object for which the pertinence is evaluated.
+     */
+    private final int code;
+
+    /**
+     * An estimation of the surface of the domain of validity as a negative 
number, or NaN if none.
+     * The units of measurement do not matter here. The only requirement is 
that larger areas are
+     * represented by <em>smaller</em> numbers, in order to have them sorted 
first.
+     * The {@link Double#NaN} values will be sorted last.
+     */
+    private final double area;
+
+    /**
+     * The objects to use instead of the object identified by the code given 
at construction time.
+     * This list is non-empty when the object is superseded by more recent 
objects.
+     * This list is empty if there is no supersession.
+     */
+    final List<Integer> replacedBy;
+
+    /**
+     * Creates a new set of information for the object identified by the given 
code.
+     *
+     * @param  code     the authority code of the object for which to collect 
information.
+     * @param  extents  authority codes of the extents of the object 
identified by {@code code}.
+     * @param  factory  the factory to use for getting extent objects.
+     * @throws FactoryException if an error occurred while fetching extents.
+     */
+    ObjectPertinence(final int code, final List<String> extents, final 
GeodeticAuthorityFactory factory)
+            throws FactoryException
+    {
+        this.code = code;
+        GeographicBoundingBox bbox = null;
+        for (final String extentCode : extents) {
+            final Extent extent = factory.createExtent(extentCode);
+            bbox = Extents.union(bbox, 
Extents.getGeographicBoundingBox(extent));
+        }
+        area = -Extents.area(bbox);
+        replacedBy = new ArrayList<>();
+    }
+
+    /**
+     * Returns the code of the object for which the pertinence is evaluated.
+     */
+    final String code() {
+        return Integer.toString(code);
+    }
+
+    /**
+     * Determines the ordering based on the extent.
+     * This method does not take supersession in account.
+     * This method is inconsistent with {@link #equals(Object)},
+     * but this is okay for the purpose of this internal class.
+     */
+    @Override
+    public int compareTo(final ObjectPertinence other) {
+        return Double.compare(area, other.area);    // Reminder: we want NaN 
to be sorted last.
+    }
+
+    /**
+     * Sorts in-place the elements that are in the given array.
+     *
+     * @param  elements  the elements to sort.
+     * @return {@code true} if the array changed as a result of this method 
call.
+     */
+    static boolean sort(final ObjectPertinence[] elements) {
+        boolean changed = false;
+        for (int i=1; i<elements.length; i++) {
+            if (elements[i-1].compareTo(elements[i]) > 0) {
+                Arrays.sort(elements);
+                changed = true;
+                break;
+            }
+        }
+        int iteration = 0;
+        boolean redo;
+        do {
+            redo = false;
+            for (int i=0; i<elements.length; i++) {
+                for (final Integer replacement : elements[i].replacedBy) {
+                    for (int j=i+1; j<elements.length; j++) {
+                        final ObjectPertinence candidate = elements[j];
+                        if (candidate.code == replacement) {
+                            /*
+                             * Found an element to move in front of the 
superseded ones.
+                             */
+                            System.arraycopy(elements, i, elements, i+1, j-i);
+                            elements[i++] = candidate;
+                            redo = changed = true;
+                        }
+                    }
+                }
+            }
+        } while (redo && ++iteration < Formulas.MAXIMUM_ITERATIONS);
+        return changed;
+    }
+
+    /**
+     * Returns a string representation for debugging purposes.
+     */
+    @Override
+    public String toString() {
+        return Strings.toString(getClass(),
+                "code", code,
+                "area", Math.abs((float) (area / 1E+6)),    // Square 
kilometers
+                "replacedBy", CollectionsExt.first(replacedBy));
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
index 737a507607..b2afeba4e5 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/TableInfo.java
@@ -84,7 +84,7 @@ final class TableInfo {
                 new String[]   {"projected",          "geographic",          
"geocentric",
                                 "vertical",           "compound",            
"engineering",
                                 "derived",            "temporal",            
"parametric"},             // See comment below
-                "SHOW_CRS"),
+                "SHOW_CRS", true),
                 /*
                  * Above declaration could omit Derived, Temporal and 
Parametric cases because they are not defined
                  * by the EPSG repository (at least as of version 8.9). In 
particular we are not sure if EPSG would
@@ -103,14 +103,14 @@ final class TableInfo {
                 new String[]   {WKTKeywords.Cartesian,  
WKTKeywords.ellipsoidal,  WKTKeywords.vertical,  WKTKeywords.linear,
                                 WKTKeywords.spherical,  WKTKeywords.polar,     
   WKTKeywords.cylindrical,
                                 WKTKeywords.temporal,   
WKTKeywords.parametric,   WKTKeywords.affine},      // Same comment as in the 
CRS case above.
-                null),
+                null, false),
 
         new TableInfo(CoordinateSystemAxis.class,
                 "\"Coordinate Axis\" AS CA INNER JOIN \"Coordinate Axis Name\" 
AS CAN " +
                                     "ON 
CA.COORD_AXIS_NAME_CODE=CAN.COORD_AXIS_NAME_CODE",
                 "COORD_AXIS_CODE",
                 "COORD_AXIS_NAME",
-                null, null, null, null),
+                null, null, null, null, false),
 
         DATUM = new TableInfo(Datum.class,
                 "\"Datum\"",
@@ -121,19 +121,19 @@ final class TableInfo {
                                  TemporalDatum.class,  ParametricDatum.class},
                 new String[]   {"geodetic",           "vertical",            
"engineering",
                                 "temporal",           "parametric"},         
// Same comment as in the CRS case above.
-                null),
+                null, true),
 
         ELLIPSOID = new TableInfo(Ellipsoid.class,
                 "\"Ellipsoid\"",
                 "ELLIPSOID_CODE",
                 "ELLIPSOID_NAME",
-                null, null, null, null),
+                null, null, null, null, false),
 
         new TableInfo(PrimeMeridian.class,
                 "\"Prime Meridian\"",
                 "PRIME_MERIDIAN_CODE",
                 "PRIME_MERIDIAN_NAME",
-                null, null, null, null),
+                null, null, null, null, false),
 
         new TableInfo(CoordinateOperation.class,
                 "\"Coordinate_Operation\"",
@@ -142,25 +142,25 @@ final class TableInfo {
                 "COORD_OP_TYPE",
                 new Class<?>[] { Conversion.class, Transformation.class},
                 new String[]   {"conversion",     "transformation"},
-                "SHOW_OPERATION"),
+                "SHOW_OPERATION", true),
 
         new TableInfo(OperationMethod.class,
                 "\"Coordinate_Operation Method\"",
                 "COORD_OP_METHOD_CODE",
                 "COORD_OP_METHOD_NAME",
-                null, null, null, null),
+                null, null, null, null, false),
 
         new TableInfo(ParameterDescriptor.class,
                 "\"Coordinate_Operation Parameter\"",
                 "PARAMETER_CODE",
                 "PARAMETER_NAME",
-                null, null, null, null),
+                null, null, null, null, false),
 
         new TableInfo(Unit.class,
                 "\"Unit of Measure\"",
                 "UOM_CODE",
                 "UNIT_OF_MEAS_NAME",
-                null, null, null, null),
+                null, null, null, null, false),
     };
 
     /**
@@ -213,6 +213,12 @@ final class TableInfo {
      */
     final String showColumn;
 
+    /**
+     * Whether the table had an {@code "AREA_OF_USE_CODE"} column
+     * in the legacy versions (before version 10) of the <abbr>EPSG</abbr> 
database.
+     */
+    final boolean areaOfUse;
+
     /**
      * Stores information about a specific table.
      *
@@ -224,11 +230,12 @@ final class TableInfo {
      * @param subTypes    sub-interfaces of {@link #type} to handle, or {@code 
null} if none.
      * @param typeNames   names of {@code subTypes} in the database, or {@code 
null} if none.
      * @param showColumn  the column that specify if the object should be 
shown, or {@code null} if none.
+     * @param areaOfUse   whether the table had an {@code "AREA_OF_USE_CODE"} 
column in the legacy versions.
      */
     private TableInfo(final Class<?> type,
                       final String table, final String codeColumn, final 
String nameColumn,
                       final String typeColumn, final Class<?>[] subTypes, 
final String[] typeNames,
-                      final String showColumn)
+                      final String showColumn, final boolean areaOfUse)
     {
         this.type       = type;
         this.table      = table;
@@ -238,6 +245,7 @@ final class TableInfo {
         this.subTypes   = subTypes;
         this.typeNames  = typeNames;
         this.showColumn = showColumn;
+        this.areaOfUse  = areaOfUse;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
index d4139330cc..6543f29648 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
@@ -45,11 +45,13 @@ import org.opengis.referencing.operation.MathTransform;
 import org.opengis.util.FactoryException;
 import org.apache.sis.system.Loggers;
 import org.apache.sis.referencing.CRS;
+import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
 import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
 import org.apache.sis.referencing.factory.IdentifiedObjectFinder;
 import org.apache.sis.util.collection.BackingStoreException;
+import org.apache.sis.metadata.iso.citation.Citations;
 
 // Test dependencies
 import org.junit.jupiter.api.Tag;
@@ -856,7 +858,7 @@ public final class EPSGFactoryTest extends TestCaseWithLogs 
{
         assertEquals(1.0, 
AbstractCoordinateOperation.castOrCopy(operation3).getLinearAccuracy());
         /*
          * Creates from CRS codes. There is 40 such operations in EPSG version 
6.7.
-         * The preferred one (according the "supersession" table) is EPSG:1612.
+         * The one with the largest domain of validity is EPSG:1133.
          */
         final Set<CoordinateOperation> all = 
factory.createFromCoordinateReferenceSystemCodes("4230", "4326");
         assertTrue(all.size() >= 3, "Number of coordinate operations.");
@@ -865,14 +867,22 @@ public final class EPSGFactoryTest extends 
TestCaseWithLogs {
         assertTrue(all.contains(operation3), "contains(“EPSG::1989”)");
 
         int count = 0;
+        boolean found1590 = false;  // In Norway, superseded by 1612.
+        boolean found1612 = false;  // Replacement for 1590.
         for (final CoordinateOperation tr : all) {
             assertSame(sourceCRS, tr.getSourceCRS());
             assertSame(targetCRS, tr.getTargetCRS());
             if (count == 0) {   // Preferred transformation (see above 
comment).
-                assertEpsgNameAndIdentifierEqual("ED50 to WGS 84 (23)", 1612, 
tr);
+                assertEpsgNameAndIdentifierEqual("ED50 to WGS 84 (1)", 1133, 
tr);
+            }
+            switch (Integer.parseInt(IdentifiedObjects.getIdentifier(tr, 
Citations.EPSG).getCode())) {
+                case 1612: found1612 = true; assertFalse(found1590); break;    
 // Should be find first.
+                case 1590: found1590 = true; assertTrue (found1612); break;    
 // Should be after 1612.
             }
             count++;
         }
+        assertTrue(found1612);
+        assertFalse(found1590);                 // TODO `assertTrue` if we 
support "Norway Offshore Interpolation".
         assertEquals(count, all.size());        // Size may have been modified 
after above loop.
         loggings.clear();                       // Too installation-dependent 
for testing them.
     }
@@ -977,8 +987,8 @@ public final class EPSGFactoryTest extends TestCaseWithLogs 
{
          * not be selected in this test.
          */
         final Iterator<IdentifiedObject> it = find.iterator();
-        assertEpsgNameAndIdentifierEqual("Beijing 1954 / 3-degree Gauss-Kruger 
CM 135E",  2442, it.next());
         assertEpsgNameAndIdentifierEqual("Beijing 1954 / Gauss-Kruger CM 
135E", 21463, it.next());
+        assertEpsgNameAndIdentifierEqual("Beijing 1954 / 3-degree Gauss-Kruger 
CM 135E", 2442, it.next());
         assertFalse(it.hasNext());
         loggings.assertNoUnexpectedLog();
     }

Reply via email to