sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 03/03: Hide SQLMM class from public API (the function that it provides are available through DefaultFilterFactory) and refactor tests.
Date Mon, 26 Aug 2019 17:28:19 GMT
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 a206c7bd933939d81820e89703ec65590c5334ff
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Mon Aug 26 19:27:32 2019 +0200

    Hide SQLMM class from public API (the function that it provides are available through DefaultFilterFactory) and refactor tests.
---
 .../apache/sis/filter/DefaultFilterFactory.java    | 234 ++++++++++++---------
 .../src/main/java/org/apache/sis/filter/SQLMM.java |  53 ++---
 .../sis/internal/feature/FunctionRegister.java     |  39 ++--
 .../org/apache/sis/internal/feature/Resources.java |   5 +
 .../sis/internal/feature/Resources.properties      |   1 +
 .../sis/internal/feature/Resources_fr.properties   |   1 +
 ...rg.apache.sis.internal.feature.FunctionRegister |   3 -
 .../test/java/org/apache/sis/filter/SQLMMTest.java | 234 ++++++++++++---------
 8 files changed, 322 insertions(+), 248 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
index 94a1cb4..018b129 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/DefaultFilterFactory.java
@@ -18,12 +18,10 @@ package org.apache.sis.filter;
 
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.ServiceLoader;
 import java.util.Set;
-import org.apache.sis.internal.feature.FunctionRegister;
 import org.opengis.filter.*;
 import org.opengis.filter.capability.*;
 import org.opengis.filter.capability.SpatialOperator;
@@ -35,6 +33,10 @@ import org.opengis.filter.temporal.*;
 import org.opengis.geometry.Envelope;
 import org.opengis.geometry.Geometry;
 import org.opengis.util.GenericName;
+import org.apache.sis.internal.system.Modules;
+import org.apache.sis.internal.system.SystemListener;
+import org.apache.sis.internal.feature.FunctionRegister;
+import org.apache.sis.internal.feature.Resources;
 
 
 /**
@@ -51,21 +53,25 @@ import org.opengis.util.GenericName;
  * @module
  */
 public class DefaultFilterFactory implements FilterFactory2 {
-
-    //TODO we should use a class like FeatureNaming to store and find registers.
-    //but it is not accessible here, should we move it ?
-    private static Map<String,FunctionRegister> FUNCTION_REGISTERS = new HashMap<>();
+    /**
+     * All functions identified by a name like {@code "cos"}, {@code "hypot"}, <i>etc</i>.
+     * The actual function creations is delegated to an external factory such as {@link SQLMM}.
+     * The factories are fetched by {@link #function(String, Expression...)} when first needed.
+     * This factory is cleared if classpath changes, for allowing dynamic reloading.
+     *
+     * @see #function(String, Expression...)
+     */
+    private static final Map<String,FunctionRegister> FUNCTION_REGISTERS = new HashMap<>();
     static {
-        final Iterator<FunctionRegister> iterator = ServiceLoader.load(FunctionRegister.class).iterator();
-        while (iterator.hasNext()) {
-            FunctionRegister register = iterator.next();
-            for (String name : register.getNames()) {
-                FUNCTION_REGISTERS.put(name, register);
+        SystemListener.add(new SystemListener(Modules.FEATURE) {
+            @Override protected void classpathChanged() {
+                synchronized (FUNCTION_REGISTERS) {
+                    FUNCTION_REGISTERS.clear();
+                }
             }
-        }
+        });
     }
 
-
     /**
      * Creates a new factory.
      */
@@ -97,7 +103,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public BBOX bbox(final Expression e, final double minx, final double miny,
@@ -107,7 +113,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public BBOX bbox(final Expression e, final Envelope bounds) {
@@ -135,7 +141,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Beyond beyond(final Expression left, final Expression right,
@@ -145,7 +151,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Contains contains(final String propertyName, final Geometry geometry) {
@@ -155,7 +161,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Contains contains(final Expression left, final Expression right) {
@@ -163,7 +169,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Crosses crosses(final String propertyName, final Geometry geometry) {
@@ -173,7 +179,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Crosses crosses(final Expression left, final Expression right) {
@@ -181,7 +187,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Disjoint disjoint(final String propertyName, final Geometry geometry) {
@@ -191,7 +197,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Disjoint disjoint(final Expression left, final Expression right) {
@@ -199,7 +205,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public DWithin dwithin(final String propertyName, final Geometry geometry,
@@ -211,7 +217,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public DWithin dwithin(final Expression left, final Expression right,
@@ -221,7 +227,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Equals equals(final String propertyName, final Geometry geometry) {
@@ -231,7 +237,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Equals equal(final Expression left, final Expression right) {
@@ -239,7 +245,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Intersects intersects(final String propertyName, final Geometry geometry) {
@@ -249,7 +255,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Intersects intersects(final Expression left, final Expression right) {
@@ -257,7 +263,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Overlaps overlaps(final String propertyName, final Geometry geometry) {
@@ -267,7 +273,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Overlaps overlaps(final Expression left, final Expression right) {
@@ -275,7 +281,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Touches touches(final String propertyName, final Geometry geometry) {
@@ -285,7 +291,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Touches touches(final Expression left, final Expression right) {
@@ -293,7 +299,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Within within(final String propertyName, final Geometry geometry) {
@@ -303,7 +309,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Within within(final Expression left, final Expression right) {
@@ -313,7 +319,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     // IDENTIFIERS /////////////////////////////////////////////////////////////
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public FeatureId featureId(final String id) {
@@ -321,7 +327,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public GmlObjectId gmlObjectId(final String id) {
@@ -331,7 +337,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     // FILTERS /////////////////////////////////////////////////////////////////
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public And and(final Filter filter1, final Filter filter2) {
@@ -339,7 +345,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public And and(final List<Filter> filters) {
@@ -347,7 +353,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Or or(final Filter filter1, final Filter filter2) {
@@ -355,7 +361,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Or or(final List<Filter> filters) {
@@ -363,7 +369,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Not not(final Filter filter) {
@@ -371,7 +377,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Id id(final Set<? extends Identifier> ids) {
@@ -379,7 +385,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyName property(final GenericName name) {
@@ -397,7 +403,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsBetween between(final Expression expression, final Expression lower, final Expression upper) {
@@ -405,7 +411,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsEqualTo equals(final Expression expression1, final Expression expression2) {
@@ -413,7 +419,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsEqualTo equal(final Expression expression1, final Expression expression2,
@@ -423,7 +429,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsNotEqualTo notEqual(final Expression expression1, final Expression expression2) {
@@ -431,7 +437,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsNotEqualTo notEqual(final Expression expression1, final Expression expression2,
@@ -441,7 +447,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsGreaterThan greater(final Expression expression1, final Expression expression2) {
@@ -449,7 +455,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsGreaterThan greater(final Expression expression1, final Expression expression2,
@@ -459,7 +465,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsGreaterThanOrEqualTo greaterOrEqual(final Expression expression1, final Expression expression2) {
@@ -467,7 +473,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsGreaterThanOrEqualTo greaterOrEqual(final Expression expression1, final Expression expression2,
@@ -477,7 +483,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLessThan less(final Expression expression1, final Expression expression2) {
@@ -485,7 +491,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLessThan less(final Expression expression1, final Expression expression2,
@@ -495,7 +501,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLessThanOrEqualTo lessOrEqual(final Expression expression1, final Expression expression2) {
@@ -503,7 +509,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLessThanOrEqualTo lessOrEqual(final Expression expression1, final Expression expression2,
@@ -513,7 +519,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLike like(final Expression expression, final String pattern) {
@@ -521,7 +527,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLike like(final Expression expression, final String pattern,
@@ -531,7 +537,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsLike like(final Expression expression, final String pattern,
@@ -542,7 +548,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsNull isNull(final Expression expression) {
@@ -550,7 +556,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public PropertyIsNil isNil(Expression expression) {
@@ -560,7 +566,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     // TEMPORAL FILTER /////////////////////////////////////////////////////////
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public After after(Expression expression1, Expression expression2) {
@@ -568,7 +574,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public AnyInteracts anyInteracts(Expression expression1, Expression expression2) {
@@ -576,7 +582,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Before before(Expression expression1, Expression expression2) {
@@ -584,7 +590,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Begins begins(Expression expression1, Expression expression2) {
@@ -592,7 +598,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public BegunBy begunBy(Expression expression1, Expression expression2) {
@@ -600,7 +606,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public During during(Expression expression1, Expression expression2) {
@@ -608,7 +614,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Ends ends(Expression expression1, Expression expression2) {
@@ -616,7 +622,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public EndedBy endedBy(Expression expression1, Expression expression2) {
@@ -624,7 +630,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Meets meets(Expression expression1, Expression expression2) {
@@ -632,7 +638,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public MetBy metBy(Expression expression1, Expression expression2) {
@@ -640,7 +646,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public OverlappedBy overlappedBy(Expression expression1, Expression expression2) {
@@ -648,7 +654,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public TContains tcontains(Expression expression1, Expression expression2) {
@@ -656,7 +662,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public TEquals tequals(Expression expression1, Expression expression2) {
@@ -664,7 +670,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public TOverlaps toverlaps(Expression expression1, Expression expression2) {
@@ -674,7 +680,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     // EXPRESSIONS /////////////////////////////////////////////////////////////
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Add add(final Expression expression1, final Expression expression2) {
@@ -682,7 +688,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Divide divide(final Expression expression1, final Expression expression2) {
@@ -690,7 +696,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Multiply multiply(final Expression expression1, final Expression expression2) {
@@ -698,7 +704,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Subtract subtract(final Expression expression1, final Expression expression2) {
@@ -706,19 +712,39 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Function function(final String name, final Expression... parameters) {
-        final FunctionRegister register = FUNCTION_REGISTERS.get(name);
+        final FunctionRegister register;
+        synchronized (FUNCTION_REGISTERS) {
+            if (FUNCTION_REGISTERS.isEmpty()) {
+                /*
+                 * Load functions when first needed or if classpath changed since last invocation.
+                 * The SQLMM factory is hard-coded because it is considered as a basic service to
+                 * be provided by all DefaultFilterFactory implementations, and for avoiding the
+                 * need to make SQLMM class public.
+                 */
+                final SQLMM r = new SQLMM();
+                for (final String fn : r.getNames()) {
+                    FUNCTION_REGISTERS.put(fn, r);
+                }
+                for (final FunctionRegister er : ServiceLoader.load(FunctionRegister.class)) {
+                    for (final String fn : er.getNames()) {
+                        FUNCTION_REGISTERS.putIfAbsent(fn, er);
+                    }
+                }
+            }
+            register = FUNCTION_REGISTERS.get(name);
+        }
         if (register == null) {
-            throw new IllegalArgumentException("Unknown function "+name);
+            throw new IllegalArgumentException(Resources.format(Resources.Keys.UnknownFunction_1, name));
         }
         return register.create(name, parameters);
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final Object value) {
@@ -726,7 +752,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final byte value) {
@@ -734,7 +760,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final short value) {
@@ -742,7 +768,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final int value) {
@@ -750,7 +776,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final long value) {
@@ -758,7 +784,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final float value) {
@@ -766,7 +792,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final double value) {
@@ -774,7 +800,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final char value) {
@@ -782,7 +808,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Literal literal(final boolean value) {
@@ -792,7 +818,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     // SORT BY /////////////////////////////////////////////////////////////////
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public SortBy sort(final String propertyName, final SortOrder order) {
@@ -802,7 +828,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     // CAPABILITIES ////////////////////////////////////////////////////////////
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Operator operator(final String name) {
@@ -810,7 +836,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public SpatialOperator spatialOperator(final String name, final GeometryOperand[] geometryOperands) {
@@ -818,7 +844,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public FunctionName functionName(final String name, final int nargs) {
@@ -826,7 +852,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public Functions functions(final FunctionName[] functionNames) {
@@ -834,7 +860,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public SpatialOperators spatialOperators(final SpatialOperator[] spatialOperators) {
@@ -842,7 +868,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public ComparisonOperators comparisonOperators(final Operator[] comparisonOperators) {
@@ -850,7 +876,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public ArithmeticOperators arithmeticOperators(final boolean simple, final Functions functions) {
@@ -858,7 +884,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public ScalarCapabilities scalarCapabilities(final ComparisonOperators comparison,
@@ -868,7 +894,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public SpatialCapabilities spatialCapabilities(
@@ -878,7 +904,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public IdCapabilities idCapabilities(final boolean eid, final boolean fid) {
@@ -886,7 +912,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public FilterCapabilities capabilities(final String version,
@@ -897,7 +923,7 @@ public class DefaultFilterFactory implements FilterFactory2 {
     }
 
     /**
-     * {@inheritDoc }
+     * {@inheritDoc}
      */
     @Override
     public TemporalCapabilities temporalCapabilities(TemporalOperand[] temporalOperands, TemporalOperators temporal) {
diff --git a/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java b/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java
index 86d3196..b32d3dc 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/filter/SQLMM.java
@@ -16,20 +16,21 @@
  */
 package org.apache.sis.filter;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.sis.internal.feature.FunctionRegister;
-import org.apache.sis.util.ArgumentChecks;
+import java.util.Arrays;
+import java.util.Collection;
 import org.opengis.filter.expression.Expression;
 import org.opengis.filter.expression.Function;
 import org.opengis.util.FactoryException;
+import org.apache.sis.internal.feature.FunctionRegister;
+import org.apache.sis.internal.feature.Resources;
+import org.apache.sis.util.ArgumentChecks;
 
 
 /**
  * A register of functions defined by the SQL/MM standard.
+ * This standard is defined by <a href="https://www.iso.org/standard/60343.html">ISO/IEC 13249-3:2016
+ * Information technology — Database languages — SQL multimedia and application packages — Part 3: Spatial</a>.
  *
- * @todo Hide from public API.
  * @todo Implement all SQL/MM specification functions.
  *
  * @author  Johann Sorel (Geomatys)
@@ -37,37 +38,39 @@ import org.opengis.util.FactoryException;
  * @since   1.0
  * @module
  */
-public final class SQLMM implements FunctionRegister {
+final class SQLMM implements FunctionRegister {
     /**
-     * Names of all functions known to this register.
+     * Creates the default register.
      */
-    private static final Set<String> FUNCTIONS;
-    static {
-        Set<String> names = new HashSet<>();
-        names.add(ST_Transform.NAME);
-        names.add(ST_Centroid.NAME);
-        names.add(ST_Buffer.NAME);
-        FUNCTIONS = Collections.unmodifiableSet(names);
+    SQLMM() {
     }
 
     /**
-     * Creates the default register.
+     * Returns a unique name for this factory.
      */
-    public SQLMM() {
-    }
-
     @Override
     public String getIdentifier() {
         return "SQL/MM";
     }
 
+    /**
+     * Returns the names of all functions known to this register.
+     */
     @Override
-    public Set<String> getNames() {
-        return FUNCTIONS;
+    public Collection<String> getNames() {
+        return Arrays.asList(ST_Transform.NAME, ST_Centroid.NAME, ST_Buffer.NAME);
     }
 
+    /**
+     * Create a new function of the given name with given parameters.
+     *
+     * @param  name        name of the function to create.
+     * @param  parameters  function parameters.
+     * @return function for the given name and parameters.
+     * @throws IllegalArgumentException if function name is unknown or some parameters are illegal.
+     */
     @Override
-    public Function create(final String name, Expression... parameters) {
+    public Function create(final String name, Expression[] parameters) {
         ArgumentChecks.ensureNonNull("name", name);
         ArgumentChecks.ensureNonNull("parameters", parameters);
         parameters = parameters.clone();
@@ -77,9 +80,9 @@ public final class SQLMM implements FunctionRegister {
         try {
             switch (name) {
                 case ST_Transform.NAME: return new ST_Transform(parameters);
-                case ST_Centroid.NAME: return new ST_Centroid(parameters);
-                case ST_Buffer.NAME: return new ST_Buffer(parameters);
-                default: throw new IllegalArgumentException("Unknown function " + name);
+                case ST_Centroid.NAME:  return new ST_Centroid(parameters);
+                case ST_Buffer.NAME:    return new ST_Buffer(parameters);
+                default: throw new IllegalArgumentException(Resources.format(Resources.Keys.UnknownFunction_1, name));
             }
         } catch (FactoryException e) {
             throw new IllegalArgumentException(e);
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FunctionRegister.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FunctionRegister.java
index 343e3c3..b4af7b3 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FunctionRegister.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/FunctionRegister.java
@@ -16,38 +16,53 @@
  */
 package org.apache.sis.internal.feature;
 
-import java.util.Set;
+import java.util.Collection;
 import org.opengis.filter.expression.Expression;
 import org.opengis.filter.expression.Function;
 
 
 /**
+ * A factory of {@link org.opengis.filter} functions identified by their names.
+ * Each factory can provide an arbitrary number of functions, enumerated by {@link #getNames()}.
+ * The {@link org.apache.sis.filter.DefaultFilterFactory#function(String, Expression...)} method
+ * delegates to this interface for creating the function implementation for a given name.
  *
- * @author Johann Sorel (Geomatys)
+ * <p><b>Warning:</b> there is currently no mechanism for avoiding name collision.
+ * It is implementer responsibility to keep trace of the whole universe of functions and avoid collision.
+ * This interface is hidden in internal API (for now) for that reason, and also because the API may change
+ * in any future Apache SIS version.</p>
+ *
+ * @author  Johann Sorel (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ *
+ * @see org.opengis.filter.FilterFactory#function(String, Expression...)
  */
 public interface FunctionRegister {
     /**
-     *
-     * Note : should it be the starting element of all function names to avoid any conflict ?
+     * Returns a unique name for this factory.
      *
      * @return factory unique name.
      */
     String getIdentifier();
 
     /**
-     * Note : should we use GenericName ?
+     * Returns the names of all functions that this factory can create.
+     * It is currently implementer responsibility to ensure that there is no name collision with
+     * functions provided by other factories (this problem may be improved in future SIS release).
      *
      * @return set of supported function names.
      */
-    Set<String> getNames();
+    Collection<String> getNames();
 
     /**
-     * Create a new function with given parameters.
+     * Create a new function of the given name with given parameters.
      *
-     * @param name function name, not null
-     * @param parameters function parameters
-     * @return
-     * @throws IllegalArgumentException if function name is unknown or parameters do not match
+     * @param  name        name of the function to create (not null).
+     * @param  parameters  function parameters.
+     * @return function for the given name and parameters.
+     * @throws IllegalArgumentException if function name is unknown or some parameters are illegal.
      */
-    Function create(String name, Expression... parameters) throws IllegalArgumentException;
+    Function create(String name, Expression[] parameters) throws IllegalArgumentException;
 }
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
index 44d8258..76ef8c3 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
@@ -320,6 +320,11 @@ public final class Resources extends IndexedResourceBundle {
         public static final short UnknownDataType_1 = 50;
 
         /**
+         * Function “{0}” is unknown or unsupported.
+         */
+        public static final short UnknownFunction_1 = 58;
+
+        /**
          * Feature named “{0}” has not yet been resolved.
          */
         public static final short UnresolvedFeatureName_1 = 18;
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
index b63161e..8ae3d8a 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.properties
@@ -69,6 +69,7 @@ UnexpectedNumberOfBands_2         = Expected {0} bands but got {1}.
 UnexpectedNumberOfComponents_4    = The \u201c{1}\u201d value given to \u201c{0}\u201d property should be separable in {2} components, but we got {3}.
 UnexpectedNumberOfCoordinates_4   = The \u201c{0}\u201d feature at {1} has a {3} coordinate values, while we expected a multiple of {2}.
 UnknownDataType_1                 = Raster data type \u2018{0}\u2019 is unknown or unsupported.
+UnknownFunction_1                 = Function \u201c{0}\u201d is unknown or unsupported.
 UnresolvedFeatureName_1           = Feature named \u201c{0}\u201d has not yet been resolved.
 UnspecifiedCRS                    = Coordinate reference system is unspecified.
 UnspecifiedGridExtent             = Grid extent is unspecified.
diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
index dbfee3f..3828cfa 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
+++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.properties
@@ -75,6 +75,7 @@ UnexpectedNumberOfBands_2         = On attendait {0} bandes mais {1} ont \u00e9t
 UnexpectedNumberOfComponents_4    = La valeur \u00ab\u202f{1}\u202f\u00bb donn\u00e9e \u00e0 la propri\u00e9t\u00e9 \u00ab\u202f{0}\u202f\u00bb devrait \u00eatre s\u00e9parable en {2} composantes, mais on en a obtenus {3}.
 UnexpectedNumberOfCoordinates_4   = L\u2019entit\u00e9 nomm\u00e9e \u00ab\u202f{0}\u202f\u00bb \u00e0 {1} contient {3} coordonn\u00e9es, alors qu\u2019on attendait un multiple de {2}.
 UnknownDataType_1                 = Le type de donn\u00e9es raster \u2018{0}\u2019 est inconnu ou non-support\u00e9.
+UnknownFunction_1                 = La fonction \u00ab\u202f{0}\u202f\u00bb est inconnue ou non-support\u00e9e.
 UnresolvedFeatureName_1           = L\u2019entit\u00e9 nomm\u00e9e \u00ab\u202f{0}\u202f\u00bb n\u2019a pas encore \u00e9t\u00e9 r\u00e9solue.
 UnspecifiedCRS                    = Le syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es n\u2019a pas \u00e9t\u00e9 sp\u00e9cifi\u00e9.
 UnspecifiedGridExtent             = L\u2019\u00e9tendue de la grille n\u2019a pas \u00e9t\u00e9 sp\u00e9cifi\u00e9e.
diff --git a/core/sis-feature/src/main/resources/META-INF/services/org.apache.sis.internal.feature.FunctionRegister b/core/sis-feature/src/main/resources/META-INF/services/org.apache.sis.internal.feature.FunctionRegister
deleted file mode 100644
index d2b068f..0000000
--- a/core/sis-feature/src/main/resources/META-INF/services/org.apache.sis.internal.feature.FunctionRegister
+++ /dev/null
@@ -1,3 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements;
-# and to You under the Apache License, Version 2.0.
-org.apache.sis.filter.SQLMM
diff --git a/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java b/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java
index 89e9660..2e98852 100644
--- a/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java
+++ b/core/sis-feature/src/test/java/org/apache/sis/filter/SQLMMTest.java
@@ -16,159 +16,185 @@
  */
 package org.apache.sis.filter;
 
-import org.apache.sis.feature.builder.FeatureTypeBuilder;
-import org.apache.sis.referencing.CommonCRS;
-import org.apache.sis.test.TestCase;
-import org.junit.Assert;
-import org.junit.Test;
 import org.locationtech.jts.geom.Coordinate;
 import org.locationtech.jts.geom.Envelope;
+import org.locationtech.jts.geom.Geometry;
 import org.locationtech.jts.geom.GeometryFactory;
 import org.locationtech.jts.geom.LineString;
 import org.locationtech.jts.geom.Point;
 import org.locationtech.jts.geom.Polygon;
 import org.opengis.feature.Feature;
 import org.opengis.feature.FeatureType;
-import org.opengis.filter.FilterFactory2;
+import org.opengis.filter.FilterFactory;
 import org.opengis.filter.expression.Function;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.apache.sis.feature.builder.FeatureTypeBuilder;
+import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.referencing.CommonCRS;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.opengis.test.Assert.*;
 
 
 /**
  * Tests {@link SQLMM} functions implementations.
+ * Current implementation tests Java Topology Suite (JTS) implementation only.
  *
- * @author Johann Sorel (Geomatys)
+ * @author  Johann Sorel (Geomatys)
  * @version 1.0
  * @since   1.0
  * @module
  */
-public class SQLMMTest extends TestCase {
+public final strictfp class SQLMMTest extends TestCase {
     /**
      * The factory to use for creating the objects to test.
      */
-    private final FilterFactory2 factory = new DefaultFilterFactory();
-    private final GeometryFactory gf = new GeometryFactory();
+    private final FilterFactory factory;
 
     /**
-     * Test SQL/MM ST_Transform function.
+     * The factory to use for creating Java Topology Suite (JTS) objects.
      */
-    @Test
-    public void ST_TransformTest() {
+    private final GeometryFactory geometryFactory;
 
-        CoordinateReferenceSystem inCrs = CommonCRS.WGS84.normalizedGeographic();
-        CoordinateReferenceSystem outCrs = CommonCRS.WGS84.geographic();
+    /**
+     * Creates a new test case.
+     */
+    public SQLMMTest() {
+        factory = new DefaultFilterFactory();
+        geometryFactory = new GeometryFactory();
+    }
 
-        //test invalid
+    /**
+     * Verifies that attempts to create a function of the given name fail if no argument is provided.
+     */
+    private void assertRequireArguments(final String functionName) {
         try {
-            factory.function("ST_Transform");
-            Assert.fail("Creation with no argument should fail");
+            factory.function(functionName);
+            fail("Creation with no argument should fail");
         } catch (IllegalArgumentException ex) {
-            //ok
+            final String message = ex.getMessage();
+            assertTrue(message, message.contains("parameters"));
         }
+    }
 
-        //create a test feature
-        final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
-        ftb.setName("test");
-        ftb.addAttribute(Point.class).setName("geom").setCRS(inCrs);
+    /**
+     * Wraps the given geometry in a feature object. The geometry will be stored in a property named {@code "geom"}.
+     *
+     * @param  geometry  the geometry to wrap in a feature.
+     * @param  crs       the coordinate reference system to assign to the geometry.
+     */
+    private static Feature wrapInFeature(final Geometry geometry, final CoordinateReferenceSystem crs) {
+        final FeatureTypeBuilder ftb = new FeatureTypeBuilder().setName("test");
+        ftb.addAttribute(Point.class).setName("geom").setCRS(crs);
         final FeatureType type = ftb.build();
-        final Point geometry = gf.createPoint(new Coordinate(10, 30));
-        geometry.setUserData(inCrs);
+        geometry.setUserData(crs);
         final Feature feature = type.newInstance();
         feature.setPropertyValue("geom", geometry);
+        return feature;
+    }
 
-        { //test transform function using epsg code
-            final Function fct = factory.function("ST_Transform", factory.property("geom"), factory.literal("EPSG:4326"));
-
-            //check result
-            final Object newGeom = fct.evaluate(feature);
-            Assert.assertTrue(newGeom instanceof Point);
-            final Point trs = (Point) newGeom;
-            Assert.assertEquals(outCrs, trs.getUserData());
-            Assert.assertEquals(30.0, trs.getX(), 0.0);
-            Assert.assertEquals(10.0, trs.getY(), 0.0);
-        }
-
-        { //test transform function using crs object
-            final Function fct = factory.function("ST_Transform", factory.property("geom"), factory.literal(outCrs));
-
-            //check result
-            final Object newGeom = fct.evaluate(feature);
-            Assert.assertTrue(newGeom instanceof Point);
-            final Point trs = (Point) newGeom;
-            Assert.assertEquals(outCrs, trs.getUserData());
-            Assert.assertEquals(30.0, trs.getX(), 0.0);
-            Assert.assertEquals(10.0, trs.getY(), 0.0);
-        }
+    /**
+     * Evaluates the given function and returns its result as an object of the given type.
+     *
+     * @param  expectedType  the expected type of the result.
+     * @param  feature       the feature to use as input value. May be {@code null}.
+     * @param  testing       the function to test.
+     * @return evaluation result.
+     */
+    private static <G extends Geometry> G evaluate(final Class<G> expectedType, final Feature feature, final Function testing) {
+        final Object result = testing.evaluate(feature);
+        assertInstanceOf("Expected JTS geometry.", expectedType, result);
+        return expectedType.cast(result);
     }
 
     /**
-     * Test SQL/MM ST_Centroid function.
+     * Test SQL/MM {@link ST_Transform} function.
      */
     @Test
-    public void ST_CentroidTest() {
-
-        CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic();
+    public void testTransform() {
+        /*
+         * Verify that creation of a function without arguments is not allowed.
+         */
+        assertRequireArguments("ST_Transform");
+        /*
+         * Create a feature to be used for testing purpose. For this test, the CRS transformation
+         * will be simply a change of axis order from (λ,φ) to (φ,λ).
+         */
+        final Point geometry = geometryFactory.createPoint(new Coordinate(10, 30));
+        final Feature feature = wrapInFeature(geometry, HardCodedCRS.WGS84);
+        /*
+         * Test transform function using the full CRS object, then using only EPSG code.
+         */
+        testTransform(feature, HardCodedCRS.WGS84_φλ, HardCodedCRS.WGS84_φλ);
+        testTransform(feature, "EPSG:4326", CommonCRS.WGS84.geographic());
+    }
 
-        //test invalid
-        try {
-            factory.function("ST_Centroid");
-            Assert.fail("Creation with no argument should fail");
-        } catch (IllegalArgumentException ex) {
-            //ok
-        }
+    /**
+     * Tests {@link ST_Transform} on the given feature. The feature must have a property named {@code "geom"}.
+     * The result is expected to be a geometry using WGS84 datum with (φ,λ) axis order.
+     *
+     * @param  feature       the feature to use for testing the function.
+     * @param  specifiedCRS  the argument to give to the {@code "ST_Transform"} function.
+     * @param  expectedCRS   the CRS expected as a result of the transform function.
+     */
+    private void testTransform(final Feature feature, final Object specifiedCRS, final CoordinateReferenceSystem expectedCRS) {
+        final Point result = evaluate(Point.class, feature, factory.function("ST_Transform",
+                factory.property("geom"), factory.literal(specifiedCRS)));
+        assertEquals("userData", expectedCRS, result.getUserData());
+        assertEquals(30, result.getX(), STRICT);
+        assertEquals(10, result.getY(), STRICT);
+    }
 
-        final LineString geometry = gf.createLineString(new Coordinate[]{new Coordinate(10, 20), new Coordinate(30, 20)});
+    /**
+     * Test SQL/MM {@link ST_Centroid} function.
+     */
+    @Test
+    public void testCentroid() {
+        assertRequireArguments("ST_Centroid");
+        /*
+         * Creates a single linestring for testing the centroid function. The CRS is not used by this computation,
+         * but we declare it in order to verify that the information is propagated to the result.
+         */
+        final LineString geometry = geometryFactory.createLineString(new Coordinate[] {
+            new Coordinate(10, 20),
+            new Coordinate(30, 20)
+        });
         geometry.setSRID(4326);
-        geometry.setUserData(crs);
-
-
-        final Function fct = factory.function("ST_Centroid", factory.literal(geometry));
-
-        //check result
-        final Object newGeom = fct.evaluate(null);
-        Assert.assertTrue(newGeom instanceof Point);
-        final Point trs = (Point) newGeom;
-        Assert.assertEquals(crs, trs.getUserData());
-        Assert.assertEquals(4326, trs.getSRID());
-        Assert.assertEquals(20.0, trs.getX(), 0.0);
-        Assert.assertEquals(20.0, trs.getY(), 0.0);
-
+        geometry.setUserData(HardCodedCRS.WGS84_φλ);
+        /*
+         * Execute the function and check the result.
+         */
+        final Point result = evaluate(Point.class, null, factory.function("ST_Centroid", factory.literal(geometry)));
+        assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
+        assertEquals("SRID", 4326, result.getSRID());
+        assertEquals(20, result.getX(), STRICT);
+        assertEquals(20, result.getY(), STRICT);
     }
 
     /**
-     * Test SQL/MM ST_Buffer function.
+     * Test SQL/MM {@link ST_Buffer} function.
      */
     @Test
     public void ST_BufferTest() {
-
-        CoordinateReferenceSystem crs = CommonCRS.WGS84.geographic();
-
-        //test invalid
-        try {
-            factory.function("ST_Buffer");
-            Assert.fail("Creation with no argument should fail");
-        } catch (IllegalArgumentException ex) {
-            //ok
-        }
-
-        final Point geometry = gf.createPoint(new Coordinate(10, 20));
+        assertRequireArguments("ST_Buffer");
+        /*
+         * Creates a single point for testing the buffer function. The CRS is not used by this computation,
+         * but we declare it in order to verify that the information is propagated to the result.
+         */
+        final Point geometry = geometryFactory.createPoint(new Coordinate(10, 20));
+        geometry.setUserData(HardCodedCRS.WGS84_φλ);
         geometry.setSRID(4326);
-        geometry.setUserData(crs);
-
-
-        final Function fct = factory.function("ST_Buffer", factory.literal(geometry), factory.literal(1.0));
-
-        //check result
-        final Object newGeom = fct.evaluate(null);
-        Assert.assertTrue(newGeom instanceof Polygon);
-        final Polygon trs = (Polygon) newGeom;
-        Assert.assertEquals(crs, trs.getUserData());
-        Assert.assertEquals(4326, trs.getSRID());
-        Envelope env = trs.getEnvelopeInternal();
-        Assert.assertEquals(9.0, env.getMinX(), 0.0);
-        Assert.assertEquals(11.0, env.getMaxX(), 0.0);
-        Assert.assertEquals(19.0, env.getMinY(), 0.0);
-        Assert.assertEquals(21.0, env.getMaxY(), 0.0);
-
+        /*
+         * Execute the function and check the result.
+         */
+        final Polygon result = evaluate(Polygon.class, null, factory.function("ST_Buffer", factory.literal(geometry), factory.literal(1)));
+        assertEquals("userData", HardCodedCRS.WGS84_φλ, result.getUserData());
+        assertEquals("SRID", 4326, result.getSRID());
+        final Envelope env = result.getEnvelopeInternal();
+        assertEquals( 9, env.getMinX(), STRICT);
+        assertEquals(11, env.getMaxX(), STRICT);
+        assertEquals(19, env.getMinY(), STRICT);
+        assertEquals(21, env.getMaxY(), STRICT);
     }
 }


Mime
View raw message