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

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

commit f034daa245c647657ce75dfeea65ce131b99a1e6
Merge: e336ffb266 af22957697
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Jan 26 22:38:32 2026 +0100

    Merge branch 'geoapi-3.1'

 .../org/apache/sis/filter/ComparisonFilter.java    | 455 ++++-------
 .../main/org/apache/sis/filter/Optimization.java   | 116 ++-
 .../main/org/apache/sis/filter/TemporalFilter.java |  26 +-
 .../org/apache/sis/filter/TemporalOperation.java   | 131 ++--
 .../sis/filter/base/BinaryFunctionWidening.java    |   3 +-
 .../apache/sis/filter/base/ConvertFunction.java    |  12 +-
 .../main/org/apache/sis/filter/base/Node.java      |  24 +-
 .../apache/sis/filter/math/ArithmeticFunction.java |  79 +-
 .../org/apache/sis/filter/math/BinaryOperator.java |   9 +-
 .../main/org/apache/sis/filter/math/Function.java  |   6 +
 .../main/org/apache/sis/filter/math/Predicate.java |   3 +-
 .../org/apache/sis/filter/math/UnaryOperator.java  |   3 +-
 .../filter/{ => math}/ArithmeticFunctionTest.java  |   5 +-
 .../org/apache/sis/temporal/DefaultInstant.java    |  14 +-
 .../main/org/apache/sis/temporal/TimeMethods.java  | 843 ++++++++++++++++-----
 .../operation/transform/PassThroughTransform.java  |  10 +-
 .../operation/transform/TransformJoiner.java       | 250 +++++-
 .../operation/transform/WraparoundTransform.java   |  25 +-
 .../transform/WraparoundTransformTest.java         |  72 ++
 .../apache/sis/storage/base/MetadataBuilder.java   |   4 +-
 .../org/apache/sis/storage/FeatureQueryTest.java   |  41 +-
 .../main/org/apache/sis/converter/ClassPair.java   |   2 +-
 .../apache/sis/converter/ConverterRegistry.java    |   2 +-
 .../org/apache/sis/converter/DateConverter.java    |  14 +-
 .../org/apache/sis/converter/StringConverter.java  |   1 +
 .../org/apache/sis/converter/SystemRegistry.java   |   2 +-
 .../main/org/apache/sis/system/Loggers.java        |   3 +-
 .../sis/referencing/factory/sql/epsg/README.md     |  24 +-
 28 files changed, 1481 insertions(+), 698 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java
index b79c097a88,4025972525..28bd310aa7
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/ComparisonFilter.java
@@@ -18,32 -18,24 +18,21 @@@ package org.apache.sis.filter
  
  import java.math.BigDecimal;
  import java.math.BigInteger;
+ import java.time.DateTimeException;
  import java.util.List;
  import java.util.Collection;
- import java.util.Date;
- import java.util.Calendar;
  import java.util.Objects;
- import java.time.Instant;
- import java.time.LocalTime;
- import java.time.OffsetTime;
- import java.time.LocalDateTime;
- import java.time.OffsetDateTime;
- import java.time.ZonedDateTime;
- import java.time.ZoneId;
- import java.time.chrono.ChronoLocalDate;
- import java.time.chrono.ChronoLocalDateTime;
- import java.time.chrono.ChronoZonedDateTime;
- import java.time.temporal.ChronoField;
- import java.time.temporal.Temporal;
+ import java.util.function.BiPredicate;
 -import org.opengis.util.CodeList;
  import org.apache.sis.math.Fraction;
  import org.apache.sis.filter.base.Node;
  import org.apache.sis.filter.base.BinaryFunctionWidening;
+ import org.apache.sis.temporal.TimeMethods;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.filter.Filter;
 -import org.opengis.filter.Expression;
 -import org.opengis.filter.MatchAction;
 -import org.opengis.filter.ComparisonOperatorName;
 -import org.opengis.filter.BinaryComparisonOperator;
 -import org.opengis.filter.BetweenComparisonOperator;
 +// Specific to the main branch:
 +import org.apache.sis.pending.geoapi.filter.MatchAction;
 +import org.apache.sis.pending.geoapi.filter.ComparisonOperatorName;
 +import org.apache.sis.pending.geoapi.filter.BinaryComparisonOperator;
 +import org.apache.sis.pending.geoapi.filter.BetweenComparisonOperator;
  
  
  /**
@@@ -162,6 -154,118 +151,118 @@@ abstract class ComparisonFilter<R> exte
          return false;
      }
  
+     /**
+      * Whether to convert literals to the same type as non-literal parameters 
during the optimization phase.
+      * This is invoked by {@link Optimization} for deciding whether to 
attempt such replacement.
+      *
+      * @return whether it is okay to convert literals in advance.
+      */
+     @Override
+     public final boolean allowLiteralConversions() {
+         return true;
+     }
+ 
+     /**
+      * Tries to optimize this filter. Fist, this method applies the 
optimization documented
+      * in the {@linkplain Optimization.OnFilter#optimize default method 
impmementation}.
+      * Then, if it is possible to avoid to inspect the number types every 
time that the
+      * filter is evaluated, this method returns a more direct implementation.
+      *
+      * @param  optimization  the simplifications or optimizations to apply on 
this filter.
+      * @return the simplified or optimized filter, or {@code this} if no 
optimization has been applied.
+      */
+     @Override
+     public final Filter<R> optimize(final Optimization optimization) {
+         final Filter<R> result = 
Optimization.OnFilter.super.optimize(optimization);
+         if (result instanceof ComparisonFilter<?>) {
+             final var optimized = (ComparisonFilter<R>) result;
+             final Class<?> t1, t2;
+             if (isSpecialized(t1 = getResultClass(expression1)) &&
+                 isSpecialized(t2 = getResultClass(expression2)))
+             {
+                 final var numeric = optimized.new Numeric();
+                 if (numeric.evaluator != null) {
+                     return numeric;
+                 }
+                 final var temporal = new Time<>(TimeMethods.forTypes(t1, t2), 
t2);
+                 if (temporal.evaluator != null) {
+                     return temporal;
+                 }
+             }
+         }
+         return result;
+     }
+ 
+     /**
+      * Returns whether the given type is non-null and something more 
specialized than {@code Object}.
+      * This is used for avoiding unnecessary class-loading of {@link Numeric} 
and {@link Time} when
+      * they are sure to be unsuccessful.
+      */
+     private static boolean isSpecialized(final Class<?> type) {
+         return (type != null) && (type != Object.class);
+     }
+ 
+     /**
+      * An optimized versions of this filter for the case where the operands 
are numeric.
+      */
+     private final class Numeric extends Node implements Filter<R> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = 4969425622445580192L;
+ 
+         /** The expression which performs the comparison and returns the 
result as an integer. */
+         @SuppressWarnings("serial") final Expression<R, ? extends Number> 
evaluator;
+ 
+         /** Creates a new filter. Callers must verifies that {@link 
#evaluator} is non-null. */
+         Numeric() {evaluator = specialize();}
+ 
+         /** Delegates to the enclosing class.*/
 -        @Override public    CodeList<?>           getOperatorType()  {return 
ComparisonFilter.this.getOperatorType();}
++        @Override public    Enum<?>               getOperatorType()  {return 
ComparisonFilter.this.getOperatorType();}
+         @Override public    Class<? super R>      getResourceClass() {return 
ComparisonFilter.this.getResourceClass();}
+         @Override public    List<Expression<R,?>> getExpressions()   {return 
ComparisonFilter.this.getExpressions();}
+         @Override protected Collection<?>         getChildren()      {return 
ComparisonFilter.this.getChildren();}
+ 
+         /** Determines if the test represented by this filter passes with the 
given operands. */
+         @Override public boolean test(final R candidate) {
+             return ((Integer) evaluator.apply(candidate)) != 0;
+         }
+     }
+ 
+     /**
+      * An optimized versions of this filter for the case where the operands 
are temporal.
+      */
+     private final class Time<T,S> extends Node implements Filter<R> {
+         /** For cross-version compatibility during (de)serialization. */
+         private static final long serialVersionUID = -5132906457258846016L;
+ 
+         /** The function which performs the comparisons. */
+         @SuppressWarnings("serial") final BiPredicate<T,S> evaluator;
+ 
+         /** Creates a new filter. Callers must verifies that {@link 
#evaluator} is non-null. */
+         Time(final TimeMethods<T> methods, final Class<S> otherType) {
+             evaluator = (methods != null) ? methods.predicate(temporalTest(), 
otherType) : null;
+         }
+ 
+         /** Delegates to the enclosing class.*/
 -        @Override public    CodeList<?>           getOperatorType()  {return 
ComparisonFilter.this.getOperatorType();}
++        @Override public    Enum<?>               getOperatorType()  {return 
ComparisonFilter.this.getOperatorType();}
+         @Override public    Class<? super R>      getResourceClass() {return 
ComparisonFilter.this.getResourceClass();}
+         @Override public    List<Expression<R,?>> getExpressions()   {return 
ComparisonFilter.this.getExpressions();}
+         @Override protected Collection<?>         getChildren()      {return 
ComparisonFilter.this.getChildren();}
+ 
+         /** Determines if the test represented by this filter passes with the 
given operands. */
+         @Override public boolean test(final R candidate) {
+             @SuppressWarnings("unchecked")
+             final T left = (T) expression1.apply(candidate);
+             if (left != null) {
+                 @SuppressWarnings("unchecked")
+                 final S right = (S) expression2.apply(candidate);
+                 if (right != null) {
+                     return evaluator.test(left, right);
+                 }
+             }
+             return false;
+         }
+     }
+ 
      /**
       * Determines if the test(s) represented by this filter passes with the 
given operands.
       * Values of {@link #expression1} and {@link #expression2} can be two 
single values,
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalOperation.java
index 57962fa707,ff6fa3905a..66f6956580
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalOperation.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/TemporalOperation.java
@@@ -23,15 -23,12 +23,12 @@@ import java.time.temporal.Temporal
  import org.apache.sis.util.internal.shared.Strings;
  import org.apache.sis.util.collection.WeakHashSet;
  import org.apache.sis.temporal.TimeMethods;
- import static org.apache.sis.temporal.TimeMethods.BEFORE;
- import static org.apache.sis.temporal.TimeMethods.AFTER;
- import static org.apache.sis.temporal.TimeMethods.EQUAL;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.temporal.Period;
 -import org.opengis.temporal.Instant;
 -import org.opengis.temporal.IndeterminateValue;
 -import org.opengis.filter.TemporalOperatorName;
 +// Specific to the main branch:
 +import org.apache.sis.pending.geoapi.temporal.Period;
 +import org.apache.sis.pending.geoapi.temporal.Instant;
 +import org.apache.sis.pending.geoapi.temporal.IndeterminateValue;
 +import org.apache.sis.pending.geoapi.temporal.TemporalOperatorName;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/ArithmeticFunction.java
index 3e355f571d,469d03b35c..1df4b0c251
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/ArithmeticFunction.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/ArithmeticFunction.java
@@@ -94,7 -93,7 +93,7 @@@ public abstract class ArithmeticFunctio
       * @param  name  name of the attribute to create.
       * @return an attribute of the given name for numbers.
       */
-     private static DefaultAttributeType<Number> createNumericType(final 
String name) {
 -    private static AttributeType<Number> createNumericType(final ScopedName 
name) {
++    private static DefaultAttributeType<Number> createNumericType(final 
ScopedName name) {
          return createType(Number.class, name);
      }
  
@@@ -199,14 -197,11 +197,11 @@@
                               effective[1].toValueType(Number.class));
          }
  
-         /** Description of results of the {@code "Add"} expression. */
+         private static final ScopedName NAME = createName(FunctionNames.Add);
 -        private static final AttributeType<Number> TYPE = 
createNumericType(NAME);
 -        @Override protected AttributeType<Number> expectedType() {return 
TYPE;}
++        private static final DefaultAttributeType<Number> TYPE = 
createNumericType(NAME);
 +        @Override protected DefaultAttributeType<Number> expectedType() 
{return TYPE;}
-         private static final DefaultAttributeType<Number> TYPE = 
createNumericType(FunctionNames.Add);
- 
-         /** Representation of the {@code "Add"} operation. */
-         @Override protected char symbol() {return '+';}
          @Override public ScopedName getFunctionName() {return NAME;}
-         private static final ScopedName NAME = createName(FunctionNames.Add);
+         @Override protected char symbol() {return '+';}
  
          /** Applies this expression to the given operands. */
          @Override protected Number applyAsDouble  (double     left, double    
 right) {return left + right;}
@@@ -245,14 -239,11 +239,11 @@@
                                    effective[1].toValueType(Number.class));
          }
  
-         /** Description of results of the {@code "Subtract"} expression. */
+         private static final ScopedName NAME = 
createName(FunctionNames.Subtract);
 -        private static final AttributeType<Number> TYPE = 
createNumericType(NAME);
 -        @Override protected AttributeType<Number> expectedType() {return 
TYPE;}
++        private static final DefaultAttributeType<Number> TYPE = 
createNumericType(NAME);
 +        @Override protected DefaultAttributeType<Number> expectedType() 
{return TYPE;}
-         private static final DefaultAttributeType<Number> TYPE = 
createNumericType(FunctionNames.Subtract);
- 
-         /** Representation of the {@code "Subtract"} operation. */
-         @Override protected char symbol() {return '−';}
          @Override public ScopedName getFunctionName() {return NAME;}
-         private static final ScopedName NAME = 
createName(FunctionNames.Subtract);
+         @Override protected char symbol() {return '−';}
  
          /** Applies this expression to the given operands. */
          @Override protected Number applyAsDouble  (double     left, double    
 right) {return left - right;}
@@@ -291,14 -281,11 +281,11 @@@
                                    effective[1].toValueType(Number.class));
          }
  
-         /** Description of results of the {@code "Multiply"} expression. */
+         private static final ScopedName NAME = 
createName(FunctionNames.Multiply);
 -        private static final AttributeType<Number> TYPE = 
createNumericType(NAME);
 -        @Override protected AttributeType<Number> expectedType() {return 
TYPE;}
++        private static final DefaultAttributeType<Number> TYPE = 
createNumericType(NAME);
 +        @Override protected DefaultAttributeType<Number> expectedType() 
{return TYPE;}
-         private static final DefaultAttributeType<Number> TYPE = 
createNumericType(FunctionNames.Multiply);
- 
-         /** Representation of the {@code "Multiply"} operation. */
-         @Override protected char symbol() {return '×';}
          @Override public ScopedName getFunctionName() {return NAME;}
-         private static final ScopedName NAME = 
createName(FunctionNames.Multiply);
+         @Override protected char symbol() {return '×';}
  
          /** Applies this expression to the given operands. */
          @Override protected Number applyAsDouble  (double     left, double    
 right) {return left * right;}
@@@ -337,16 -323,13 +323,13 @@@
                                  effective[1].toValueType(Number.class));
          }
  
-         /** Description of results of the {@code "Divide"} expression. */
+         private static final ScopedName NAME = 
createName(FunctionNames.Divide);
 -        private static final AttributeType<Number> TYPE = 
createNumericType(NAME);
 -        @Override protected AttributeType<Number> expectedType() {return 
TYPE;}
++        private static final DefaultAttributeType<Number> TYPE = 
createNumericType(NAME);
 +        @Override protected DefaultAttributeType<Number> expectedType() 
{return TYPE;}
-         private static final DefaultAttributeType<Number> TYPE = 
createNumericType(FunctionNames.Divide);
- 
-         /** Representation of the {@code "Divide"} operation. */
-         @Override protected char symbol() {return '÷';}
          @Override public ScopedName getFunctionName() {return NAME;}
-         private static final ScopedName NAME = 
createName(FunctionNames.Divide);
+         @Override protected char symbol() {return '÷';}
  
-         /** Divides the given integers, changing the type if the result is 
not an integer. */
+         /** Applies this expression to the given operands. */
          @Override protected Number applyAsDouble  (double     left, double    
 right) {return left / right;}
          @Override protected Number applyAsFraction(Fraction   left, Fraction  
 right) {return left.divide(right);}
          @Override protected Number applyAsDecimal (BigDecimal left, 
BigDecimal right) {return left.divide(right);}
diff --cc 
endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/WraparoundTransformTest.java
index 55dd28d31d,ba6dacc002..b9671019fd
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/WraparoundTransformTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/WraparoundTransformTest.java
@@@ -31,9 -31,11 +31,11 @@@ import org.junit.jupiter.api.Test
  import static org.junit.jupiter.api.Assertions.*;
  import org.apache.sis.test.TestCase;
  import org.apache.sis.referencing.crs.HardCodedCRS;
+ import org.apache.sis.referencing.operation.matrix.Matrices;
+ import org.apache.sis.referencing.operation.matrix.MatrixSIS;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import static org.opengis.test.Assertions.assertMatrixEquals;
 +// Specific to the main branch:
 +import static org.apache.sis.test.GeoapiAssert.assertMatrixEquals;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
index 4cb4a801bf,d85f3abc94..4bd782842f
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/MetadataBuilder.java
@@@ -1146,12 -1141,12 +1146,12 @@@ public class MetadataBuilder 
       * If two dates are of the same type, retains the latest one if the type 
name starts with {@code "LATE_"}
       * or retains the earliest date otherwise.
       */
 -    private static void addEarliest(final Collection<CitationDate> dates, 
final CitationDate date, final DateType type) {
 +    private static void addEarliest(final Collection<CitationDate> dates, 
final DefaultCitationDate date, final DateType type) {
          for (final Iterator<CitationDate> it = dates.iterator(); 
it.hasNext();) {
              final CitationDate existing = it.next();
 -            if (type.equals(existing.getDateType())) {
 +            if (type.equals(existing.getDateType()) && existing instanceof 
DefaultCitationDate) {
-                 final int method = type.name().startsWith("LATE_") ? 
TimeMethods.BEFORE : TimeMethods.AFTER;
-                 if (TimeMethods.compareAny(method, ((DefaultCitationDate) 
existing).getReferenceDate(), date.getReferenceDate())) {
+                 TimeMethods.Test method = type.name().startsWith("LATE_") ? 
TimeMethods.Test.BEFORE : TimeMethods.Test.AFTER;
 -                if (TimeMethods.compareLenient(method, 
existing.getReferenceDate(), date.getReferenceDate())) {
++                if (TimeMethods.compareLenient(method, ((DefaultCitationDate) 
existing).getReferenceDate(), date.getReferenceDate())) {
                      it.remove();
                      break;
                  }
diff --cc 
endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
index acf5924e20,cdb9fbe5ea..230646b086
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureQueryTest.java
@@@ -90,10 -97,10 +91,10 @@@ public final class FeatureQueryTest ext
       * Creates a simple feature with a property flagged as an identifier.
       */
      private void createFeatureWithIdentifier() {
-         final FeatureTypeBuilder ftb = new 
FeatureTypeBuilder().setName("Test");
+         final var ftb = new FeatureTypeBuilder().setName("Test");
          
ftb.addAttribute(String.class).setName("id").addRole(AttributeRole.IDENTIFIER_COMPONENT);
 -        final FeatureType type = ftb.build();
 -        features = new Feature[] {
 +        final DefaultFeatureType type = ftb.build();
 +        features = new AbstractFeature[] {
              type.newInstance()
          };
          features[0].setPropertyValue("id", "id-0");
@@@ -109,9 -116,9 +110,9 @@@
       * @return the points created by this method in no particular order.
       */
      private Set<Point2D.Double> createFeaturesWithGeometry(final 
GeometryLibrary library) {
-         final FeatureTypeBuilder ftb = new FeatureTypeBuilder(null, library, 
null).setName("Test");
+         final var ftb = new FeatureTypeBuilder(null, library, 
null).setName("Test");
          
ftb.addAttribute(GeometryType.POINT).setCRS(HardCodedCRS.WGS84_LATITUDE_FIRST).setName("point");
 -        final FeatureType type = ftb.build();
 +        final DefaultFeatureType type = ftb.build();
          final var points = new HashSet<Point2D.Double>();
          final Geometries<?> factory = Geometries.factory(library);
          @SuppressWarnings("LocalVariableHidesMemberVariable")
@@@ -119,10 -126,10 +120,10 @@@
          for (int i=0; i < features.length; i++) {
              final var point = new Point2D.Double(-10 - i, 20 + i);
              assertTrue(points.add(point));
 -            final Feature f = type.newInstance();
 +            final AbstractFeature f = type.newInstance();
              f.setPropertyValue("point", factory.createPoint(point.x, 
point.y));
              features[i] = f;
-         };
+         }
          this.features = features;
          featureSet = new MemoryFeatureSet(null, type, 
Arrays.asList(features));
          return points;
@@@ -269,6 -291,40 +270,40 @@@
          verifyQueryResult(3);
      }
  
+     /**
+      * Verifies the effect of {@link FeatureQuery#setSelection(Filter)} on a 
property having a date.
+      *
+      * @throws DataStoreException if an error occurred while executing the 
query.
+      */
+     @Test
+     public void testSelectionOfDate() throws DataStoreException {
+         // Prepare the feature instances.
+         {
+             final var ftb = new FeatureTypeBuilder().setName("Test");
+             ftb.addAttribute(LocalDate.class).setName("value1");
 -            final FeatureType type = ftb.build();
 -            features = new Feature[4];
++            final DefaultFeatureType type = ftb.build();
++            features = new AbstractFeature[4];
+             Arrays.setAll(features, (i) -> {
 -                Feature feature = type.newInstance();
++                AbstractFeature feature = type.newInstance();
+                 feature.setPropertyValue("value1", LocalDate.of(2000, 1, 10 + 
i));
+                 return feature;
+             });
+             featureSet = new MemoryFeatureSet(null, type, 
Arrays.asList(features));
+         }
+         // Prepare the query.
+         {
 -            final FilterFactory<Feature,?,?> ff = 
DefaultFilterFactory.forFeatures();
++            final DefaultFilterFactory<AbstractFeature,?,?> ff = 
DefaultFilterFactory.forFeatures();
+             query.setSelection(ff.lessOrEqual(
+                     ff.property("value1", LocalDate.class),
+                     ff.literal(LocalDate.of(2000, 1, 12))));
+             assertXPathsEqual("value1");
+         }
+         // Verify the result.
+         final FeatureSet fs = query.execute(featureSet);
 -        final Feature[] result = fs.features(false).toArray(Feature[]::new);
++        final AbstractFeature[] result = 
fs.features(false).toArray(AbstractFeature[]::new);
+         assertArrayEquals(Arrays.copyOf(features, 3), result);
+     }
+ 
      /**
       * Verifies the effect of {@link 
FeatureQuery#setProjection(FeatureQuery.Column[])}.
       *
diff --cc 
optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
index e2158b075b,85ccdef170..bb9e8739ef
--- 
a/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
+++ 
b/optional/src/org.apache.sis.referencing.epsg/test/org/apache/sis/referencing/factory/sql/epsg/README.md
@@@ -60,10 -60,13 +60,13 @@@ export NON_FREE_DIR=$PW
  
  cd _<path to SIS project directory>_
  gradle clean test jar
- export 
CLASSPATH=~/.m2/repository/org/apache/derby/derby/10.14.2.0/derby-10.14.2.0.jar
+ export 
CLASSPATH=~/.m2/repository/org/apache/derby/derby/10.15.2.0/derby-10.15.2.0.jar
+ export 
CLASSPATH=~/.m2/repository/org/apache/derby/derbyshared/10.15.2.0/derbyshared-10.15.2.0.jar:$CLASSPATH
+ export 
CLASSPATH=~/.m2/repository/org/apache/derby/derbytools/10.15.2.0/derbytools-10.15.2.0.jar:$CLASSPATH
  export 
CLASSPATH=~/.m2/repository/org/postgresql/postgresql/42.7.7/postgresql-42.7.7.jar:$CLASSPATH
  export 
CLASSPATH=~/.m2/repository/javax/measure/unit-api/2.1.3/unit-api-2.1.3.jar:$CLASSPATH
+ export 
CLASSPATH=~/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.4/jakarta.xml.bind-api-4.0.4.jar:$CLASSPATH
 -export 
CLASSPATH=$PWD/geoapi/snapshot/geoapi/target/geoapi-3.1-SNAPSHOT.jar:$CLASSPATH
 +export 
CLASSPATH=$PWD/geoapi/snapshot/geoapi/target/geoapi-3.0.2.jar:$CLASSPATH
  export 
CLASSPATH=$PWD/endorsed/build/libs/org.apache.sis.referencing.jar:$CLASSPATH
  export 
CLASSPATH=$PWD/endorsed/build/libs/org.apache.sis.metadata.jar:$CLASSPATH
  export CLASSPATH=$PWD/endorsed/build/libs/org.apache.sis.util.jar:$CLASSPATH

Reply via email to