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 7a049f9417 Update for the removal of the non-standard 
`org.opengis.referencing.operation.Projection` interface.
7a049f9417 is described below

commit 7a049f9417379966bb8b6351c657657c916192d9
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Thu Apr 18 16:01:05 2024 +0200

    Update for the removal of the non-standard 
`org.opengis.referencing.operation.Projection` interface.
---
 .../main/org/apache/sis/xml/XLink.java             |   1 +
 .../sis/referencing/crs/AbstractDerivedCRS.java    |  39 ++----
 .../sis/referencing/crs/DefaultDerivedCRS.java     |  11 +-
 .../sis/referencing/crs/DefaultProjectedCRS.java   |  18 +--
 .../sis/referencing/crs/ExplicitParameters.java    |   2 +-
 .../referencing/factory/sql/AuthorityCodes.java    |  45 ++-----
 .../referencing/factory/sql/EPSGDataAccess.java    |  32 +----
 .../sis/referencing/factory/sql/TableInfo.java     |   4 +-
 .../operation/AbstractCoordinateOperation.java     |   4 +-
 .../referencing/operation/DefaultConversion.java   |  75 ++++-------
 .../DefaultCoordinateOperationFactory.java         |  24 +---
 .../operation/DefaultOperationMethod.java          |  20 ++-
 .../operation/DefaultPassThroughOperation.java     |   3 +-
 .../referencing/operation/DefaultProjection.java   | 139 ---------------------
 .../apache/sis/referencing/operation/SubTypes.java |  75 -----------
 .../operation/provider/AbstractProvider.java       |   6 +-
 .../operation/provider/Equirectangular.java        |   4 +-
 .../operation/provider/MapProjection.java          |   4 +-
 .../operation/provider/PseudoPlateCarree.java      |   3 -
 .../provider/ZonedTransverseMercator.java          |   4 +-
 .../transform/DefaultMathTransformFactory.java     |  12 +-
 .../referencing/factory/sql/EPSGFactoryTest.java   |  11 +-
 .../operation/CoordinateOperationFinderTest.java   |   3 +-
 .../operation/DefaultConversionTest.java           |  21 ++--
 .../operation/provider/ProvidersTest.java          |   3 +-
 .../transform/DefaultMathTransformFactoryTest.java |  19 +--
 .../report/CoordinateOperationMethods.java         |   4 +-
 geoapi/snapshot                                    |   2 +-
 28 files changed, 116 insertions(+), 472 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XLink.java 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XLink.java
index e0ad0e8901..b5cf1d8592 100644
--- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XLink.java
+++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XLink.java
@@ -398,6 +398,7 @@ public class XLink implements Serializable {
         if (hashCode != 0) {
             throw new 
UnsupportedOperationException(Errors.format(Errors.Keys.UnmodifiableObject_1, 
"XLink"));
         }
+        @SuppressWarnings("LocalVariableHidesMemberVariable")
         final Type type = this.type;
         if (type != null) {
             if (value != null) {
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
index e27652217b..7b2f7e7655 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
@@ -51,8 +51,6 @@ import org.apache.sis.util.resources.Errors;
  * A coordinate reference system that is defined by its coordinate conversion 
from another CRS.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- *
- * @param <C>  the conversion type, either {@code Conversion} or {@code 
Projection}.
  */
 @XmlType(name = "AbstractGeneralDerivedCRSType")
 @XmlRootElement(name = "AbstractGeneralDerivedCRS")
@@ -60,7 +58,7 @@ import org.apache.sis.util.resources.Errors;
     DefaultDerivedCRS.class,
     DefaultProjectedCRS.class
 })
-abstract class AbstractDerivedCRS<C extends Conversion> extends AbstractCRS 
implements DerivedCRS {
+abstract class AbstractDerivedCRS extends AbstractCRS implements DerivedCRS {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -76,7 +74,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
      * @see #getConversionFromBase()
      */
     @SuppressWarnings("serial")         // Most SIS implementations are 
serializable.
-    private C conversionFromBase;
+    private Conversion conversionFromBase;
 
     /**
      * Creates a derived CRS from a defining conversion.
@@ -111,7 +109,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
      * Creates a new CRS derived from the specified one, but with different 
axis order or unit.
      * This is for implementing the {@link #createSameType(AbstractCS)} method 
only.
      */
-    AbstractDerivedCRS(final AbstractDerivedCRS<C> original, final AbstractCS 
derivedCS) {
+    AbstractDerivedCRS(final AbstractDerivedCRS original, final AbstractCS 
derivedCS) {
         super(original, null, derivedCS);
         final Conversion conversion = original.conversionFromBase;
         conversionFromBase = createConversionFromBase(null, (SingleCRS) 
conversion.getSourceCRS(), conversion);
@@ -134,8 +132,8 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
         ArgumentChecks.ensureNonNull("baseCRS", baseCRS);
         ArgumentChecks.ensureNonNull("method", method);
         ArgumentChecks.ensureNonNull("baseToDerived", baseToDerived);
-        conversionFromBase = (C) new DefaultConversion(   // Cast to (C) is 
valid only for DefaultDerivedCRS.
-                ConversionKeys.unprefix(properties), baseCRS, this, 
interpolationCRS, method, baseToDerived);
+        conversionFromBase = new 
DefaultConversion(ConversionKeys.unprefix(properties),
+                baseCRS, this, interpolationCRS, method, baseToDerived);
     }
 
     /**
@@ -161,13 +159,13 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
      * instance is advanced enough for allowing the {@code 
getCoordinateSystem()} method to execute.
      * Subclasses should make their {@code getCoordinateSystem()} method final 
for better guarantees.</p>
      */
-    private C createConversionFromBase(final Map<String,?> properties, final 
SingleCRS baseCRS, final Conversion conversion) {
+    private Conversion createConversionFromBase(final Map<String,?> 
properties, final SingleCRS baseCRS, final Conversion conversion) {
         MathTransformFactory factory = null;
         if (properties != null) {
             factory = (MathTransformFactory) 
properties.get(ReferencingFactoryContainer.MT_FACTORY);
         }
         try {
-            return 
DefaultConversion.castOrCopy(conversion).specialize(getConversionType(), 
baseCRS, this, factory);
+            return 
DefaultConversion.castOrCopy(conversion).specialize(baseCRS, this, factory);
         } catch (FactoryException e) {
             throw new 
IllegalArgumentException(Errors.forProperties(properties).getString(
                     Errors.Keys.IllegalArgumentValue_2, "conversion", 
conversion.getName()), e);
@@ -175,22 +173,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
     }
 
     /**
-     * Returns the type of conversion associated to this {@code 
AbstractDerivedCRS}.
-     *
-     * <p><b>WARNING:</b> this method is invoked (indirectly) at construction 
time.
-     * Consequently, it shall return a constant value - this method is not 
allowed to
-     * depend on the object state.</p>
-     */
-    abstract Class<C> getConversionType();
-
-    /**
-     * Returns the GeoAPI interface implemented by this class.
-     */
-    @Override
-    public abstract Class<? extends DerivedCRS> getInterface();
-
-    /**
-     * Returns the datum of the {@linkplain #getBaseCRS() base CRS}.
+     * Returns the datum of the base CRS.
      *
      * @return the datum of the base CRS.
      */
@@ -198,13 +181,13 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
     public abstract Datum getDatum();
 
     /**
-     * Returns the conversion from the {@linkplain #getBaseCRS() base CRS} to 
this CRS.
+     * Returns the conversion from the base CRS to this CRS.
      *
      * @return the conversion to this CRS.
      */
     @Override
     @XmlElement(name = "conversion", required = true)
-    public C getConversionFromBase() {
+    public Conversion getConversionFromBase() {
         return conversionFromBase;
     }
 
@@ -297,7 +280,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> 
extends AbstractCRS impl
      * At this state, the given conversion has null {@code sourceCRS} and 
{@code targetCRS}.
      * Those CRS will be set later, in {@link #afterUnmarshal(Unmarshaller, 
Object)}.
      */
-    private void setConversionFromBase(final C conversion) {
+    private void setConversionFromBase(final Conversion conversion) {
         if (conversionFromBase == null) {
             conversionFromBase = conversion;
         } else {
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
index 631d67866d..832a631500 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
@@ -105,7 +105,7 @@ import org.opengis.referencing.cs.ParametricCS;
     "coordinateSystem"
 })
 @XmlRootElement(name = "DerivedCRS")
-public class DefaultDerivedCRS extends AbstractDerivedCRS<Conversion> 
implements DerivedCRS {
+public class DefaultDerivedCRS extends AbstractDerivedCRS implements 
DerivedCRS {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -380,15 +380,6 @@ public class DefaultDerivedCRS extends 
AbstractDerivedCRS<Conversion> implements
         }
     }
 
-    /**
-     * Returns the type of conversion associated to this {@code 
DefaultDerivedCRS}.
-     * Must be a hard-coded, constant value (not dependent on object state).
-     */
-    @Override
-    final Class<Conversion> getConversionType() {
-        return Conversion.class;
-    }
-
     /**
      * Returns the GeoAPI interface implemented by this class.
      * The SIS implementation returns {@code DerivedCRS.class}.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
index 0a69f68c58..bca03ade69 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
@@ -28,7 +28,6 @@ import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.CoordinateSystem;                 // For 
javadoc
 import org.opengis.referencing.datum.GeodeticDatum;
 import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.geometry.MismatchedDimensionException;
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.cs.AbstractCS;
@@ -72,7 +71,7 @@ import org.apache.sis.util.Workaround;
     "coordinateSystem"
 })
 @XmlRootElement(name = "ProjectedCRS")
-public class DefaultProjectedCRS extends AbstractDerivedCRS<Projection> 
implements ProjectedCRS {
+public class DefaultProjectedCRS extends AbstractDerivedCRS implements 
ProjectedCRS {
     /**
      * Serial number for inter-operability with different versions.
      */
@@ -191,15 +190,6 @@ public class DefaultProjectedCRS extends 
AbstractDerivedCRS<Projection> implemen
                 ? (DefaultProjectedCRS) object : new 
DefaultProjectedCRS(object);
     }
 
-    /**
-     * Returns the type of conversion associated to this {@code 
DefaultProjectedCRS}.
-     * Must be a hard-coded, constant value (not dependent on object state).
-     */
-    @Override
-    final Class<Projection> getConversionType() {
-        return Projection.class;
-    }
-
     /**
      * Returns the GeoAPI interface implemented by this class.
      * The SIS implementation returns {@code ProjectedCRS.class}.
@@ -236,8 +226,8 @@ public class DefaultProjectedCRS extends 
AbstractDerivedCRS<Projection> implemen
      */
     @Override
     public GeodeticCRS getBaseCRS() {
-        final Projection projection = super.getConversionFromBase();
-        return (projection != null) ? projection.getSourceCRS() : null;
+        final Conversion projection = super.getConversionFromBase();
+        return (projection != null) ? (GeodeticCRS) projection.getSourceCRS() 
: null;
     }
 
     /**
@@ -257,7 +247,7 @@ public class DefaultProjectedCRS extends 
AbstractDerivedCRS<Projection> implemen
      * @return the map projection from base CRS to this CRS.
      */
     @Override
-    public Projection getConversionFromBase() {
+    public Conversion getConversionFromBase() {
         return super.getConversionFromBase();
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/ExplicitParameters.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/ExplicitParameters.java
index 5984372e29..65a7624e86 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/ExplicitParameters.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/ExplicitParameters.java
@@ -59,7 +59,7 @@ final class ExplicitParameters extends FormattableObject {
     /**
      * Creates a new temporary {@code Conversion} elements for the parameters 
of the given CRS.
      */
-    ExplicitParameters(final AbstractDerivedCRS<?> crs, final String keyword) {
+    ExplicitParameters(final AbstractDerivedCRS crs, final String keyword) {
         conversion = crs.getConversionFromBase();
         final Datum datum = crs.getDatum();
         ellipsoid = (datum instanceof GeodeticDatum) ? ((GeodeticDatum) 
datum).getEllipsoid() : null;
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
index 9fd9585b36..6dab326502 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
@@ -24,7 +24,6 @@ import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.PreparedStatement;
 import java.sql.Statement;
-import org.opengis.referencing.operation.Projection;
 import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.util.collection.IntegerList;
 import org.apache.sis.util.privy.AbstractMap;
@@ -79,11 +78,6 @@ final class AuthorityCodes extends 
AbstractMap<String,String> implements Seriali
      */
     final Class<?> type;
 
-    /**
-     * {@code true} if {@link #type} is assignable to {@link Projection}.
-     */
-    private final transient boolean isProjection;
-
     /**
      * The SQL commands that this {@code AuthorityCodes} may need to execute.
      * In this array:
@@ -165,7 +159,6 @@ final class AuthorityCodes extends 
AbstractMap<String,String> implements Seriali
          * Other information opportunistically computed from above search.
          */
         this.type = tableType;
-        isProjection = Projection.class.isAssignableFrom(tableType);
     }
 
     /**
@@ -177,14 +170,6 @@ final class AuthorityCodes extends 
AbstractMap<String,String> implements Seriali
         return new CloseableReference(this, factory, statements);
     }
 
-    /**
-     * Returns {@code true} if the specified code should be included in this 
map.
-     */
-    private boolean filter(final int code) throws SQLException {
-        assert Thread.holdsLock(factory);
-        return !isProjection || factory.isProjection(code);
-    }
-
     /**
      * Returns the code at the given index, or -1 if the index is out of 
bounds.
      *
@@ -216,10 +201,8 @@ final class AuthorityCodes extends 
AbstractMap<String,String> implements Seriali
                         return -1;
                     }
                     code = r.getInt(1);
-                    if (filter(code)) {
-                        codes.addInt(code);
-                        more--;
-                    }
+                    codes.addInt(code);
+                    more--;
                 } while (more >= 0);
             }
         }
@@ -273,19 +256,17 @@ final class AuthorityCodes extends 
AbstractMap<String,String> implements Seriali
             }
             try {
                 synchronized (factory) {
-                    if (filter(n)) {
-                        PreparedStatement statement = (PreparedStatement) 
statements[ONE];
-                        if (statement == null) {
-                            statements[ONE] = statement = 
factory.connection.prepareStatement(sql[ONE]);
-                            sql[ONE] = null;    // Not needed anymore.
-                        }
-                        statement.setInt(1, n);
-                        try (ResultSet r = statement.executeQuery()) {
-                            while (r.next()) {
-                                String name = r.getString(1);
-                                if (name != null) {
-                                    return name;
-                                }
+                    PreparedStatement statement = (PreparedStatement) 
statements[ONE];
+                    if (statement == null) {
+                        statements[ONE] = statement = 
factory.connection.prepareStatement(sql[ONE]);
+                        sql[ONE] = null;    // Not needed anymore.
+                    }
+                    statement.setInt(1, n);
+                    try (ResultSet r = statement.executeQuery()) {
+                        while (r.next()) {
+                            String name = r.getString(1);
+                            if (name != null) {
+                                return name;
                             }
                         }
                     }
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 30a53e2475..ba8f9caf19 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
@@ -285,14 +285,6 @@ public class EPSGDataAccess extends 
GeodeticAuthorityFactory implements CRSAutho
      */
     private final Map<Integer,AxisName> axisNames = new HashMap<>();
 
-    /**
-     * Cache for whether conversions are projections. This service is not 
provided by {@code ConcurrentAuthorityFactory}
-     * since the check for conversion type is used internally in this class.
-     *
-     * @see #isProjection(Integer)
-     */
-    private final Map<Integer,Boolean> isProjection = new HashMap<>();
-
     /**
      * Cache of naming systems other than EPSG. There is usually few of them 
(at most 15).
      * This is used for aliases.
@@ -1447,7 +1439,7 @@ codes:  for (int i=0; i<codes.length; i++) {
                             } catch (ClassCastException e) {
                                 // Should never happen in a well-formed EPSG 
database.
                                 // If happen anyway, the ClassCastException 
cause will give more hints than just the message.
-                                throw (NoSuchAuthorityCodeException) 
noSuchAuthorityCode(Projection.class, opCode).initCause(e);
+                                throw (NoSuchAuthorityCodeException) 
noSuchAuthorityCode(Conversion.class, opCode).initCause(e);
                             }
                             final CoordinateReferenceSystem baseCRS;
                             final boolean suspendParamChecks;
@@ -3128,28 +3120,6 @@ next:                   while (r.next()) {
         }
     }
 
-    /**
-     * Returns {@code true} if the {@link CoordinateOperation} for the 
specified code is a {@link Projection}.
-     * The caller must have verified that the designed operation is a {@link 
Conversion} before to invoke this method.
-     *
-     * @throws SQLException if an error occurred while querying the database.
-     */
-    final boolean isProjection(final Integer code) throws SQLException {
-        Boolean projection = isProjection.get(code);
-        if (projection == null) {
-            try (ResultSet result = executeQuery("isProjection",
-                    "SELECT COORD_REF_SYS_CODE" +
-                    " FROM [Coordinate Reference System]" +
-                    " WHERE PROJECTION_CONV_CODE = ?" +
-                      " AND CAST(COORD_REF_SYS_KIND AS " + 
TableInfo.ENUM_REPLACEMENT + ") LIKE 'projected%'", code))
-            {
-                projection = result.next();
-            }
-            isProjection.put(code, projection);
-        }
-        return projection;
-    }
-
     /**
      * 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
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 c7ed64c976..61f0df5aab 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
@@ -139,8 +139,8 @@ final class TableInfo {
                 "COORD_OP_CODE",
                 "COORD_OP_NAME",
                 "COORD_OP_TYPE",
-                new Class<?>[] { Projection.class, Conversion.class, 
Transformation.class},
-                new String[]   {"conversion",     "conversion",     
"transformation"},
+                new Class<?>[] { Conversion.class, Transformation.class},
+                new String[]   {"conversion",     "transformation"},
                 "SHOW_OPERATION"),
                 // Note: Projection is handled in a special way.
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
index 9bd95fe8b8..14326610b7 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
@@ -436,9 +436,9 @@ check:      for (int isTarget=0; ; isTarget++) {        // 
0 == source check; 1
      * <ul>
      *   <li>If the given object is {@code null}, then this method returns 
{@code null}.</li>
      *   <li>Otherwise if the given object is an instance of
-     *       {@link org.opengis.referencing.operation.Transformation},
      *       {@link org.opengis.referencing.operation.Conversion},
-     *       {@link org.opengis.referencing.operation.Projection},
+     *       {@link org.opengis.referencing.operation.Transformation},
+     *       {@link org.opengis.referencing.operation.PointMotionOperation},
      *       {@link org.opengis.referencing.operation.PassThroughOperation} or
      *       {@link org.opengis.referencing.operation.ConcatenatedOperation},
      *       then this method delegates to the {@code castOrCopy(…)} method of 
the corresponding SIS subclass.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
index 1e76500102..90cf08b7bd 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultConversion.java
@@ -23,7 +23,6 @@ import javax.measure.IncommensurableException;
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -64,8 +63,7 @@ import org.apache.sis.util.resources.Errors;
  * MathTransform, ParameterValueGroup) constructor} for such defining 
conversions.
  *
  * <p>After the source and target CRS become known, we can invoke the {@link 
#specialize specialize(…)} method for
- * {@linkplain DefaultMathTransformFactory#createParameterizedTransform 
creating a math transform from the parameters},
- * instantiate a new {@code Conversion} of a more specific type ({@link 
Projection}) if relevant,
+ * {@linkplain DefaultMathTransformFactory#createParameterizedTransform 
creating a math transform from the parameters}
  * and assign the source and target CRS to it.</p>
  *
  * <h2>Immutability and thread safety</h2>
@@ -130,8 +128,8 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
      * {@linkplain org.apache.sis.referencing.crs.DefaultDerivedCRS derived 
CRS} construction.</p>
      *
      * <h4>Example</h4>
-     * Converting time instants from a {@linkplain 
org.apache.sis.referencing.crs.DefaultTemporalCRS temporal CRS} using
-     * the <i>January 1st, 1950</i> epoch to another temporal CRS using the 
<i>January 1st, 1970</i> epoch
+     * Converting time instants from a {@linkplain 
org.apache.sis.referencing.crs.DefaultTemporalCRS temporal CRS}
+     * using the <i>January 1st, 1950</i> epoch to another temporal CRS using 
the <i>January 1st, 1970</i> epoch
      * is a datum change, since the epoch is part of {@linkplain 
org.apache.sis.referencing.datum.DefaultTemporalDatum
      * temporal datum} definition. However, such operation does not have all 
the accuracy issues of transformations
      * between geodetic datum (empirically determined, over-determined 
systems, stochastic nature of the parameters).
@@ -219,13 +217,11 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
      * @param source      the new source CRS.
      * @param target      the new target CRS.
      * @param factory     the factory to use for creating a transform from the 
parameters or for performing axis changes.
-     * @param actual      an array of length 1 where to store the actual 
operation method used by the math transform factory.
      */
-    DefaultConversion(final Conversion definition,
-                      final CoordinateReferenceSystem source,
-                      final CoordinateReferenceSystem target,
-                      final MathTransformFactory factory,
-                      final OperationMethod[] actual) throws FactoryException
+    private DefaultConversion(final Conversion definition,
+                              final CoordinateReferenceSystem source,
+                              final CoordinateReferenceSystem target,
+                              final MathTransformFactory factory) throws 
FactoryException
     {
         super(definition);
         int interpDim = 
ReferencingUtilities.getDimension(super.getInterpolationCRS().orElse(null));
@@ -254,7 +250,6 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
                     context = 
ReferencingUtilities.createTransformContext(source, target);
                 }
                 transform = ((DefaultMathTransformFactory) 
factory).createParameterizedTransform(parameters, context);
-                actual[0] = context.getMethodUsed();
                 setParameterValues(context.getCompletedParameters(), 
context.getContextualParameters());
             } else {
                 /*
@@ -263,7 +258,6 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
                  * the code should work anyway.
                  */
                 transform = factory.createBaseToDerived(source, parameters, 
target.getCoordinateSystem());
-                actual[0] = factory.getLastMethodUsed();
             }
         } else {
             /*
@@ -273,7 +267,7 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
              * method for this job.
              */
             if (sourceCRS == null && targetCRS == null && factory instanceof 
DefaultMathTransformFactory) {
-                final DefaultMathTransformFactory.Context context = new 
DefaultMathTransformFactory.Context();
+                final var context = new DefaultMathTransformFactory.Context();
                 context.setSource(source.getCoordinateSystem());
                 context.setTarget(target.getCoordinateSystem());    // See 
comment on the other setTarget(…) call.
                 transform = ((DefaultMathTransformFactory) 
factory).swapAndScaleAxes(transform, context);
@@ -333,11 +327,7 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
         if (object == null || object instanceof DefaultConversion) {
             return (DefaultConversion) object;
         }
-        if (object instanceof Projection) {
-            return new DefaultProjection((Projection) object);
-        } else {
-            return new DefaultConversion(object);
-        }
+        return new DefaultConversion(object);
     }
 
     /**
@@ -352,32 +342,16 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
     }
 
     /**
-     * Returns a specialization of this conversion with a more specific type 
and non-null <abbr>CRS</abbr>s.
+     * Returns a specialization of this conversion with non-null 
<abbr>CRS</abbr>s.
      * This {@code specialize(…)} method is typically invoked on {@linkplain 
#DefaultConversion(Map,
      * OperationMethod, MathTransform, ParameterValueGroup) defining 
conversion} instances,
      * when more information become available about the conversion to create.
      *
-     * <p>The given {@code baseType} argument can be one of the following 
values:</p>
-     * <ul>
-     *   <li><code>{@linkplain Conversion}.class</code></li>
-     *   <li><code>{@linkplain Projection}.class</code></li>
-     * </ul>
-     *
-     * This {@code specialize(…)} method returns a conversion which implement 
at least the given {@code baseType}
-     * interface, but may also implement a more specific interface if {@code 
specialize(…)} has been able to infer
-     * the type from the {@linkplain #getMethod() operation method}.
-     * The list of interfaces supported by this method may change in any 
version of Apache SIS.
-     *
-     * @param  <T>        compile-time type of the {@code baseType} argument.
-     * @param  baseType   the base GeoAPI interface to be implemented by the 
conversion to return.
      * @param  sourceCRS  the source CRS.
      * @param  targetCRS  the target CRS.
-     * @param  factory    the factory to use for creating a transform from the 
parameters or for performing axis changes,
-     *                    or {@code null} for the default factory.
-     * @return conversion of the given type which declares the given 
<abbr>CRS</abbr>s as the source and target.
-     * @throws ClassCastException if a contradiction is found between the 
given {@code baseType},
-     *         the defining {@linkplain DefaultConversion#getInterface() 
conversion type} and
-     *         the {@linkplain DefaultOperationMethod#getOperationType() 
method operation type}.
+     * @param  factory    the factory to use for creating a transform from the 
parameters
+     *         or for performing axis changes, or {@code null} for the default 
factory.
+     * @return conversion which declares the given <abbr>CRS</abbr>s as the 
source and target.
      * @throws MismatchedDatumException if the given CRS do not use the same 
datum as the source and target CRS
      *         of this conversion.
      * @throws FactoryException if the creation of a {@link MathTransform} 
from the {@linkplain #getParameterValues()
@@ -385,16 +359,17 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
      *         failed.
      *
      * @see 
DefaultMathTransformFactory#createParameterizedTransform(ParameterValueGroup, 
DefaultMathTransformFactory.Context)
+     *
+     * @since 1.5
      */
-    public <T extends Conversion> T specialize(final Class<T> baseType,
-            final CoordinateReferenceSystem sourceCRS, final 
CoordinateReferenceSystem targetCRS,
-            MathTransformFactory factory) throws FactoryException
+    public Conversion specialize(final CoordinateReferenceSystem sourceCRS,
+                                 final CoordinateReferenceSystem targetCRS,
+                                 MathTransformFactory factory) throws 
FactoryException
     {
-        ArgumentChecks.ensureNonNull("baseType",  baseType);
         ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
         ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
         /*
-         * Conceptual consistency check: verify that the new CRS use the same 
datum as the previous ones,
+         * Conceptual consistency check: verify that the new CRSs use the same 
datum as the previous ones,
          * since the purpose of this method is not to apply datum changes. 
Datum changes are the purpose of
          * a dedicated kind of operations, namely Transformation.
          */
@@ -411,14 +386,18 @@ public class DefaultConversion extends 
AbstractSingleOperation implements Conver
              * datum for source and target CRS, since DerivedCRS and 
ProjectedCRS are expected to have the same
              * datum than their source CRS.
              */
-            if (super.getTargetCRS() != null) {
-                ensureCompatibleDatum("targetCRS", sourceCRS, 
super.getTargetCRS());
-            }
+            ensureCompatibleDatum("targetCRS", sourceCRS, 
super.getTargetCRS());
+        }
+        if (super.getSourceCRS() == sourceCRS &&
+            super.getTargetCRS() == targetCRS &&
+            super.getMathTransform() != null)
+        {
+            return this;
         }
         if (factory == null) {
             factory = DefaultMathTransformFactory.provider();
         }
-        return SubTypes.create(baseType, this, sourceCRS, targetCRS, factory);
+        return new DefaultConversion(this, sourceCRS, targetCRS, factory);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
index bbf45d2eef..65fbd9cc84 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultCoordinateOperationFactory.java
@@ -28,8 +28,6 @@ import org.opengis.referencing.AuthorityFactory;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.operation.*;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.crs.GeodeticCRS;
-import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.referencing.crs.SingleCRS;
 import org.opengis.referencing.crs.CRSFactory;
 import org.opengis.referencing.cs.CSFactory;
@@ -553,22 +551,12 @@ next:   for (int i=components.size(); --i >= 0;) {
          *
          *   - If the two CRS uses the same datum (ignoring metadata), assume 
that we have a Conversion.
          *   - Otherwise we have a datum change, which implies that we have a 
Transformation.
-         *
-         * In the case of Conversion, we can specialize one step more if the 
conversion is going from a geographic CRS
-         * to a projected CRS. It may seems that we should check if 
ProjectedCRS.getBaseCRS() is equal (ignoring meta
-         * data) to source CRS. But we already checked the datum, which is the 
important part. The axis order and unit
-         * could be different, which we want to allow.
          */
         if (baseType == SingleOperation.class) {
             if (isConversion(sourceCRS, targetCRS)) {
-                if (interpolationCRS == null && sourceCRS instanceof 
GeodeticCRS
-                                             && targetCRS instanceof 
ProjectedCRS)
-                {
-                    baseType = Projection.class;
-                } else {
-                    baseType = Conversion.class;
-                }
+                baseType = Conversion.class;
             } else {
+                // TODO: handle point motion operation.
                 baseType = Transformation.class;
             }
         }
@@ -585,14 +573,6 @@ next:   for (int i=components.size(); --i >= 0;) {
         final AbstractSingleOperation op;
         if (Transformation.class.isAssignableFrom(baseType)) {
             op = new DefaultTransformation(properties, sourceCRS, targetCRS, 
interpolationCRS, method, transform);
-        } else if (Projection.class.isAssignableFrom(baseType)) {
-            ArgumentChecks.ensureCanCast("sourceCRS", GeodeticCRS .class, 
sourceCRS);
-            ArgumentChecks.ensureCanCast("targetCRS", ProjectedCRS.class, 
targetCRS);
-            if (interpolationCRS != null) {
-                throw new IllegalArgumentException(Errors.format(
-                        Errors.Keys.ForbiddenAttribute_2, "interpolationCRS", 
baseType));
-            }
-            op = new DefaultProjection(properties, (GeodeticCRS) sourceCRS, 
(ProjectedCRS) targetCRS, method, transform);
         } else if (Conversion.class.isAssignableFrom(baseType)) {
             op = new DefaultConversion(properties, sourceCRS, targetCRS, 
interpolationCRS, method, transform);
         } else {  // See above comment about this last-resort fallback.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultOperationMethod.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultOperationMethod.java
index 60ace525eb..21375f03fb 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultOperationMethod.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultOperationMethod.java
@@ -29,7 +29,6 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.operation.Formula;
 import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.SingleOperation;
@@ -334,16 +333,15 @@ public class DefaultOperationMethod extends 
AbstractIdentifiedObject implements
      * The base {@code CoordinateOperation} interface is usually one of the 
following subtypes:
      *
      * <ul class="verbose">
+     *   <li class="verbose">{@link 
org.opengis.referencing.operation.Conversion}
+     *     if the coordinate operation is theoretically of infinite precision, 
ignoring the limitations of floating
+     *     point arithmetic (including rounding errors) and the approximations 
implied by finite series expansions.</li>
      *   <li>{@link org.opengis.referencing.operation.Transformation}
      *     if the coordinate operation has some errors (typically of a few 
metres) because of the empirical process by
      *     which the operation parameters were determined. Those errors do not 
depend on the floating point precision
      *     or the accuracy of the implementation algorithm.</li>
-     *   <li class="verbose">{@link 
org.opengis.referencing.operation.Conversion}
-     *     if the coordinate operation is theoretically of infinite precision, 
ignoring the limitations of floating
-     *     point arithmetic (including rounding errors) and the approximations 
implied by finite series expansions.</li>
-     *   <li>{@link org.opengis.referencing.operation.Projection}
-     *     if the coordinate operation is a conversion (as defined above) 
converting geodetic latitudes and longitudes
-     *     to plane (map) coordinates.</li>
+     *   <li>{@link org.opengis.referencing.operation.PointMotionOperation}
+     *     if the coordinate operation applies changes due to the motion of 
points between two coordinate epochs.</li>
      * </ul>
      *
      * In case of doubt, {@code getOperationType()} can conservatively return 
the base type.
@@ -523,8 +521,8 @@ public class DefaultOperationMethod extends 
AbstractIdentifiedObject implements
         if (isWKT1) {
             /*
              * The WKT 1 keyword is "PROJECTION", which imply that the 
operation method should be of type
-             * org.opengis.referencing.operation.Projection. So strictly 
speaking only the first check in
-             * the following 'if' statement is relevant.
+             * org.opengis.referencing.operation.Conversion. So strictly 
speaking only the first check in
+             * the following 'if' statement is relevant, and we should also 
check CRS types.
              *
              * Unfortunately in many cases we do not know the operation type, 
because the method that we
              * invoked - getOperationType() - is not a standard OGC/ISO 
property, so this information is
@@ -535,10 +533,10 @@ public class DefaultOperationMethod extends 
AbstractIdentifiedObject implements
              *
              * In other words, the combination of those two checks exclude the 
following operation types:
              * Transformation, ConcatenatedOperation, PassThroughOperation, or 
any user-defined type that
-             * do not extend Projection. All other operation types are 
accepted.
+             * do not extend Conversion. All other operation types are 
accepted.
              */
             final Class<? extends SingleOperation> type = getOperationType();
-            if (Projection.class.isAssignableFrom(type) || 
type.isAssignableFrom(Projection.class)) {
+            if (Conversion.class.isAssignableFrom(type) || 
type.isAssignableFrom(Conversion.class)) {
                 return WKTKeywords.Projection;
             }
             formatter.setInvalidWKT(this, null);
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
index a444daff6a..762e3283c4 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
@@ -370,6 +370,7 @@ public class DefaultPassThroughOperation extends 
AbstractCoordinateOperation imp
          * State validation. The `missing` string will be used in exception 
message
          * at the end of this method if a required component is reported 
missing.
          */
+        @SuppressWarnings("LocalVariableHidesMemberVariable")
         final int[] modifiedCoordinates = this.modifiedCoordinates;
         FactoryException cause = null;
         String missing = "modifiedCoordinate";
@@ -393,7 +394,7 @@ public class DefaultPassThroughOperation extends 
AbstractCoordinateOperation imp
                                 if (sourceSub == null) sourceSub = 
CRS.selectDimensions(sourceCRS, modifiedCoordinates);
                                 if (targetSub == null) targetSub = 
CRS.selectDimensions(targetCRS, modifiedCoordinates);
                                 operation = 
DefaultConversion.castOrCopy((Conversion) operation)
-                                            .specialize(Conversion.class, 
sourceSub, targetSub, null);
+                                            .specialize(sourceSub, targetSub, 
null);
                                 subTransform = operation.getMathTransform();
                             } catch (FactoryException e) {
                                 cause = e;
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultProjection.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultProjection.java
deleted file mode 100644
index 123b12a327..0000000000
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/DefaultProjection.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * 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.operation;
-
-import java.util.Map;
-import jakarta.xml.bind.annotation.XmlTransient;
-import org.opengis.util.FactoryException;
-import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.Projection;
-import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.MathTransformFactory;
-import org.opengis.referencing.crs.GeodeticCRS;
-import org.opengis.referencing.crs.ProjectedCRS;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.util.ArgumentChecks;
-
-
-/**
- * A conversion from (<var>longitude</var>, <var>latitude</var>) coordinates 
to Cartesian coordinates
- * (<var>x</var>,<var>y</var>).
- *
- * <p>An unofficial list of projections and their parameters can be found
- * <a href="http://geotiff.maptools.org/proj_list/";>there</a>.
- * Most projections expect the following parameters:</p>
- *
- * <ul>
- *   <li>{@code "central_meridian"} (default to 0),
- *   <li>{@code "latitude_of_origin"} (default to 0),
- *   <li>{@code "scale_factor"} (default to 1),
- *   <li>{@code "false_easting"} (default to 0) and
- *   <li>{@code "false_northing"} (default to 0).
- * </ul>
- *
- * @author  Martin Desruisseaux (IRD, Geomatys)
- *
- * @see org.apache.sis.referencing.crs.DefaultProjectedCRS
- */
-@XmlTransient
-final class DefaultProjection extends DefaultConversion implements Projection {
-    /**
-     * Serial number for inter-operability with different versions.
-     */
-    private static final long serialVersionUID = -7176751851369816864L;
-
-    /**
-     * Creates a projection from the given properties.
-     *
-     * @param  properties  the properties to be given to the identified object.
-     * @param  sourceCRS   the source CRS.
-     * @param  targetCRS   the target CRS.
-     * @param  method      the coordinate operation method.
-     * @param  transform   transform from positions in the source CRS to 
positions in the target CRS.
-     */
-    public DefaultProjection(final Map<String,?>   properties,
-                             final GeodeticCRS     sourceCRS,
-                             final ProjectedCRS    targetCRS,
-                             final OperationMethod method,
-                             final MathTransform   transform)
-    {
-        super(properties, sourceCRS, targetCRS, null, method, transform);
-    }
-
-    /**
-     * Creates a new projection with the same values as the specified one, 
together with the
-     * specified source and target CRS. While the source conversion can be an 
arbitrary one,
-     * it is typically a defining conversion.
-     *
-     * @param  definition  the defining conversion.
-     * @param  sourceCRS   the source CRS.
-     * @param  targetCRS   the target CRS.
-     * @param  factory     the factory to use for creating a transform from 
the parameters or for performing axis changes.
-     * @param  actual      an array of length 1 where to store the actual 
operation method used by the math transform factory.
-     * @throws IllegalArgumentException if the source or targe CRS is not of 
the requested type.
-     */
-    DefaultProjection(final Conversion definition,
-                      final CoordinateReferenceSystem sourceCRS,
-                      final CoordinateReferenceSystem targetCRS,
-                      final MathTransformFactory factory,
-                      final OperationMethod[] actual) throws FactoryException
-    {
-        super(definition, sourceCRS, targetCRS, factory, actual);
-        ArgumentChecks.ensureCanCast("sourceCRS", GeodeticCRS.class,  
sourceCRS);
-        ArgumentChecks.ensureCanCast("targetCRS", ProjectedCRS.class, 
targetCRS);
-    }
-
-    /**
-     * Creates a new coordinate operation with the same values as the 
specified one.
-     * This copy constructor provides a way to convert an arbitrary 
implementation
-     * into a SIS one, usually in order to leverage some 
implementation-specific API.
-     *
-     * <p>This constructor performs a shallow copy, i.e. the properties are 
not cloned.</p>
-     *
-     * @param  operation  the coordinate operation to copy.
-     */
-    protected DefaultProjection(final Projection operation) {
-        super(operation);
-    }
-
-    /**
-     * Returns the GeoAPI interface implemented by this class.
-     *
-     * @return the conversion interface implemented by this class.
-     */
-    @Override
-    public Class<? extends Projection> getInterface() {
-        return Projection.class;
-    }
-
-    /**
-     * Returns the source CRS, which must be geographic or {@code null}.
-     */
-    @Override
-    public final GeodeticCRS getSourceCRS() {
-        return (GeodeticCRS) super.getSourceCRS();
-    }
-
-    /**
-     * Returns the target CRS, which must be projected or {@code null}.
-     */
-    @Override
-    public final ProjectedCRS getTargetCRS() {
-        return (ProjectedCRS) super.getTargetCRS();
-    }
-}
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/SubTypes.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/SubTypes.java
index c17d8883d6..d7e8ce8b8b 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/SubTypes.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/SubTypes.java
@@ -16,10 +16,7 @@
  */
 package org.apache.sis.referencing.operation;
 
-import org.opengis.util.FactoryException;
 import org.opengis.referencing.operation.*;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.apache.sis.referencing.AbstractIdentifiedObject;
 
 
 /**
@@ -30,8 +27,6 @@ import org.apache.sis.referencing.AbstractIdentifiedObject;
  * <p>This class currently provides implementation for the following 
methods:</p>
  * <ul>
  *   <li>{@link 
AbstractCoordinateOperation#castOrCopy(CoordinateOperation)}</li>
- *   <li>{@link DefaultConversion#castOrCopy(Conversion)}</li>
- *   <li>{@link DefaultConversion#specialize(Class, CoordinateReferenceSystem, 
CoordinateReferenceSystem, MathTransformFactory)}</li>
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
@@ -76,74 +71,4 @@ final class SubTypes {
         }
         return new AbstractCoordinateOperation(object);
     }
-
-    /**
-     * Returns a conversion from the specified defining conversion.
-     * The returned conversion will implement at least the {@code baseType} 
interface, but may implement
-     * a more specific GeoAPI interface if this method has been able to infer 
the type from the
-     * {@code conversion} argument.
-     *
-     * @param  baseType    the base GeoAPI interface to be implemented by the 
conversion to return.
-     * @param  definition  the defining conversion.
-     * @param  sourceCRS   the source CRS.
-     * @param  targetCRS   the target CRS.
-     * @param  factory     the factory to use for creating a transform from 
the parameters or for performing axis changes.
-     * @return the conversion of the given type between the given CRS.
-     * @throws ClassCastException if a contradiction is found between the 
given {@code baseType},
-     *         the defining {@linkplain DefaultConversion#getInterface() 
conversion type} and
-     *         the {@linkplain DefaultOperationMethod#getOperationType() 
method operation type}.
-     */
-    static <T extends Conversion> T create(final Class<T> baseType, Conversion 
definition,
-            final CoordinateReferenceSystem sourceCRS, final 
CoordinateReferenceSystem targetCRS,
-            final MathTransformFactory factory) throws FactoryException
-    {
-        Class<? extends T> type = baseType;
-        if (definition instanceof AbstractIdentifiedObject) {
-            final Class<?> c = ((AbstractIdentifiedObject) 
definition).getInterface();
-            if (!c.isAssignableFrom(baseType)) {                        // Do 
nothing if c is a parent type.
-                type = c.asSubclass(type);
-            }
-        }
-        final OperationMethod method = definition.getMethod();
-        if (method instanceof DefaultOperationMethod) {
-            final Class<? extends SingleOperation> c = 
((DefaultOperationMethod) method).getOperationType();
-            if (!c.isAssignableFrom(baseType)) {                        // Do 
nothing if c is a parent type.
-                type = c.asSubclass(type);
-            }
-        }
-        Conversion conversion;
-        if (type.isInstance(definition)
-                && definition.getSourceCRS() == sourceCRS
-                && definition.getTargetCRS() == targetCRS
-                && definition.getMathTransform() != null)
-        {
-            conversion = definition;
-        } else {
-            final OperationMethod[] actual = new OperationMethod[1];
-            boolean tryAgain;
-            do {
-                tryAgain = false;
-                if (Projection.class.isAssignableFrom(type)) {
-                    conversion = new DefaultProjection(definition, sourceCRS, 
targetCRS, factory, actual);
-                } else {
-                    conversion = new DefaultConversion(definition, sourceCRS, 
targetCRS, factory, actual);
-                }
-                /*
-                 * The DefaultConversion constructor may have used 
MathTransformFactory for creating the actual
-                 * MathTransform object. In such case, we can use the 
knownledge that the factory has about the
-                 * coordinate operation for refining again the type of the 
object to be returned.
-                 */
-                final OperationMethod m = actual[0];
-                if (m instanceof DefaultOperationMethod) {
-                    final Class<?> t = ((DefaultOperationMethod) 
m).getOperationType();
-                    if (t != null && t != type && type.isAssignableFrom(t)) {
-                        type = t.asSubclass(type);
-                        definition = conversion;
-                        tryAgain = true;
-                    }
-                }
-            } while (tryAgain);
-        }
-        return type.cast(conversion);
-    }
 }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
index f7f6f19e72..761257b360 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/AbstractProvider.java
@@ -60,9 +60,9 @@ public abstract class AbstractProvider extends 
DefaultOperationMethod implements
     /**
      * The base interface of the {@code CoordinateOperation} instances that 
use this method.
      * Value can be {@link org.opengis.referencing.operation.SingleOperation},
-     * {@link org.opengis.referencing.operation.Transformation},
-     * {@link org.opengis.referencing.operation.Conversion} or
-     * {@link org.opengis.referencing.operation.Projection}.
+     * {@link org.opengis.referencing.operation.Conversion},
+     * {@link org.opengis.referencing.operation.Transformation} or
+     * {@link org.opengis.referencing.operation.PointMotionOperation}.
      *
      * @see #getOperationType()
      */
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java
index 46ed35bf62..e0b023c68f 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/Equirectangular.java
@@ -25,7 +25,7 @@ import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.EllipsoidalCS;
-import org.opengis.referencing.operation.Projection;
+import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.apache.sis.parameter.Parameters;
 import org.apache.sis.parameter.ParameterBuilder;
@@ -270,7 +270,7 @@ public final class Equirectangular extends AbstractProvider 
{
      * @see MapProjection#MapProjection(Class, ParameterDescriptorGroup)
      */
     public Equirectangular() {
-        super(Projection.class, PARAMETERS,
+        super(Conversion.class, PARAMETERS,
               EllipsoidalCS.class, true,
               CartesianCS.class,  false,
               (byte) 2);
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/MapProjection.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/MapProjection.java
index 09ef70ddd3..114fe3e8a4 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/MapProjection.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/MapProjection.java
@@ -33,7 +33,7 @@ import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.cs.CartesianCS;
 import org.opengis.referencing.cs.EllipsoidalCS;
 import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.Projection;
+import org.opengis.referencing.operation.Conversion;
 import static org.opengis.metadata.Identifier.AUTHORITY_KEY;
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.referencing.IdentifiedObjects;
@@ -173,7 +173,7 @@ public abstract class MapProjection extends 
AbstractProvider {
      * @param  parameters  the set of parameters (never {@code null}).
      */
     protected MapProjection(final ParameterDescriptorGroup parameters) {
-        super(Projection.class, parameters,
+        super(Conversion.class, parameters,
               EllipsoidalCS.class, true,
               CartesianCS.class, false,
               (byte) 2);
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/PseudoPlateCarree.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/PseudoPlateCarree.java
index 5047e8c6d8..c53bf30ebb 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/PseudoPlateCarree.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/PseudoPlateCarree.java
@@ -30,9 +30,6 @@ import org.apache.sis.metadata.iso.citation.Citations;
  * The semi-major and semi-minor axis lengths are ignored (they could be fixed 
to 1) but nevertheless declared
  * for allowing netCDF file encoding to declare the ellipsoid in 
pseudo-projection parameters.
  *
- * <p>We do not declare that operation method as a {@link 
org.opengis.referencing.operation.Projection} because
- * axis units are degrees.</p>
- *
  * @author  Martin Desruisseaux (Geomatys)
  *
  * @see Equirectangular
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/ZonedTransverseMercator.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/ZonedTransverseMercator.java
index 52d12e96d2..0c63480b63 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/ZonedTransverseMercator.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/provider/ZonedTransverseMercator.java
@@ -22,7 +22,7 @@ import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.cs.EllipsoidalCS;
-import org.opengis.referencing.operation.Projection;
+import org.opengis.referencing.operation.Conversion;
 import org.opengis.referencing.operation.MathTransform;
 import org.apache.sis.measure.Units;
 import org.apache.sis.measure.Longitude;
@@ -104,7 +104,7 @@ public final class ZonedTransverseMercator extends 
AbstractProvider {
      * because of the discontinuities between zones.
      */
     public ZonedTransverseMercator() {
-        super(Projection.class, PARAMETERS,
+        super(Conversion.class, PARAMETERS,
               EllipsoidalCS.class, true,
               EllipsoidalCS.class, false,
               (byte) 2);
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
index 83750adbdd..25949cec40 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
@@ -394,12 +394,12 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
      * {@code OperationMethod}s. The argument is usually (but not restricted 
to) one of the following types:
      *
      * <ul>
+     *   <li>{@link org.opengis.referencing.operation.Conversion}
+     *       for coordinate operations described by definitions (including map 
projections).</li>
      *   <li>{@link org.opengis.referencing.operation.Transformation}
      *       for coordinate operations described by empirically derived 
parameters.</li>
-     *   <li>{@link org.opengis.referencing.operation.Conversion}
-     *       for coordinate operations described by definitions.</li>
-     *   <li>{@link org.opengis.referencing.operation.Projection}
-     *       for conversions from geodetic latitudes and longitudes to plane 
(map) coordinates.</li>
+     *   <li>{@link org.opengis.referencing.operation.PointMotionOperation}
+     *       for changes due to the motion of the point between two coordinate 
epochs.</li>
      *   <li>{@link SingleOperation} for all coordinate operations.</li>
      * </ul>
      *
@@ -407,8 +407,8 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
      * if this {@code MathTransformFactory} does not support filtering by the 
given type.
      *
      * @param  type  <code>{@linkplain SingleOperation}.class</code> for 
fetching all operation methods,
-     *               <code>{@linkplain 
org.opengis.referencing.operation.Projection}.class</code> for
-     *               fetching only map projection methods, <i>etc</i>.
+     *               <code>{@linkplain 
org.opengis.referencing.operation.Transformation}.class</code>
+     *               for operations defined by empirical parameters, 
<i>etc</i>.
      * @return methods available in this factory for coordinate operations of 
the given type.
      *
      * @see #getDefaultParameters(String)
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 a71ea42375..cff1f41696 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
@@ -43,7 +43,6 @@ import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.util.FactoryException;
 import org.apache.sis.system.Loggers;
 import org.apache.sis.referencing.CRS;
@@ -651,34 +650,26 @@ public final class EPSGFactoryTest extends 
TestCaseWithLogs {
         final Set<String> parameters      = 
factory.getAuthorityCodes(ParameterDescriptor.class);
         final Set<String> operations      = 
factory.getAuthorityCodes(SingleOperation    .class);
         final Set<String> conversions     = 
factory.getAuthorityCodes(Conversion         .class);
-        final Set<String> projections     = 
factory.getAuthorityCodes(Projection         .class);
         final Set<String> transformations = 
factory.getAuthorityCodes(Transformation     .class);
 
         assertFalse(methods        .isEmpty(), "Methods not found.");
         assertFalse(parameters     .isEmpty(), "Parameters not found.");
         assertFalse(operations     .isEmpty(), "Operations not found.");
         assertFalse(conversions    .isEmpty(), "Conversions not found.");
-        assertFalse(projections    .isEmpty(), "Projections not found.");
         assertFalse(transformations.isEmpty(), "Transformations not found.");
 
         assertTrue (methods        .contains("9804"),  "Shall contain 
“Mercator 1SP”");
         assertTrue (parameters     .contains("8805"),  "Shall contain “Scale 
factor”");
         assertTrue (operations     .contains("1133"),  "Shall contain “ED50 to 
WGS 84 (1)”");
         assertFalse(conversions    .contains("1133"),  "Shall not contain 
“ED50 to WGS 84 (1)”");
-        assertFalse(projections    .contains("1133"),  "Shall not contain 
“ED50 to WGS 84 (1)”");
         assertTrue (transformations.contains("1133"),  "Shall contain “ED50 to 
WGS 84 (1)”");
         assertTrue (operations     .contains("16001"), "Shall contain “UTM 
zone 1N”");
         assertTrue (conversions    .contains("16001"), "Shall contain “UTM 
zone 1N”");
-        assertTrue (projections    .contains("16001"), "Shall contain “UTM 
zone 1N”");
         assertFalse(transformations.contains("16001"), "Shall not contain “UTM 
zone 1N”");
 
         if (RUN_EXTENSIVE_TESTS) {
             assertTrue (conversions    .size() < operations .size(), 
"Conversions shall be a subset of operations.");
-            assertTrue (projections    .size() < operations .size(), 
"Projections shall be a subset of operations.");
-            assertTrue (projections    .size() < conversions.size(), 
"Projections shall be a subset of conversions.");
             assertTrue (transformations.size() < operations .size(), 
"Transformations shall be a subset of operations.");
-            assertFalse(projections.containsAll(conversions),        
"Projections shall be a subset of conversions.");
-            assertTrue (conversions.containsAll(projections),        
"Projections shall be a subset of conversions.");
             assertTrue (operations .containsAll(conversions),        
"Conversion shall be a subset of operations.");
             assertTrue (operations .containsAll(transformations),    
"Transformations shall be a subset of operations.");
             assertTrue (Collections.disjoint(conversions, transformations), 
"Conversions cannot be transformations.");
@@ -752,7 +743,7 @@ public final class EPSGFactoryTest extends TestCaseWithLogs 
{
         assertNotSame(projection, operation,
                 "The defining conversion and the actual conversion should 
differ " +
                 "because the actual conversion should have semi-axis length 
values.");
-        assertInstanceOf(Projection.class, projection);
+        assertInstanceOf(Conversion.class, projection);
         assertNotNull(projection.getSourceCRS());
         assertNotNull(projection.getTargetCRS());
         assertNotNull(projection.getMathTransform());
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
index 45672693bb..dd933a7b54 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/CoordinateOperationFinderTest.java
@@ -33,7 +33,6 @@ import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.referencing.operation.Transformation;
 import org.opengis.referencing.operation.TransformException;
 import org.opengis.referencing.operation.ConcatenatedOperation;
@@ -454,7 +453,7 @@ public final class CoordinateOperationFinderTest extends 
MathTransformTestCase {
         assertSame(sourceCRS, operation.getSourceCRS());
         assertSame(targetCRS, operation.getTargetCRS());
         assertEquals("TM", operation.getName().getCode());
-        assertInstanceOf(Projection.class, operation);
+        assertInstanceOf(Conversion.class, operation);
 
         final ParameterValueGroup param = ((SingleOperation) 
operation).getParameterValues();
         assertEquals(6370997, param.parameter("semi_major"        
).doubleValue());
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java
index 6c3e80b065..2f693ca840 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/DefaultConversionTest.java
@@ -239,13 +239,12 @@ public final class DefaultConversionTest extends TestCase 
{
          * Now create a normal conversion from the defining one,
          * but add a swapping of (latitude, longitude) axes.
          */
-        final DefaultConversion completed = definingConversion.specialize(
-                DefaultConversion.class,    // In normal use, this would be 
'Conversion.class'.
+        final Conversion completed = definingConversion.specialize(
                 changeCS(reference.getSourceCRS(), HardCodedCS.GEODETIC_φλ),
                 reference.getTargetCRS(),
                 null);
 
-        verifyProperties(completed, true);
+        verifyProperties(assertInstanceOf(DefaultConversion.class, completed), 
true);
     }
 
     /**
@@ -270,17 +269,16 @@ public final class DefaultConversionTest extends TestCase 
{
          * When asking for a "specialization" with the same properties,
          * we should get the existing instance since no change is needed.
          */
-        assertSame(op, op.specialize(Conversion.class, op.getSourceCRS(), 
op.getTargetCRS(), null));
+        assertSame(op, op.specialize(op.getSourceCRS(), op.getTargetCRS(), 
null));
         /*
          * Reducing the number of dimensions to 2 and swapping (latitude, 
longitude) axes.
          */
-        op = op.specialize(DefaultConversion.class, op.getSourceCRS(),
-                changeCS(op.getTargetCRS(), HardCodedCS.GEODETIC_φλ), null);
+        Conversion c = op.specialize(op.getSourceCRS(), 
changeCS(op.getTargetCRS(), HardCodedCS.GEODETIC_φλ), null);
         assertMatrixEquals(Matrices.create(3, 4, new double[] {
                     0, 1, 0, 0,
                     1, 0, 0, OFFSET,
                     0, 0, 0, 1
-                }), MathTransforms.getMatrix(op.getMathTransform()), STRICT,
+                }), MathTransforms.getMatrix(c.getMathTransform()), STRICT,
                 "Longitude rotation of a two-dimensional CRS");
     }
 
@@ -310,8 +308,7 @@ public final class DefaultConversionTest extends TestCase {
                 MathTransforms.getMatrix(op.getMathTransform()), STRICT,
                 "Longitude rotation of a time-varying CRS");
 
-        op = op.specialize(
-                DefaultConversion.class,    // In normal use, this would be 
'Conversion.class'.
+        Conversion c = op.specialize(
                 op.getSourceCRS(),          // Keep the same source CRS.
                 changeCS(op.getTargetCRS(), HardCodedCS.GEODETIC_φλ),   // 
Swap axis order.
                 null);
@@ -320,7 +317,7 @@ public final class DefaultConversionTest extends TestCase {
                                        0, 0, 1, 0,
                                        0, 1, 0, OFFSET,
                                        0, 0, 0, 1),
-                MathTransforms.getMatrix(op.getMathTransform()), STRICT,
+                MathTransforms.getMatrix(c.getMathTransform()), STRICT,
                 "Longitude rotation of a time-varying CRS");
     }
 
@@ -334,12 +331,12 @@ public final class DefaultConversionTest extends TestCase 
{
         final DefaultConversion op = createLongitudeRotation(true);
         IllegalArgumentException e;
         e = assertThrows(IllegalArgumentException.class,
-                () -> op.specialize(Conversion.class, HardCodedCRS.WGS84, 
HardCodedCRS.NTF_NORMALIZED_AXES, null),
+                () -> op.specialize(HardCodedCRS.WGS84, 
HardCodedCRS.NTF_NORMALIZED_AXES, null),
                 "Should not have accepted to change the geodetic datum.");
         assertMessageContains(e, "sourceCRS", "Nouvelle Triangulation 
Française");
 
         e = assertThrows(IllegalArgumentException.class,
-                () -> op.specialize(Conversion.class, 
HardCodedCRS.NTF_NORMALIZED_AXES, HardCodedCRS.WGS84, null),
+                () -> op.specialize(HardCodedCRS.NTF_NORMALIZED_AXES, 
HardCodedCRS.WGS84, null),
                 "Should not have accepted to change the geodetic datum.");
         assertMessageContains(e, "targetCRS", "Nouvelle Triangulation 
Française");
     }
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java
index 37aaf8704a..fea87bd442 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/provider/ProvidersTest.java
@@ -22,7 +22,6 @@ import java.util.IdentityHashMap;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
 import org.opengis.referencing.cs.VerticalCS;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 
@@ -207,7 +206,7 @@ public final class ProvidersTest extends TestCase {
             final int expected;
             if (method.sourceCSType == VerticalCS.class) {
                 expected = 1;
-            } else if 
(Projection.class.isAssignableFrom(method.getOperationType())) {
+            } else if (method instanceof MapProjection) {
                 expected = 2;
             } else if (name.endsWith("1D")) {
                 expected = 1;
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
index 622899fa08..5a29446915 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactoryTest.java
@@ -24,20 +24,20 @@ import java.util.ServiceLoader;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.referencing.operation.Conversion;
-import org.opengis.referencing.operation.Projection;
 import org.opengis.referencing.operation.SingleOperation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.parameter.ParameterValueGroup;
 import org.apache.sis.parameter.Parameterized;
+import org.apache.sis.referencing.crs.DefaultProjectedCRS;
 import org.apache.sis.referencing.operation.DefaultConversion;
 import org.apache.sis.referencing.operation.matrix.Matrix2;
 import org.apache.sis.referencing.operation.matrix.Matrices;
-import org.apache.sis.referencing.crs.DefaultProjectedCRS;
-import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.referencing.operation.provider.Affine;
 import org.apache.sis.referencing.operation.provider.Mercator1SP;
+import org.apache.sis.referencing.operation.provider.MapProjection;
+import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.util.privy.Constants;
 import org.apache.sis.measure.Units;
 
@@ -149,19 +149,16 @@ public final class DefaultMathTransformFactoryTest 
extends TestCase {
         final DefaultMathTransformFactory factory = factory();
         final Set<OperationMethod> transforms  = 
factory.getAvailableMethods(SingleOperation.class);
         final Set<OperationMethod> conversions = 
factory.getAvailableMethods(Conversion.class);
-        final Set<OperationMethod> projections = 
factory.getAvailableMethods(Projection.class);
         /*
          * Following tests should not cause loading of more classes than 
needed.
          */
         assertFalse(transforms .isEmpty());
         assertFalse(conversions.isEmpty());
-        assertFalse(projections.isEmpty());
         assertTrue 
(transforms.contains(factory.getOperationMethod(Constants.AFFINE)));
         /*
          * Following tests will force instantiation of all remaining 
OperationMethod.
          */
-        assertTrue(transforms .containsAll(conversions), "Conversions should 
be a subset of transforms.");
-        assertTrue(conversions.containsAll(projections), "Projections should 
be a subset of conversions.");
+        assertTrue(transforms.containsAll(conversions), "Conversions should be 
a subset of transforms.");
     }
 
     /**
@@ -213,8 +210,12 @@ public final class DefaultMathTransformFactoryTest extends 
TestCase {
          */
         final MathTransformFactory factory = factory();
         final Map<String,?> dummyName = Map.of(DefaultProjectedCRS.NAME_KEY, 
"Test");
-        final Collection<OperationMethod> methods = 
factory.getAvailableMethods(Projection.class);
+        final Collection<OperationMethod> methods = 
factory.getAvailableMethods(Conversion.class);
+        int count = 0;
         for (final OperationMethod method : methods) {
+            if (!(method instanceof MapProjection)) {
+                continue;
+            }
             final String classification = method.getName().getCode();
             ParameterValueGroup pg = 
factory.getDefaultParameters(classification);
             pg.parameter("semi_major").setValue(6377563.396);
@@ -295,7 +296,9 @@ public final class DefaultMathTransformFactoryTest extends 
TestCase {
             final Conversion projection = crs.getConversionFromBase();
             assertSame(mt, projection.getMathTransform(), classification);
             assertEquals(projection.getMethod().getName().getCode(), 
classification);
+            count++;
         }
+        assertTrue(count >= 15, "Map projection methods not found.");
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/report/CoordinateOperationMethods.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/report/CoordinateOperationMethods.java
index d649065fe5..74817c606a 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/report/CoordinateOperationMethods.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/report/CoordinateOperationMethods.java
@@ -100,7 +100,7 @@ public class CoordinateOperationMethods extends 
HTMLGenerator {
     /**
      * Values returned by {@link #category(OperationMethod)}.
      */
-    private static final int PROJECTION = 1, CONVERSION = 2, TRANSFORMATION = 
3;
+    private static final int CONVERSION = 1, TRANSFORMATION = 3;
 
     /**
      * Parameters to default to the latitude of origin. We can hardly detect 
those cases
@@ -192,7 +192,6 @@ public class CoordinateOperationMethods extends 
HTMLGenerator {
                 closeTags(innerUL);
                 reopenTag("li");
                 switch (nc) {
-                    case PROJECTION:     println("Projections");    break;
                     case CONVERSION:     println("Conversions");    break;
                     case TRANSFORMATION: println("Tranformations"); break;
                     default: throw new AssertionError(category);
@@ -522,7 +521,6 @@ public class CoordinateOperationMethods extends 
HTMLGenerator {
      */
     private static int category(final OperationMethod method) {
         final Class<?> c = getOperationType((DefaultOperationMethod) method);
-        if (Projection    .class.isAssignableFrom(c)) return PROJECTION;
         if (Conversion    .class.isAssignableFrom(c)) return CONVERSION;
         if (Transformation.class.isAssignableFrom(c)) return TRANSFORMATION;
         return 0;
diff --git a/geoapi/snapshot b/geoapi/snapshot
index b822d026bd..1dd682e1b3 160000
--- a/geoapi/snapshot
+++ b/geoapi/snapshot
@@ -1 +1 @@
-Subproject commit b822d026bd9e4692a159a9bd2bc158716da2e721
+Subproject commit 1dd682e1b3950d7024b17f6639673b896f701441

Reply via email to