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

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

commit 973019be6b42517022f10b037d3b8f51a1fe3925
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Sat Jul 6 15:58:19 2024 +0200

    Reduce usage of deprecated methods, and consolidation.
---
 .../org/apache/sis/io/wkt/MathTransformParser.java |  11 +-
 .../sis/referencing/MultiRegisterOperations.java   |   2 +-
 .../referencing/factory/IdentifiedObjectSet.java   |   5 +-
 .../internal/ParameterizedTransformBuilder.java    |  45 +++------
 .../sis/referencing/operation/package-info.java    |  14 ---
 .../operation/projection/NormalizedProjection.java |   3 +-
 .../CoordinateSystemTransformBuilder.java          |  29 +-----
 .../transform/DefaultMathTransformFactory.java     |  95 ++++--------------
 .../operation/transform/MathTransformBuilder.java  | 111 +++++++++++++++++++++
 .../projection/MapProjectionTestCase.java          |   3 +-
 .../transform/MathTransformFactoryMock.java        |  51 +++++++---
 .../apache/sis/util/privy/MetadataServices.java    |   2 +-
 geoapi/snapshot                                    |   2 +-
 13 files changed, 198 insertions(+), 175 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
index 282575dc0a..0226437ebc 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/MathTransformParser.java
@@ -415,10 +415,9 @@ class MathTransformParser extends AbstractParser {
             return null;
         }
         classification = element.pullString("classification");
-        final MathTransformFactory mtFactory = 
factories.getMathTransformFactory();
-        final ParameterValueGroup parameters;
+        final MathTransform.Builder builder;
         try {
-            parameters = mtFactory.getDefaultParameters(classification);
+            builder = 
factories.getMathTransformFactory().builder(classification);
         } catch (NoSuchIdentifierException exception) {
             throw element.parseFailed(exception);
         }
@@ -426,18 +425,18 @@ class MathTransformParser extends AbstractParser {
          * Scan over all PARAMETER["name", value] elements and
          * set the corresponding parameter in the parameter group.
          */
-        parseParameters(element, parameters, null, null);
+        parseParameters(element, builder.parameters(), null, null);
         element.close(ignoredElements);
         /*
          * We now have all information for constructing the math transform.
          */
         final MathTransform transform;
         try {
-            transform = mtFactory.createParameterizedTransform(parameters);
+            transform = builder.create();
         } catch (FactoryException exception) {
             throw element.parseFailed(exception);
         }
-        lastMethod = mtFactory.getLastMethodUsed();
+        lastMethod = builder.getMethod().orElse(null);
         return transform;
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
index 6bf7628dbd..db0cdca8e4 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/MultiRegisterOperations.java
@@ -416,7 +416,7 @@ public class MultiRegisterOperations extends 
AbstractFactory implements Register
      * @throws IllegalArgumentException if the specified type is not one of 
the above-cited values.
      */
     @Override
-    public <T extends Factory> Optional<T> getFactory(final Class<T> type) {
+    public <T extends Factory> Optional<T> getFactory(final Class<? extends T> 
type) {
         final Factory factory;
         final Boolean b = FACTORY_TYPES.get(type);
         if (b != null) {
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 5f5ac29be8..3abc6e9f4b 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
@@ -533,9 +533,8 @@ public class IdentifiedObjectSet<T extends 
IdentifiedObject> extends AbstractSet
      *   <li>If {@link NoSuchAuthorityCodeException}, returns {@code false} 
since failure to find a code declared
      *       in the collection would be an inconsistency. Note that this 
exception is a subtype of
      *       {@code NoSuchIdentifierException}, so it must be tested before 
the last case below.</li>
-     *   <li>If {@link NoSuchIdentifierException}, returns {@code true} since 
this exception is caused by an attempt to
-     *       {@linkplain 
org.opengis.referencing.operation.MathTransformFactory#createParameterizedTransform
-     *       create a parameterized transform} for an unimplemented 
operation.</li>
+     *   <li>If {@link NoSuchIdentifierException}, returns {@code true} 
because this exception is caused
+     *       by an attempt to create a parameterized transform for an 
unimplemented operation.</li>
      *   <li>If {@link MissingFactoryResourceException}, returns {@code 
true}.</li>
      *   <li>Otherwise returns {@code false}.</li>
      * </ul>
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
index bab03dcdb0..d439168dd4 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/ParameterizedTransformBuilder.java
@@ -19,7 +19,6 @@ package org.apache.sis.referencing.internal;
 import java.util.Map;
 import java.util.LinkedHashMap;
 import java.util.Collections;
-import java.util.Optional;
 import java.util.OptionalInt;
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
@@ -55,6 +54,7 @@ import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.provider.AbstractProvider;
 import org.apache.sis.referencing.operation.provider.VerticalOffset;
 import org.apache.sis.referencing.operation.transform.MathTransforms;
+import org.apache.sis.referencing.operation.transform.MathTransformBuilder;
 import org.apache.sis.referencing.operation.transform.ContextualParameters;
 import org.apache.sis.referencing.operation.transform.MathTransformProvider;
 import 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory;
@@ -87,7 +87,7 @@ import org.opengis.util.UnimplementedServiceException;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-public class ParameterizedTransformBuilder implements MathTransform.Builder, 
MathTransformProvider.Context {
+public class ParameterizedTransformBuilder extends MathTransformBuilder 
implements MathTransformProvider.Context {
     /**
      * Minimal precision of ellipsoid semi-major and semi-minor axis lengths, 
in metres.
      * If the length difference between the axis of two ellipsoids is greater 
than this threshold,
@@ -96,11 +96,6 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
      */
     private static final double ELLIPSOID_PRECISION = 
Formulas.LINEAR_TOLERANCE;
 
-    /**
-     * The factory to use for building the transform.
-     */
-    private final MathTransformFactory factory;
-
     /**
      * Coordinate system of the source or target points.
      */
@@ -111,15 +106,6 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
      */
     private Ellipsoid sourceEllipsoid, targetEllipsoid;
 
-    /**
-     * The provider that created the parameterized {@link MathTransform} 
instance, or {@code null}
-     * if this information does not apply. This is initially set to the 
operation method specified
-     * in the call to {@link #builder(String)}, but may be modified by {@link 
#create()}.
-     *
-     * @see #getMethod()
-     */
-    protected OperationMethod provider;
-
     /**
      * The parameters of the transform to create. This is initialized to 
default values.
      * The instance is returned directly by {@link #parameters()} for allowing 
users to
@@ -163,7 +149,7 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
      * @param  method   a method known to the given factory, or {@code null} 
if none.
      */
     public ParameterizedTransformBuilder(final MathTransformFactory factory, 
final OperationMethod method) {
-        this.factory = factory;
+        super(factory);
         if (method != null) {
             provider   = method;
             parameters = method.getParameters().createValue();
@@ -365,19 +351,6 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
         }
     }
 
-    /**
-     * Returns the operation method used for creating the math transform from 
the parameter values.
-     * This is initially the operation method specified in the call to {@link 
#builder(String)},
-     * but may change after the call to {@link #create()} if the method has 
been adjusted because
-     * of the parameter values.
-     *
-     * @return the operation method used for creating the math transform from 
the parameter values.
-     */
-    @Override
-    public final Optional<OperationMethod> getMethod() {
-        return Optional.ofNullable(provider);
-    }
-
     /**
      * Returns the parameter values to modify for defining the transform to 
create.
      * Those parameters are initialized to default values, which are 
{@linkplain #getMethod() method} depend.
@@ -453,7 +426,7 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
      * Returns the value of the given parameter in the given unit, or {@code 
NaN} if the parameter is not set.
      *
      * <p><b>NOTE:</b> Do not merge this function with {@code ensureSet(…)}. 
We keep those two methods
-     * separated in order to give to {@code createParameterizedTransform(…)} a 
"all or nothing" behavior.</p>
+     * separated in order to give to {@code completeParameters()} an "all or 
nothing" behavior.</p>
      */
     private static double getValue(final ParameterValue<?> parameter, final 
Unit<?> unit) {
         return (parameter.getValue() != null) ? parameter.doubleValue(unit) : 
Double.NaN;
@@ -665,6 +638,10 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
                             :  
DefaultMathTransformFactory.provider()).getOperationMethod(method);
                 }
             }
+            /*
+             * Will catch only exceptions that may be the result of improper 
parameter usage (e.g. a value out
+             * of range). Do not catch exceptions caused by programming errors 
(e.g. null pointer exception).
+             */
             final MathTransform transform;
             if (provider instanceof MathTransformProvider) try {
                 transform = ((MathTransformProvider) 
provider).createMathTransform(this);
@@ -677,7 +654,7 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
             if (provider instanceof AbstractProvider) {
                 provider = ((AbstractProvider) provider).variantFor(transform);
             }
-            return swapAndScaleAxes(transform);
+            return swapAndScaleAxes(unique(transform));
         } catch (FactoryException exception) {
             if (warning != null) {
                 exception.addSuppressed(warning);
@@ -807,7 +784,9 @@ public class ParameterizedTransformBuilder implements 
MathTransform.Builder, Mat
          * created transform; it does not change the operation.
          */
         if (normalized instanceof ParameterizedAffine && !(mt instanceof 
ParameterizedAffine)) {
-            mt = ((ParameterizedAffine) normalized).newTransform(mt);
+            if (mt != (mt = ((ParameterizedAffine) 
normalized).newTransform(mt))) {
+                mt = unique(mt);
+            }
         }
         return mt;
     }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/package-info.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/package-info.java
index 3895167703..00874455c0 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/package-info.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/package-info.java
@@ -34,20 +34,6 @@
  *     — changes a <i>defining conversion</i> into a complete conversion.</li>
  * </ul>
  *
- * <h2>Apache SIS specific behavior</h2>
- * The following operations have a behavior in Apache SIS which may be 
different
- * than the behavior found in other software products. Those particularities 
apply only when the math transform is
- * {@linkplain 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createParameterizedTransform
- * created directly}. Users do not need to care about them when the coordinate 
operation is
- * {@linkplain 
org.apache.sis.referencing.operation.DefaultCoordinateOperationFactory#createOperation
- * inferred by Apache SIS for a given pair of CRS}.
- *
- * <ul>
- *   <li><b>Longitude rotation</b> (EPSG:9601) — the longitude offset may be 
specified in any units,
- *     but SIS unconditionally converts the value to degrees. Consequently, 
the user is responsible
- *     for converting the longitude axis of source and target CRS to degrees 
before this operation is applied.</li>
- * </ul>
- *
  * <h2><i>Early binding</i> versus <i>late binding</i> implementations</h2>
  * There is sometimes multiple ways of transforming coordinates for a given 
pair of source and target CRS.
  * For example, the {@linkplain 
org.apache.sis.referencing.datum.BursaWolfParameters Bursa-Wolf parameters}
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
index 1226a486e1..f3f8c3368d 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
@@ -99,8 +99,7 @@ import org.opengis.metadata.Identifier;
  * The first matrix on the left side is for {@linkplain 
org.apache.sis.referencing.cs.CoordinateSystems#swapAndScaleAxes
  * swapping axes} from (<var>latitude</var>, <var>longitude</var>) to 
(<var>longitude</var>, <var>latitude</var>) order.
  * This matrix is shown here for completeness, but is not managed by this 
projection package. Axes swapping is managed
- * at a {@linkplain 
org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory#createParameterizedTransform
- * higher level}.</div>
+ * at a {@linkplain 
org.apache.sis.referencing.internal.ParameterizedTransformBuilder higher 
level}.</div>
  *
  * {@code NormalizedProjection} does not store the above cited parameters 
(central meridian, scale factor, <i>etc.</i>)
  * on intent (except indirectly), in order to make clear that those parameters 
are not used by subclasses.
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
index 930a981f92..3229427266 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/CoordinateSystemTransformBuilder.java
@@ -18,7 +18,6 @@ package org.apache.sis.referencing.operation.transform;
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Optional;
 import javax.measure.IncommensurableException;
 import org.opengis.util.FactoryException;
 import org.opengis.parameter.ParameterValueGroup;
@@ -32,7 +31,6 @@ import org.opengis.referencing.cs.PolarCS;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.OperationNotFoundException;
-import org.opengis.referencing.operation.OperationMethod;
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.cs.CoordinateSystems;
 import org.apache.sis.referencing.cs.DefaultCompoundCS;
@@ -48,12 +46,7 @@ import org.apache.sis.util.resources.Errors;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-class CoordinateSystemTransformBuilder implements MathTransform.Builder {
-    /**
-     * The factory to use for building the transform.
-     */
-    protected final MathTransformFactory factory;
-
+final class CoordinateSystemTransformBuilder extends MathTransformBuilder {
     /**
      * The source and target coordinate systems.
      */
@@ -66,18 +59,13 @@ class CoordinateSystemTransformBuilder implements 
MathTransform.Builder {
      */
     private Ellipsoid ellipsoid;
 
-    /**
-     * The operation method used for the transform.
-     */
-    private OperationMethod method;
-
     /**
      * Creates a new builder.
      *
      * @param  factory  the factory to use for building the transform.
      */
     CoordinateSystemTransformBuilder(final MathTransformFactory factory) {
-        this.factory = factory;
+        super(factory);
     }
 
     /**
@@ -110,15 +98,6 @@ class CoordinateSystemTransformBuilder implements 
MathTransform.Builder {
         }
     }
 
-    /**
-     * Returns the operation method used for creating the math transform from 
the parameter values.
-     * This information is known only after {@link #create()} has been invoked.
-     */
-    @Override
-    public Optional<OperationMethod> getMethod() {
-        return Optional.ofNullable(method);
-    }
-
     /**
      * Unsupported operation because this builder has no parameters.
      */
@@ -213,7 +192,7 @@ class CoordinateSystemTransformBuilder implements 
MathTransform.Builder {
         if (result == null) {
             result = single(source, target);
         }
-        return result;
+        return unique(result);
     }
 
     /**
@@ -263,7 +242,7 @@ class CoordinateSystemTransformBuilder implements 
MathTransform.Builder {
                         CoordinateSystems.replaceAxes(stepTarget, 
AxesConvention.NORMALIZED), stepTarget));
                 final MathTransform result = 
factory.createConcatenatedTransform(before,
                                              
factory.createConcatenatedTransform(tr, after));
-                method = (passthrough == 0 ? kernel.method : kernel.method3D);
+                provider = (passthrough == 0 ? kernel.method : 
kernel.method3D);
                 return result;
             }
         } catch (IllegalArgumentException | IncommensurableException e) {
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 c44cc8c2b6..a408b92ac3 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
@@ -44,23 +44,17 @@ import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.apache.sis.io.wkt.Parser;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.Classes;
 import org.apache.sis.util.privy.Constants;
 import org.apache.sis.util.iso.AbstractFactory;
-import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.collection.WeakHashSet;
 import org.apache.sis.referencing.privy.CoordinateOperations;
 import org.apache.sis.referencing.operation.DefaultOperationMethod;
-import org.apache.sis.referencing.operation.provider.AbstractProvider;
 import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.internal.ParameterizedTransformBuilder;
 import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
 import org.apache.sis.parameter.DefaultParameterValueGroup;
 import org.apache.sis.system.Reflect;
 
-// Specific to the geoapi-3.1 and geoapi-4.0 branches:
-import org.opengis.util.UnimplementedServiceException;
-
 
 /**
  * Low level factory for creating {@linkplain AbstractMathTransform math 
transforms}.
@@ -191,12 +185,14 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
     /**
      * The last coordinate operation method used by a {@code create(…)} 
constructor.
      */
-    private final ThreadLocal<OperationMethod> lastMethod;
+    final ThreadLocal<OperationMethod> lastMethod;
 
     /**
      * The math transforms created so far. This pool is used in order to 
return instances of existing
      * math transforms when possible. If {@code null}, then no pool should be 
used. A null value is
      * preferable when the transforms are known to be short-lived, for 
avoiding the cost of caching them.
+     *
+     * @see #unique(MathTransform)
      */
     private final WeakHashSet<MathTransform> pool;
 
@@ -482,38 +478,9 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
     @Override
     public MathTransform.Builder builder(final String method) throws 
NoSuchIdentifierException {
         if (method.replace('_', ' 
').equalsIgnoreCase(Constants.COORDINATE_SYSTEM_CONVERSION)) {
-            return new CoordinateSystemTransformBuilder(this) {
-                @Override public MathTransform create() throws 
FactoryException {
-                    try {
-                        return super.create();
-                    } finally {
-                        ((DefaultMathTransformFactory) 
factory).lastMethod.set(getMethod().orElse(null));
-                    }
-                }
-            };
-        }
-        return new ContextBuilder(this, getOperationMethod(method));
-    }
-
-    /**
-     * Builder of a parameterized math transform, which is also the context 
for transform providers.
-     * Instances are created by {@link #builder(String)}. The same instance is 
also used for context
-     * given to {@link MathTransformProvider}.
-     */
-    private static final class ContextBuilder extends 
ParameterizedTransformBuilder {
-        /** Creates a new builder for the given operation method. */
-        ContextBuilder(final DefaultMathTransformFactory factory, final 
OperationMethod method) {
-            super(factory, method);
-        }
-
-        /** Creates the parameterized transform. */
-        @Override public MathTransform create() throws FactoryException {
-            try {
-                return super.create();
-            } finally {
-                ((DefaultMathTransformFactory) 
getFactory()).lastMethod.set(provider);
-            }
+            return new CoordinateSystemTransformBuilder(this);
         }
+        return new ParameterizedTransformBuilder(this, 
getOperationMethod(method));
     }
 
     /**
@@ -533,8 +500,12 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
      * @see #getAvailableMethods(Class)
      * @see #createParameterizedTransform(ParameterValueGroup)
      * @see AbstractMathTransform#getParameterValues()
+     *
+     * @deprecated This {@linkplain #createParameterizedTransform way to 
create parameterized transform} is ambiguous.
+     * Use {@link #builder(String)} instead.
      */
     @Override
+    @Deprecated(since="1.5")
     public ParameterValueGroup getDefaultParameters(final String method) 
throws NoSuchIdentifierException {
         return getOperationMethod(method).getParameters().createValue();
     }
@@ -571,7 +542,7 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
         /**
          * The builder, created when first needed.
          */
-        private ContextBuilder builder;
+        private ParameterizedTransformBuilder builder;
 
         /**
          * The parameters actually used.
@@ -703,12 +674,12 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
         /**
          * Returns the builder on which to delegate the {@code MathTransform} 
creation.
          */
-        final ContextBuilder builder() throws FactoryException {
+        final ParameterizedTransformBuilder builder() throws FactoryException {
             if (builder == null) {
                 if (factory == null) {
                     factory = provider();
                 }
-                builder = new ContextBuilder(factory, null);
+                builder = new ParameterizedTransformBuilder(factory, null);
                 if (parameters != null) {
                     builder.setParameters(parameters, false);
                 }
@@ -880,41 +851,19 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
      * @see #getAvailableMethods(Class)
      * @see #getLastMethodUsed()
      * @see 
org.apache.sis.parameter.ParameterBuilder#createGroupForMapProjection(ParameterDescriptor...)
+     *
+     * @deprecated This constructor is ambiguous when axis directions are 
parts of the map projection definition
+     * as in <q>Transverse Mercator (South Orientated)</q>.
+     * Use {@link #builder(String)} instead for allowing the implementation to 
resolve such ambiguities.
      */
     @Override
+    @Deprecated(since="1.5")
     public MathTransform createParameterizedTransform(final 
ParameterValueGroup parameters)
             throws NoSuchIdentifierException, FactoryException
     {
-        OperationMethod  method  = null;
-        RuntimeException failure = null;
-        MathTransform transform;
-        try {
-            method = CoordinateOperations.findMethod(this, 
parameters.getDescriptor());
-            /*
-             * Will catch only exceptions that may be the result of improper 
parameter usage (e.g. a value out
-             * of range). Do not catch exceptions caused by programming errors 
(e.g. null pointer exception).
-             */
-            if (method instanceof MathTransformProvider) try {
-                transform = ((MathTransformProvider) 
method).createMathTransform(this, parameters);
-            } catch (IllegalArgumentException | IllegalStateException 
exception) {
-                throw new 
InvalidGeodeticParameterException(exception.getLocalizedMessage(), exception);
-            } else {
-                throw new UnimplementedServiceException(Errors.format(
-                        Errors.Keys.UnsupportedImplementation_1, 
Classes.getClass(method)));
-            }
-            transform = unique(transform);
-            if (method instanceof AbstractProvider) {
-                method = ((AbstractProvider) method).variantFor(transform);
-            }
-        } catch (FactoryException e) {
-            if (failure != null) {
-                e.addSuppressed(failure);
-            }
-            throw e;
-        } finally {
-            lastMethod.set(method);     // May be null in case of failure, 
which is intended.
-        }
-        return transform;
+        final var builder = new ParameterizedTransformBuilder(this, null);
+        builder.setParameters(parameters, false);
+        return builder.create();
     }
 
     /**
@@ -1008,7 +957,7 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
         ArgumentChecks.ensureNonNull("baseCRS",    baseCRS);
         ArgumentChecks.ensureNonNull("parameters", parameters);
         ArgumentChecks.ensureNonNull("derivedCS",  derivedCS);
-        final var builder = new ContextBuilder(this, null);
+        final var builder = new ParameterizedTransformBuilder(this, null);
         builder.setParameters(parameters, true);
         builder.setSourceAxes(baseCRS);
         builder.setTargetAxes(derivedCS, null);
@@ -1234,7 +1183,7 @@ public class DefaultMathTransformFactory extends 
AbstractFactory implements Math
     /**
      * Replaces the given transform by a unique instance, if one already 
exists.
      */
-    private MathTransform unique(final MathTransform tr) {
+    final MathTransform unique(final MathTransform tr) {
         return (pool != null) ? pool.unique(tr) : tr;
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java
new file mode 100644
index 0000000000..9ca49145f5
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java
@@ -0,0 +1,111 @@
+/*
+ * 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.transform;
+
+import java.util.Objects;
+import java.util.Optional;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.MathTransformFactory;
+import org.opengis.referencing.operation.OperationMethod;
+import org.apache.sis.metadata.iso.citation.Citations;
+import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.util.privy.Strings;
+
+
+/**
+ * Builder of a parameterized math transform using a method identified by a 
name or code.
+ * A builder instance is created by a call to {@link 
DefaultMathTransformFactory#builder(String)}.
+ * The {@linkplain #parameters() parameters} are set to default values and 
should be modified
+ * in-place by the caller. If the transform requires semi-major and semi-minor 
axis lengths,
+ * those parameters can be set directly or {@linkplain #setSourceAxes 
indirectly}.
+ * Then, the transform is created by a call to {@link #create()}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.5
+ * @since   1.5
+ */
+public abstract class MathTransformBuilder implements MathTransform.Builder {
+    /**
+     * The factory to use for building the transform.
+     */
+    protected final MathTransformFactory factory;
+
+    /**
+     * The provider that created the parameterized {@link MathTransform} 
instance, or {@code null}
+     * if this information does not apply. This is initially set to the 
operation method specified
+     * in the call to {@link #builder(String)}, but may be modified by {@link 
#create()}.
+     *
+     * <p>This operation method is usually an instance of {@link 
MathTransformProvider},
+     * but not necessarily.</p>
+     *
+     * @see #getMethod()
+     */
+    protected OperationMethod provider;
+
+    /**
+     * Creates a new builder.
+     *
+     * @param  factory  factory to use for building the transform.
+     */
+    protected MathTransformBuilder(final MathTransformFactory factory) {
+        this.factory = Objects.requireNonNull(factory);
+    }
+
+    /**
+     * Returns the operation method used for creating the math transform from 
the parameter values.
+     * This is initially the operation method specified in the call to {@link 
#builder(String)},
+     * but may change after the call to {@link #create()} if the method has 
been adjusted because
+     * of the parameter values.
+     *
+     * @return the operation method used for creating the math transform from 
the parameter values.
+     */
+    @Override
+    public final Optional<OperationMethod> getMethod() {
+        return Optional.ofNullable(provider);
+    }
+
+    /**
+     * Eventually replaces the given transform by a unique instance. The 
replacement is done
+     * only if the {@linkplain #factory} is an instance of {@link 
DefaultMathTransformFactory}
+     * and {@linkplain DefaultMathTransformFactory#caching(boolean) caching} 
is enabled.
+     *
+     * <p>This is a helper method for {@link #create()} implementations.</p>
+     *
+     * @param  result  the newly created transform.
+     * @return a transform equals to the given transform (may be the given 
transform itself).
+     */
+    protected MathTransform unique(MathTransform result) {
+        if (factory instanceof DefaultMathTransformFactory) {
+            final var df = (DefaultMathTransformFactory) factory;
+            df.lastMethod.set(getMethod().orElse(null));
+            result = df.unique(result);
+        }
+        return result;
+    }
+
+    /**
+     * Returns a string representation of this builder for debugging purposes.
+     *
+     * @return a string representation of this builder.
+     */
+    @Override
+    public String toString() {
+        return Strings.toString(getClass(),
+                "factory", Citations.getIdentifier(factory.getVendor()),
+                "method", IdentifiedObjects.getDisplayName(provider, null));
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
index 83aebfe4e1..b0b03ff68d 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/projection/MapProjectionTestCase.java
@@ -29,6 +29,7 @@ import org.apache.sis.parameter.Parameters;
 import org.apache.sis.util.privy.Constants;
 import org.apache.sis.referencing.operation.DefaultOperationMethod;
 import org.apache.sis.referencing.operation.provider.MapProjection;
+import org.apache.sis.referencing.operation.provider.AbstractProvider;
 import org.apache.sis.referencing.operation.transform.CoordinateDomain;
 import org.apache.sis.referencing.operation.transform.MathTransformFactoryMock;
 import org.apache.sis.referencing.operation.transform.MathTransformProvider;
@@ -150,7 +151,7 @@ abstract class MapProjectionTestCase extends 
MathTransformTestCase {
      * Initializes a complete projection (including conversion from degrees to 
radians) for the given provider.
      * Base CRS axis order is (longitude, latitude).
      */
-    final void createCompleteProjection(final DefaultOperationMethod provider,
+    final void createCompleteProjection(final AbstractProvider provider,
             final double semiMajor,
             final double semiMinor,
             final double centralMeridian,
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
index f368841e2d..0a9459255d 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/MathTransformFactoryMock.java
@@ -17,6 +17,7 @@
 package org.apache.sis.referencing.operation.transform;
 
 import java.util.Set;
+import java.util.Optional;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.metadata.citation.Citation;
@@ -28,7 +29,6 @@ import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.SingleOperation;
-import org.apache.sis.referencing.operation.DefaultOperationMethod;
 import org.apache.sis.referencing.operation.provider.AbstractProvider;
 
 // Test dependencies
@@ -48,7 +48,7 @@ public final class MathTransformFactoryMock implements 
MathTransformFactory {
     /**
      * The operation method.
      */
-    private final DefaultOperationMethod method;
+    private final AbstractProvider method;
 
     /**
      * Parameters used during the last creation of a math transform.
@@ -70,7 +70,7 @@ public final class MathTransformFactoryMock implements 
MathTransformFactory {
      *
      * @param  method  the operation method to put in this factory.
      */
-    public MathTransformFactoryMock(final DefaultOperationMethod method) {
+    public MathTransformFactoryMock(final AbstractProvider method) {
         this.method = method;
     }
 
@@ -107,6 +107,36 @@ public final class MathTransformFactoryMock implements 
MathTransformFactory {
         return method;
     }
 
+    /**
+     * Returns the builder for the operation method.
+     *
+     * @param  name  shall be the operation method name.
+     * @return the builder.
+     * @throws NoSuchIdentifierException if the given name is not the name
+     *         of the operation method known to this factory.
+     */
+    @Override
+    public MathTransform.Builder builder(final String name) throws 
NoSuchIdentifierException {
+        if (method.isHeuristicMatchForName(name)) {
+            final ParameterValueGroup parameters = 
method.getParameters().createValue();
+            return new MathTransform.Builder() {
+                @Override public Optional<OperationMethod> getMethod() {
+                    return Optional.of(method);
+                }
+
+                @Override public ParameterValueGroup parameters() {
+                    return parameters;
+                }
+
+                @Override public MathTransform create() throws 
FactoryException {
+                    lastParameters = parameters;
+                    return 
method.createMathTransform(MathTransformFactoryMock.this, parameters);
+                }
+            };
+        }
+        throw new NoSuchIdentifierException(null, name);
+    }
+
     /**
      * Returns the parameters for the operation method.
      *
@@ -116,6 +146,7 @@ public final class MathTransformFactoryMock implements 
MathTransformFactory {
      *         of the operation method known to this factory.
      */
     @Override
+    @Deprecated
     public ParameterValueGroup getDefaultParameters(final String name) throws 
NoSuchIdentifierException {
         if (method.isHeuristicMatchForName(name)) {
             return method.getParameters().createValue();
@@ -131,9 +162,10 @@ public final class MathTransformFactoryMock implements 
MathTransformFactory {
      * @throws FactoryException if the provider cannot create the transform.
      */
     @Override
+    @Deprecated
     public MathTransform createParameterizedTransform(ParameterValueGroup 
parameters) throws FactoryException {
         lastParameters = parameters;
-        return ((MathTransformProvider) method).createMathTransform(this, 
parameters);
+        return method.createMathTransform(this, parameters);
     }
 
     /**
@@ -200,17 +232,6 @@ public final class MathTransformFactoryMock implements 
MathTransformFactory {
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * Unimplemented method.
-     *
-     * @param  code  ignored.
-     * @return never returned.
-     */
-    @Override
-    public MathTransform.Builder builder(String code) {
-        throw new UnsupportedOperationException();
-    }
-
     /**
      * Unimplemented method.
      *
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/MetadataServices.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/MetadataServices.java
index c20f80d7c5..b3cc0b19c8 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/MetadataServices.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/MetadataServices.java
@@ -129,7 +129,7 @@ public class MetadataServices extends OptionalDependency {
          */
         final UML uml = code.getClass().getAnnotation(UML.class);
         if (uml != null) try {
-            return 
ResourceBundles.codeLists(locale).getString(uml.identifier() + '.' + 
code.identifier());
+            return 
ResourceBundles.codeLists(locale).getString(uml.identifier() + '.' + 
code.identifier().orElse(code.name()));
         } catch (MissingResourceException e) {
             /*
              * Ignore. The reason for not finding the resource may because of 
above code not covering enough cases.
diff --git a/geoapi/snapshot b/geoapi/snapshot
index e57e817bb1..48d58002a5 160000
--- a/geoapi/snapshot
+++ b/geoapi/snapshot
@@ -1 +1 @@
-Subproject commit e57e817bb1965d241d4f16f498499d6bb304fddd
+Subproject commit 48d58002a5f500446c1237bf8718f018d0f90982


Reply via email to