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

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

commit 3c800ecbf613bf07cf962cef6e7d9bdab100967f
Merge: 8eb0911e58 3b34cf323f
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed May 20 19:02:19 2026 +0200

    Merge branch 'geoapi-3.1'

 .../main/org/apache/sis/console/CommandRunner.java |   4 +-
 .../apache/sis/console/FormattedOutputCommand.java |   2 +-
 .../org/apache/sis/console/TranslateCommand.java   |   2 +-
 .../coverage/grid/CoordinateOperationFinder.java   |  44 +-
 .../apache/sis/coverage/grid/GridCRSBuilder.java   | 128 +++++-
 .../apache/sis/coverage/grid/GridGeometryTest.java |  48 ++
 .../org/apache/sis/metadata/MetadataStandard.java  |   2 +-
 .../org/apache/sis/metadata/TitleProperty.java     |   2 +-
 .../main/org/apache/sis/metadata/TreeNode.java     |  90 +++-
 .../org/apache/sis/metadata/TreeNodeChildren.java  |  44 +-
 .../org/apache/sis/metadata/TreeTableView.java     |  67 +--
 .../apache/sis/metadata/ValueExistencePolicy.java  | 104 +++--
 .../main/org/apache/sis/metadata/package-info.java |   2 +-
 .../org/apache/sis/xml/PooledUnmarshaller.java     |   8 +-
 .../main/org/apache/sis/xml/TransformedEvent.java  |   2 +-
 .../main/org/apache/sis/xml/XML.java               |   4 +-
 .../main/org/apache/sis/xml/bind/gcx/Anchor.java   |   9 +-
 .../sis/xml/internal/shared/InputFactory.java      |  42 +-
 .../main/org/apache/sis/xml/package-info.java      |  24 +-
 .../apache/sis/metadata/TreeNodeChildrenTest.java  |  14 +-
 .../test/org/apache/sis/metadata/TreeNodeTest.java |  11 +-
 .../apache/sis/metadata/TreeTableFormatTest.java   |  15 +-
 .../org/apache/sis/metadata/TreeTableViewTest.java |   3 +-
 .../sis/xml/internal/shared/InputFactoryTest.java  |   8 +-
 .../main/org/apache/sis/io/wkt/WKTFormat.java      |   4 +-
 .../sis/referencing/cs/CoordinateSystems.java      |   2 +-
 .../referencing/datum/DefaultDatumEnsemble.java    |  31 +-
 .../apache/sis/referencing/datum/package-info.java |   2 +-
 .../factory/CommonAuthorityFactory.java            |   6 +-
 .../referencing/factory/FactoryDataException.java  |   2 +-
 .../referencing/factory/GeodeticObjectFactory.java |   2 +-
 ...xception.java => InternalFactoryException.java} |  28 +-
 .../internal/ParameterizedTransformBuilder.java    |   4 +-
 .../internal/shared/CoordinateOperations.java      |   4 +-
 .../internal/shared/OperationMethodExt.java        |  73 +++
 .../operation/AbstractCoordinateOperation.java     |   7 +-
 .../operation/AbstractSingleOperation.java         |   4 +-
 .../operation/CoordinateOperationContext.java      |   2 +-
 .../operation/CoordinateOperationFinder.java       |  69 ++-
 .../operation/CoordinateOperationRegistry.java     |  14 +-
 .../operation/DefaultConcatenatedOperation.java    |   4 +-
 .../DefaultCoordinateOperationFactory.java         |  19 +-
 .../sis/referencing/operation/DefaultFormula.java  |   9 +-
 .../operation/DefaultOperationMethod.java          |   4 +-
 .../referencing/operation/gridded/LoadedGrid.java  |   2 +-
 .../operation/projection/ZonedGridSystem.java      |   3 +-
 .../provider/FranceGeocentricInterpolation.java    |   3 +-
 .../GeocentricAffineBetweenGeographic.java         |   3 +-
 .../operation/provider/GeocentricToGeographic.java |   3 +-
 .../operation/provider/Geographic3Dto2D.java       |   3 +-
 .../operation/provider/Spherical2Dto3D.java        |   3 +-
 .../operation/provider/VerticalOffset.java         |   3 +-
 .../transform/DefaultMathTransformFactory.java     |   3 +-
 .../transform/EllipsoidToRadiusTransform.java      |   3 +-
 .../operation/transform/MathTransformProvider.java |  31 +-
 .../test/org/apache/sis/io/wkt/WKTFormatTest.java  |  21 +-
 .../operation/DefaultTransformationTest.java       |   3 +-
 .../main/org/apache/sis/storage/landsat/Band.java  |   4 +-
 .../org/apache/sis/storage/landsat/BandGroup.java  |   2 +-
 .../apache/sis/storage/landsat/LandsatStore.java   |   2 +-
 .../apache/sis/storage/landsat/MetadataReader.java |   2 +-
 .../storage/landsat/LandsatStoreProviderTest.java  |   2 +-
 .../apache/sis/storage/geotiff/Compression.java    |   2 +-
 .../apache/sis/storage/geotiff/FormatModifier.java |   2 +-
 .../apache/sis/storage/geotiff/GeoTiffStore.java   |   4 +-
 .../apache/sis/storage/geotiff/NativeMetadata.java | 106 ++++-
 .../org/apache/sis/storage/geotiff/Writer.java     |   2 +-
 .../geotiff/reader/GridGeometryBuilder.java        |   2 +-
 .../geotiff/reader/ImageMetadataBuilder.java       |   2 +-
 .../sis/storage/geotiff/reader/Localization.java   |   3 +-
 .../sis/storage/geotiff/reader/XMLMetadata.java    |   5 +-
 .../sis/storage/geotiff/writer/GeoEncoder.java     |   2 +-
 .../storage/geotiff/reader/XMLMetadataTest.java    |   2 +-
 .../apache/sis/storage/netcdf/MetadataReader.java  |   2 +-
 .../org/apache/sis/storage/netcdf/NetcdfStore.java |   2 +-
 .../sis/storage/netcdf/NetcdfStoreProvider.java    |   2 +-
 .../apache/sis/storage/netcdf/base/Decoder.java    |   2 +-
 .../sis/storage/netcdf/base/RasterResource.java    |   2 +-
 .../sis/storage/netcdf/classic/ChannelDecoder.java |   2 +-
 .../sis/storage/netcdf/ucar/DecoderWrapper.java    |   2 +-
 .../main/org/apache/sis/storage/sql/SQLStore.java  |   4 +-
 .../apache/sis/storage/sql/feature/Database.java   |   2 +-
 .../sis/storage/sql/feature/SchemaModifier.java    |   4 +-
 .../sis/storage/sql/postgis/PostgresTest.java      |   2 +-
 .../main/org/apache/sis/storage/gpx/Store.java     |   2 +-
 .../main/org/apache/sis/storage/gpx/Types.java     |   2 +-
 .../sis/storage/xml/stream/StaxDataStore.java      |  41 +-
 .../org/apache/sis/storage/gpx/ReaderTest.java     |   2 +-
 .../org/apache/sis/storage/gpx/UpdaterTest.java    |   2 +-
 .../org/apache/sis/storage/gpx/WriterTest.java     |   2 +-
 .../org.apache.sis.storage/main/module-info.java   |  13 +
 .../apache/sis/io/stream/InternalOptionKey.java    |   2 +-
 .../org/apache/sis/storage/AbstractFeatureSet.java |   2 +-
 .../sis/storage/AbstractGridCoverageResource.java  |   2 +-
 .../org/apache/sis/storage/AbstractResource.java   |   2 +-
 .../org/apache/sis/storage/CoverageSubset.java     |   2 +-
 .../main/org/apache/sis/storage/DataOptionKey.java |  83 +---
 .../main/org/apache/sis/storage/DataStore.java     |   3 +-
 .../org/apache/sis/storage/DataStoreProvider.java  |  13 +
 .../org/apache/sis/storage/DataStoreRegistry.java  |   2 +-
 .../main/org/apache/sis/storage/FeatureSubset.java |   2 +-
 .../sis/storage/InternalDataStoreException.java    |   9 +-
 .../main/org/apache/sis/storage/OptionKey.java     | 297 ++++++++++++
 .../org/apache/sis/storage/StorageConnector.java   |  19 +-
 .../storage/aggregate/AggregatedFeatureSet.java    |   2 +-
 .../sis/storage/aggregate/AggregatedResource.java  |   2 +-
 .../aggregate/BandAggregateGridResource.java       |   2 +-
 .../aggregate/ConcatenatedGridResource.java        |   2 +-
 .../sis/storage/aggregate/GroupAggregate.java      |   2 +-
 .../main/org/apache/sis/storage/base/CodeType.java |  12 +-
 .../sis/storage/base/DocumentedStoreProvider.java  |   2 +-
 .../org/apache/sis/storage/base/PRJDataStore.java  |   2 +-
 .../org/apache/sis/storage/base/URIDataStore.java  |  12 +-
 .../sis/storage/base/URIDataStoreProvider.java     |  14 +-
 .../org/apache/sis/storage/base/package-info.java  |   2 +-
 .../main/org/apache/sis/storage/csv/Store.java     |   9 +-
 .../org/apache/sis/storage/csv/StoreProvider.java  |   6 +-
 .../org/apache/sis/storage/csv/package-info.java   |   2 +-
 .../apache/sis/storage/esri/AsciiGridStore.java    |   6 +-
 .../org/apache/sis/storage/esri/RasterStore.java   |   2 +-
 .../main/org/apache/sis/storage/folder/Store.java  |   7 +-
 .../apache/sis/storage/folder/StoreProvider.java   |   4 +-
 .../apache/sis/storage/folder/WritableStore.java   |   2 +-
 .../apache/sis/storage/image/WorldFileStore.java   |   4 +-
 .../apache/sis/storage/image/WritableStore.java    |   2 +-
 .../storage/{base => metadata}/LegalSymbols.java   |   3 +-
 .../{base => metadata}/MetadataBuilder.java        |   3 +-
 .../{base => metadata}/MetadataFetcher.java        |   8 +-
 .../{base => metadata}/ResourceLineage.java        |   2 +-
 .../storage/{base => metadata}/package-info.java   |   4 +-
 .../sis/storage/modifier/CoverageModifier.java     |  10 +-
 .../org/apache/sis/storage/tiling/TileMatrix.java  |   2 +-
 .../apache/sis/storage/tiling/TileMatrixSet.java   |   2 +-
 .../main/org/apache/sis/storage/wkt/Store.java     |   4 +-
 .../main/org/apache/sis/storage/xml/Store.java     |   4 +-
 .../org/apache/sis/storage/DataOptionKeyTest.java  |  46 --
 .../org/apache/sis/storage}/OptionKeyTest.java     |  23 +-
 .../apache/sis/storage/StorageConnectorTest.java   |   1 -
 .../apache/sis/storage/csv/StoreProviderTest.java  |   2 +-
 .../test/org/apache/sis/storage/csv/StoreTest.java |   5 +-
 .../apache/sis/storage/esri/WritableStoreTest.java |   2 +-
 .../sis/storage/image/WorldFileStoreTest.java      |   2 +-
 .../{base => metadata}/MetadataBuilderTest.java    |   2 +-
 .../main/org/apache/sis/io/CompoundFormat.java     |  77 ++--
 .../main/org/apache/sis/io/LineAppender.java       |   6 +-
 .../main/org/apache/sis/math/StatisticsFormat.java |  14 +-
 .../main/org/apache/sis/setup/GeometryLibrary.java |   2 +-
 .../main/org/apache/sis/setup/OptionKey.java       |  46 +-
 .../main/org/apache/sis/setup/package-info.java    |   5 +-
 .../sis/util/AbstractInternationalString.java      |  22 +-
 .../main/org/apache/sis/util/Exceptions.java       |   6 +-
 .../org/apache/sis/util/collection/TreeTable.java  |  18 +-
 .../sis/util/collection/TreeTableFormat.java       |  67 +--
 .../apache/sis/util/internal/shared/Constants.java |   2 +-
 .../sis/util/internal/shared/PropertyFormat.java   |  74 +--
 .../internal/shared/TreeFormatCustomization.java   |  51 ---
 .../sis/util/internal/shared/TreeTableForGUI.java  |  42 ++
 .../org/apache/sis/util/resources/Vocabulary.java  |  10 +
 .../sis/util/resources/Vocabulary.properties       |   2 +
 .../sis/util/resources/Vocabulary_fr.properties    |   2 +
 .../storage/coveragejson/CoverageJsonStore.java    |   2 +-
 .../sis/storage/geoheif/CoverageBuilder.java       |   9 +-
 .../apache/sis/storage/geoheif/GeoHeifStore.java   |   5 +-
 .../sis/storage/geoheif/UncompressedImage.java     |   2 +-
 .../main/org/apache/sis/storage/isobmff/Box.java   |   4 +-
 .../apache/sis/storage/isobmff/BoxRegistry.java    |   9 +
 .../apache/sis/storage/isobmff/ContainerBox.java   |  15 +-
 .../org/apache/sis/storage/isobmff/Extension.java  |  20 +-
 .../org/apache/sis/storage/isobmff/FullBox.java    |  41 +-
 .../{gimi/package-info.java => Incomplete.java}    |  19 +-
 .../sis/storage/isobmff/MainBoxRegistry.java       |   2 +-
 .../apache/sis/storage/isobmff/NodeSummary.java    |  59 +++
 .../org/apache/sis/storage/isobmff/Reader.java     |  19 +-
 .../main/org/apache/sis/storage/isobmff/Root.java  |   2 +-
 .../org/apache/sis/storage/isobmff/TreeNode.java   | 507 +++++++++++++++------
 .../storage/isobmff/base/ColourInformation.java    |   2 +-
 .../sis/storage/isobmff/base/CombinaisonType.java  |   2 +-
 .../apache/sis/storage/isobmff/base/Copyright.java |   3 +-
 .../sis/storage/isobmff/base/EntityToGroup.java    |   2 +
 .../storage/isobmff/base/FDItemInfoExtension.java  |   4 +-
 .../apache/sis/storage/isobmff/base/FileType.java  |   2 +-
 .../apache/sis/storage/isobmff/base/GroupList.java |   2 +-
 .../sis/storage/isobmff/base/HandlerReference.java |   2 +-
 .../storage/isobmff/base/IdentifiedMediaData.java  |   2 +-
 .../apache/sis/storage/isobmff/base/ItemInfo.java  |  17 +-
 .../sis/storage/isobmff/base/ItemInfoEntry.java    |   9 +-
 .../sis/storage/isobmff/base/ItemLocation.java     |   2 +-
 .../sis/storage/isobmff/base/ItemProperties.java   |  40 +-
 .../isobmff/base/ItemPropertyAssociation.java      |  41 +-
 .../isobmff/base/ItemPropertyContainer.java        |   2 +-
 .../sis/storage/isobmff/base/ItemReference.java    |   5 +-
 .../org/apache/sis/storage/isobmff/base/Meta.java  |   5 +-
 .../org/apache/sis/storage/isobmff/base/Movie.java |   2 +-
 .../sis/storage/isobmff/base/MovieHeader.java      |   5 +-
 .../sis/storage/isobmff/base/OriginalFileType.java |   2 +-
 .../sis/storage/isobmff/base/PrimaryItem.java      |   2 +-
 .../isobmff/base/ProgressiveDownloadInfo.java      |   5 +-
 .../isobmff/base/SingleItemTypeReference.java      |   2 +-
 .../org/apache/sis/storage/isobmff/base/Track.java |   2 +-
 .../sis/storage/isobmff/base/TrackHeader.java      |  27 +-
 .../apache/sis/storage/isobmff/base/UserData.java  |   2 +-
 .../storage/isobmff/{gimi => geo}/ModelCRS.java    |   9 +-
 .../isobmff/{gimi => geo}/ModelTiePoint.java       |  29 +-
 .../isobmff/{gimi => geo}/ModelTransformation.java |   6 +-
 .../isobmff/geo/TiledImageConfiguration.java       | 164 +++++++
 .../isobmff/{gimi => geo}/UnknownProperty.java     |   4 +-
 .../isobmff/{gimi => geo}/package-info.java        |   2 +-
 .../isobmff/gimi/TiledImageConfiguration.java      |  56 ---
 .../sis/storage/isobmff/image/CreationTime.java    |   1 +
 .../storage/isobmff/image/ModificationTime.java    |   1 +
 .../sis/storage/isobmff/image/UserDescription.java |   3 +-
 .../sis/storage/isobmff/mpeg/ChromaLocation.java   |   5 +-
 .../apache/sis/storage/isobmff/mpeg/Component.java |   1 +
 .../isobmff/mpeg/ComponentReferenceLevel.java      |   5 +-
 .../isobmff/mpeg/DepthMappingInformation.java      |   5 +-
 .../storage/isobmff/mpeg/DisparityInformation.java |   5 +-
 .../sis/storage/isobmff/mpeg/FieldInterlace.java   |   5 +-
 .../storage/isobmff/mpeg/FieldInterlaceType.java   |   5 +-
 .../isobmff/mpeg/FramePackingInformation.java      |   5 +-
 .../mpeg/PolarizationPatternDefinition.java        |   5 +-
 .../storage/isobmff/mpeg/SensorBadPixelsMap.java   |   5 +-
 .../mpeg/SensorNonUniformityCorrection.java        |   5 +-
 .../sis/storage/isobmff/mpeg/TAIClockInfo.java     |   6 +-
 .../sis/storage/isobmff/mpeg/TAITimeStamp.java     |   5 +-
 .../isobmff/mpeg/UncompressedFrameConfig.java      |   2 +-
 .../storage/isobmff/video/ContentDescribes.java    |   5 +-
 .../isobmff/{gimi => geo}/ExtensionTest.java       |   4 +-
 .../org/apache/sis/storage/geopackage/Content.java |   2 +-
 .../sis/storage/geopackage/GpkgStoreProvider.java  |   2 +-
 .../apache/sis/storage/geopackage/Initializer.java |   2 +-
 .../sis/storage/geopackage/GpkgStoreTest.java      |   2 +-
 .../conformance/CoreConformanceTest.java           |   2 +-
 .../main/org/apache/sis/storage/gsf/GSFStore.java  |   2 +-
 .../sis/storage/shapefile/ShapefileProvider.java   |  13 +-
 .../sis/storage/shapefile/ShapefileStore.java      |  38 +-
 .../apache/sis/storage/shapefile/dbf/DBFField.java |   2 +-
 .../sis/storage/shapefile/shp/ShapeRecord.java     |   1 +
 .../sis/storage/shapefile/ShapefileStoreTest.java  |  31 ++
 .../sis/storage/shapefile/dbf/DBFIOTest.java       |   2 +-
 .../apache/sis/storage/shapefile/dbf/Snippets.java |   2 +-
 .../test/org/apache/sis/storage/shapefile/noid.cpg |   1 +
 .../test/org/apache/sis/storage/shapefile/noid.dbf | Bin 0 -> 147 bytes
 .../test/org/apache/sis/storage/shapefile/noid.prj |   1 +
 .../test/org/apache/sis/storage/shapefile/noid.shp | Bin 0 -> 128 bytes
 .../test/org/apache/sis/storage/shapefile/noid.shx | Bin 0 -> 108 bytes
 .../sis/storage/shapefile/shp/ShapeIOTest.java     |   2 +-
 .../apache/sis/storage/shapefile/shp/Snippets.java |   2 +-
 .../apache/sis/gui/coverage/BandRangeTable.java    |   6 +-
 .../sis/gui/coverage/ImagePropertyExplorer.java    |  12 +-
 .../org/apache/sis/gui/dataset/FeatureTable.java   |  19 +-
 .../sis/gui/internal/IdentityValueFactory.java     |   4 +-
 .../sis/gui/internal/PropertyValueFormats.java     |   4 +-
 .../sis/gui/internal/PropertyValueFormatter.java   |   2 +-
 .../org/apache/sis/gui/metadata/MetadataTree.java  | 157 +++++--
 .../sis/gui/metadata/StandardMetadataTree.java     |  10 +-
 .../org/apache/sis/gui/metadata/package-info.java  |   2 +-
 .../org/apache/sis/storage/gdal/GDALStore.java     |   4 +-
 .../apache/sis/storage/gdal/GDALStoreProvider.java |   2 +-
 .../org/apache/sis/storage/gdal/TiledResource.java |   2 +-
 259 files changed, 2605 insertions(+), 1374 deletions(-)

diff --cc 
endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java
index 7a1df0e19d,5421b8639c..d3116da0a7
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/coverage/grid/GridCRSBuilder.java
@@@ -172,13 -247,11 +247,11 @@@ final class GridCRSBuilder extends Refe
              throws FactoryException
      {
          properties.put(DefiningConversion.NORMALIZED_KEY, Boolean.FALSE);
 -        properties.put(ObjectDomain.SCOPE_KEY, SCOPE);
 +        properties.put(Datum.SCOPE_KEY, SCOPE);
          grid.getGeographicExtent().ifPresent((domain) -> {
 -            properties.put(ObjectDomain.DOMAIN_OF_VALIDITY_KEY, new 
DefaultExtent(null, domain, null, null));
 +            properties.put(Datum.DOMAIN_OF_VALIDITY_KEY, new 
DefaultExtent(null, domain, null, null));
          });
-         if (grid.isDefined(GridGeometry.EXTENT)) {
-             extent = grid.getExtent();
-         }
+         fullGrid = grid;
          if (derived || grid.isDefined(GridGeometry.CRS | 
GridGeometry.GRID_TO_CRS)) try {
              separator = new 
TransformSeparator(grid.getGridToCRS(anchor).inverse());
              return forComponent(name, grid.getCoordinateReferenceSystem(), 0, 
0);
diff --cc 
endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/TreeNodeChildrenTest.java
index 879dbbc324,e59dfb3026..c6122ee9f7
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/TreeNodeChildrenTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/TreeNodeChildrenTest.java
@@@ -232,11 -229,11 +232,11 @@@ public final class TreeNodeChildrenTes
           * We need to perform the tests on the "Date" node, not on the 
"DefaultCitation" node.
           */
          final TreeTable.Node node = assertSingleton(create(citation, 
ValueExistencePolicy.COMPACT));
-         assertEquals(15340, ((LocalDate) 
node.getValue(TableColumn.VALUE)).toEpochDay());
-         final TreeNodeChildren children = (TreeNodeChildren) 
node.getChildren();
+         assertEquals(15340, assertInstanceOf(LocalDate.class, 
node.getValue(TableColumn.VALUE)).toEpochDay());
+         final TreeNodeChildren children = 
assertInstanceOf(TreeNodeChildren.class, node.getChildren());
          final String[] expected = {
              // The "Date" node should be omitted because merged with the 
parent "Date" node.
 -            "DateType.CREATION"
 +            "DateType[CREATION]"
          };
          assertEquals(0, children.titleProperty);
          assertFalse (children.isEmpty());
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
index b4ca7845a3,8d78cd0390..03988ff65c
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/datum/DefaultDatumEnsemble.java
@@@ -439,24 -556,23 +439,23 @@@ check:  if (it.hasNext()) 
       * @hidden because nothing new to said.
       */
      @Override
-     public boolean equals(final Object object, final ComparisonMode mode) {
-         if (!super.equals(object, mode)) {
-             return false;
-         }
-         switch (mode) {
-             case STRICT: {
-                 final var that = (DefaultDatumEnsemble<?>) object;
-                 return members.equals(that.members) && 
ensembleAccuracy.equals(that.ensembleAccuracy);
-             }
-             default: {
-                 if (!(object instanceof DefaultDatumEnsemble<?>)) {
-                     return false;
+     public boolean equals(final Object object, ComparisonMode mode) {
+         if (super.equals(object, mode)) {
+             switch (mode) {
+                 case STRICT: {
+                     final var that = (DefaultDatumEnsemble<?>) object;
+                     return members.equals(that.members) && 
ensembleAccuracy.equals(that.ensembleAccuracy);
+                 }
+                 default: {
 -                    final var that = (DatumEnsemble<?>) object;
++                    final var that = (DefaultDatumEnsemble<?>) object;
+                     if (Utilities.deepEquals(getEnsembleAccuracy(), 
that.getEnsembleAccuracy(), mode)) {
+                         if (mode == ComparisonMode.IGNORE_METADATA) mode = 
ComparisonMode.COMPATIBILITY;
+                         return Utilities.deepEquals(getMembers(), 
that.getMembers(), mode);
+                     }
                  }
-                 final var that = (DefaultDatumEnsemble<?>) object;
-                 return Utilities.deepEquals(getMembers(), that.getMembers(), 
mode) &&
-                        Utilities.deepEquals(getEnsembleAccuracy(), 
that.getEnsembleAccuracy(), mode);
              }
          }
+         return false;
      }
  
      /**
diff --cc 
endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index e5ccf4b103,611c8d7e25..9af989d31c
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@@ -1200,8 -1206,50 +1201,50 @@@ public class CoordinateOperationFinder 
          if (isIdentity(step3)) return concatenate(step1, step2);
          if (canHide(step1.getName())) return concatenate(concatenate(step1, 
step2), step3);
          if (canHide(step3.getName())) return concatenate(step1, 
concatenate(step2, step3));
-         final Map<String, ?> properties = defaultName(step1.getSourceCRS(), 
step3.getTargetCRS());
-         return factory.createConcatenatedOperation(properties, step1, step2, 
step3);
+         return createConcatenatedOperation(step1.getSourceCRS(), 
step3.getTargetCRS(), step1, step2, step3);
+     }
+ 
+     /**
+      * Creates an ordered sequence of two or more single coordinate 
operations.
+      * The {@code sourceCRS} and {@code targetCRS} arguments of this method 
are
+      * needed for detecting whether the source or last step needs to be 
reversed.
+      *
+      * <p>If any operation step uses a method that implements the {@link 
OperationMethodExt} interface,
+      * it will be used for enriching the metadata. It may go as far as 
overriding the default algorithm for
+      * computing the transform if a method supplies an {@value 
DefaultConcatenatedOperation#TRANSFORM_KEY}
+      * value.</p>
+      *
+      * @param  sourceCRS   the source <abbr>CRS</abbr>, or {@code null} for 
the source of the first step.
+      * @param  targetCRS   the target <abbr>CRS</abbr>, or {@code null} for 
the target of the last effective step.
+      * @param  operations  the sequence of operations. Should contain at 
least two operations.
+      * @return the concatenated operation created from the given arguments.
+      * @throws FactoryException if the object creation failed.
+      */
+     private CoordinateOperation createConcatenatedOperation(
+             final CoordinateReferenceSystem sourceCRS,
+             final CoordinateReferenceSystem targetCRS,
+             final CoordinateOperation... operations) throws FactoryException
+     {
+         final var properties = new HashMap<String, Object>(4);
+         properties.put(IdentifiedObject.NAME_KEY, new CRSPair(sourceCRS, 
targetCRS).toString());
+         final var merge  = new Consumer<CoordinateOperation>() {
+             @Override public void accept(final CoordinateOperation operation) 
{
+                 final OperationMethod method = 
CoordinateOperations.getMethod(operation);
+                 if (method instanceof OperationMethodExt) {
+                     final var provider = (OperationMethodExt) method;
+                     provider.completeOperationMetadata(context, sourceCRS, 
targetCRS, properties);
+                 }
+                 if (operation instanceof ConcatenatedOperation) {
+                     ((ConcatenatedOperation) 
operation).getOperations().stream().forEach(this);
+                 }
+             }
+         };
+         try {
+             for (CoordinateOperation step : operations) merge.accept(step);
 -            return factory.createConcatenatedOperation(properties, sourceCRS, 
targetCRS, operations);
++            return factorySIS.createConcatenatedOperation(properties, 
sourceCRS, targetCRS, operations);
+         } catch (BackingStoreException e) {
+             throw e.unwrapOrRethrow(FactoryException.class);
+         }
      }
  
      /**
diff --cc 
endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
index 646e176680,348fa06f0b..17f07b7b78
--- 
a/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
+++ 
b/endorsed/src/org.apache.sis.storage.earthobservation/main/org/apache/sis/storage/landsat/MetadataReader.java
@@@ -64,11 -64,10 +64,11 @@@ import org.apache.sis.referencing.inter
  import org.apache.sis.referencing.internal.shared.ReferencingFactoryContainer;
  import org.apache.sis.referencing.operation.provider.PolarStereographicB;
  import org.apache.sis.referencing.operation.provider.TransverseMercator;
- import org.apache.sis.storage.base.MetadataBuilder;
+ import org.apache.sis.storage.metadata.MetadataBuilder;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.referencing.operation.MathTransform;
 +// Specific to the main branch:
 +import org.apache.sis.referencing.internal.shared.CoordinateOperations;
 +import org.apache.sis.referencing.operation.transform.MathTransformBuilder;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SchemaModifier.java
index a0010991fa,05cd03b6dd..32ae640975
--- 
a/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SchemaModifier.java
+++ 
b/endorsed/src/org.apache.sis.storage.sql/main/org/apache/sis/storage/sql/feature/SchemaModifier.java
@@@ -17,12 -17,12 +17,12 @@@
  package org.apache.sis.storage.sql.feature;
  
  import org.apache.sis.feature.builder.FeatureTypeBuilder;
+ import org.apache.sis.storage.OptionKey;
  import org.apache.sis.storage.DataStoreException;
  import org.apache.sis.io.stream.InternalOptionKey;
- import org.apache.sis.setup.OptionKey;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.feature.FeatureType;
 +// Specific to the main branch:
 +import org.apache.sis.feature.DefaultFeatureType;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.storage.xml/main/org/apache/sis/storage/gpx/Types.java
index b5a77a06e2,3819d827c0..d6f19815c6
--- 
a/endorsed/src/org.apache.sis.storage.xml/main/org/apache/sis/storage/gpx/Types.java
+++ 
b/endorsed/src/org.apache.sis.storage.xml/main/org/apache/sis/storage/gpx/Types.java
@@@ -40,12 -40,12 +40,12 @@@ import org.apache.sis.feature.builder.P
  import org.apache.sis.feature.builder.AttributeRole;
  import org.apache.sis.feature.internal.shared.AttributeConvention;
  import org.apache.sis.geometry.wrapper.Geometries;
- import org.apache.sis.storage.base.MetadataBuilder;
+ import org.apache.sis.storage.metadata.MetadataBuilder;
  import org.apache.sis.util.iso.DefaultNameFactory;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.feature.FeatureType;
 -import org.opengis.feature.Operation;
 +// Specific to the main branch:
 +import org.apache.sis.feature.AbstractOperation;
 +import org.apache.sis.feature.DefaultFeatureType;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
index 76ed7914ed,2fbc724929..b6b4afdabb
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/AggregatedFeatureSet.java
@@@ -30,10 -30,10 +30,10 @@@ import org.apache.sis.storage.Resource
  import org.apache.sis.storage.FeatureSet;
  import org.apache.sis.storage.DataStoreException;
  import org.apache.sis.storage.AbstractFeatureSet;
- import org.apache.sis.storage.base.MetadataBuilder;
+ import org.apache.sis.storage.metadata.MetadataBuilder;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.feature.FeatureType;
 +// Specific to the main branch:
 +import org.apache.sis.feature.DefaultFeatureType;
  
  
  /**
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
index 7765fdbcdc,a773d56db7..ce216b3c6f
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/Store.java
@@@ -72,12 -72,13 +72,11 @@@ import org.apache.sis.geometry.Immutabl
  import org.apache.sis.geometry.wrapper.Geometries;
  import org.apache.sis.geometry.wrapper.GeometryType;
  import org.apache.sis.metadata.iso.DefaultMetadata;
- import org.apache.sis.setup.OptionKey;
  import org.apache.sis.measure.Units;
  
 -// Specific to the geoapi-3.1 and geoapi-4.0 branches:
 -import org.opengis.feature.Feature;
 -import org.opengis.feature.FeatureType;
 -import org.opengis.feature.PropertyType;
 -import org.opengis.feature.AttributeType;
 +// Specific to the main branch:
 +import org.apache.sis.feature.AbstractFeature;
 +import org.apache.sis.feature.AbstractIdentifiedType;
  
  
  /**
@@@ -225,9 -226,9 +224,9 @@@ final class Store extends URIDataStore 
          final Reader r = connector.commit(Reader.class, StoreProvider.NAME);
          source     = (r instanceof BufferedReader) ? (BufferedReader) r : new 
LineNumberReader(r);
          geometries = 
Geometries.factory(connector.getOption(OptionKey.GEOMETRY_LIBRARY));
-         dissociate = 
connector.getOption(DataOptionKey.FOLIATION_REPRESENTATION) == 
FoliationRepresentation.FRAGMENTED;
+         dissociate = connector.getOption(OptionKey.FOLIATION_REPRESENTATION) 
== FoliationRepresentation.FRAGMENTED;
          @SuppressWarnings("LocalVariableHidesMemberVariable") GeneralEnvelope 
envelope    = null;
 -        @SuppressWarnings("LocalVariableHidesMemberVariable") FeatureType     
featureType = null;
 +        @SuppressWarnings("LocalVariableHidesMemberVariable") 
DefaultFeatureType featureType = null;
          @SuppressWarnings("LocalVariableHidesMemberVariable") Foliation       
foliation   = null;
          try {
              final var elements = new ArrayList<String>();
diff --cc 
endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/StoreProvider.java
index 64708c0c53,bd40e74acf..a587630dc7
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/StoreProvider.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/folder/StoreProvider.java
@@@ -48,11 -48,8 +48,11 @@@ import org.apache.sis.storage.base.URID
  import org.apache.sis.storage.base.Capability;
  import org.apache.sis.storage.base.StoreMetadata;
  import org.apache.sis.storage.base.StoreUtilities;
- import org.apache.sis.setup.OptionKey;
+ import org.apache.sis.util.logging.Logging;
  
 +// Specific to the main branch:
 +import org.apache.sis.parameter.DefaultParameterDescriptor;
 +
  
  /**
   * The provider of {@link Store} instances. This provider is intentionally 
registered with lowest priority
diff --cc 
endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
index c572de29ba,50cfe95def..713e3d5e31
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/PropertyFormat.java
@@@ -121,13 -126,13 +126,13 @@@ public abstract class PropertyFormat ex
              final Locale locale = getLocale();
              text = (locale != Locale.ROOT) ? ((Currency) 
value).getDisplayName(locale) : value.toString();
          } else if (value instanceof Record) {
-             appendCollection(((Record) value).getAttributes().values(), 
recursive);
 -            appendCollection(((Record) value).getFields().values());
++            appendCollection(((Record) value).getAttributes().values());
              return;
          } else if (value instanceof Iterable<?>) {
-             appendCollection((Iterable<?>) value, recursive);
+             appendCollection((Iterable<?>) value);
              return;
          } else if (value instanceof Object[]) {
-             appendCollection(Arrays.asList((Object[]) value), recursive);
+             appendCollection(Arrays.asList((Object[]) value));
              return;
          } else if (value instanceof Map.Entry<?,?>) {
              final Map.Entry<?,?> entry = (Map.Entry<?,?>) value;
diff --cc 
incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
index 415352c976,5bd2209ac6..26da5ef39f
--- 
a/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
+++ 
b/incubator/src/org.apache.sis.storage.shapefile/main/org/apache/sis/storage/shapefile/ShapefileStore.java
@@@ -306,12 -308,8 +306,8 @@@ public final class ShapefileStore exten
          private int[] dbfPropertiesIndex;
          private ShapeHeader shpHeader;
          private DBFHeader dbfHeader;
-         /**
-          * Name of the field used as identifier, may be null.
-          */
-         private String idField;
          private CoordinateReferenceSystem crs;
 -        private FeatureType type;
 +        private DefaultFeatureType type;
  
          /**
           * @param filter optional shape filter, must be in data CRS
@@@ -336,10 -334,11 +332,11 @@@
           * @throws DataStoreException
           */
          private boolean mustGenerateId() throws DataStoreException {
-             getType();
-             if (idField != null) return false;
-             if (readProperties == null) return true;
-             return readProperties.contains(AttributeConvention.IDENTIFIER);
+             try {
+                 return getType().getProperty(AttributeConvention.IDENTIFIER) 
!= null;
 -            } catch (PropertyNotFoundException ex) {
++            } catch (IllegalArgumentException ex) {
+                 return false;
+             }
          }
  
          /**
diff --cc 
incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
index 92cebceb1b,4d355a9c6c..beac409aaf
--- 
a/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
+++ 
b/incubator/src/org.apache.sis.storage.shapefile/test/org/apache/sis/storage/shapefile/ShapefileStoreTest.java
@@@ -323,7 -328,33 +326,33 @@@ public class ShapefileStoreTest 
          }
      }
  
+     /**
+      * Test incremental id creation.
+      */
+     @Test
+     public void testGeneratedId() throws DataStoreException, IOException, 
URISyntaxException {
+         final URL url = 
ShapefileStoreTest.class.getResource("/org/apache/sis/storage/shapefile/noid.shp");
+         try (final ShapefileStore store = new 
ShapefileStore(Paths.get(url.toURI()))) {
+ 
 -            final FeatureType type = store.getType();
 -            final PropertyType generatedID = 
type.getProperty(AttributeConvention.IDENTIFIER);
 -            assertTrue(generatedID instanceof AttributeType);
++            final DefaultFeatureType type = store.getType();
++            final var generatedID = 
type.getProperty(AttributeConvention.IDENTIFIER);
++            assertTrue(generatedID instanceof DefaultAttributeType);
+             assertEquals(5, type.getProperties(true).size());
+ 
 -            try (Stream<Feature> stream = store.features(false)) {
 -                Iterator<Feature> iterator = stream.iterator();
++            try (Stream<AbstractFeature> stream = store.features(false)) {
++                Iterator<AbstractFeature> iterator = stream.iterator();
+                 assertTrue(iterator.hasNext());
 -                Feature feature1 = iterator.next();
++                AbstractFeature feature1 = iterator.next();
+                 assertEquals("noid.1", 
feature1.getPropertyValue(AttributeConvention.IDENTIFIER));
+                 assertEquals("some text", feature1.getPropertyValue("text"));
+ 
+                 assertFalse(iterator.hasNext());
+             }
+         }
+ 
+     }
+ 
 -    private static FeatureType createType() {
 +    private static DefaultFeatureType createType() {
          final FeatureTypeBuilder ftb = new FeatureTypeBuilder();
          ftb.setName("test");
          ftb.addAttribute(Integer.class).setName("id");
@@@ -335,9 -366,10 +364,10 @@@
          return ftb.build();
      }
  
 -    private static Feature createFeature1(FeatureType type) {
 -        Feature feature = type.newInstance();
 +    private static AbstractFeature createFeature1(DefaultFeatureType type) {
 +        AbstractFeature feature = type.newInstance();
          feature.setPropertyValue("geometry", GF.createPoint(new 
Coordinate(10,20)));
+         feature.setPropertyValue(AttributeConvention.IDENTIFIER, "test.1");
          feature.setPropertyValue("id", 1);
          feature.setPropertyValue("text", "some text 1");
          feature.setPropertyValue("integer", 123);
@@@ -346,9 -378,10 +376,10 @@@
          return feature;
      }
  
 -    private static Feature createFeature2(FeatureType type) {
 -        Feature feature = type.newInstance();
 +    private static AbstractFeature createFeature2(DefaultFeatureType type) {
 +        AbstractFeature feature = type.newInstance();
          feature.setPropertyValue("geometry", GF.createPoint(new 
Coordinate(30,40)));
+         feature.setPropertyValue(AttributeConvention.IDENTIFIER, "test.2");;
          feature.setPropertyValue("id", 2);
          feature.setPropertyValue("text", "some text 2");
          feature.setPropertyValue("integer", 456);
diff --cc 
optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/FeatureTable.java
index 06509fbde4,4bb0f17dc1..198b895e5d
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/FeatureTable.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/dataset/FeatureTable.java
@@@ -274,10 -274,10 +273,10 @@@ public class FeatureTable extends Table
       * Creates table columns for the current {@link #featureType}.
       */
      private void createColumns() {
 -        final Collection<? extends PropertyType> properties = 
featureType.getProperties(true);
 -        final var columns = new ArrayList<TableColumn<Feature, 
?>>(properties.size());
 +        final Collection<? extends AbstractIdentifiedType> properties = 
featureType.getProperties(true);
-         final List<TableColumn<AbstractFeature,?>> columns = new 
ArrayList<>(properties.size());
-         final List<String> multiValued = new ArrayList<>(columns.size());
++        final var columns = new ArrayList<TableColumn<AbstractFeature, 
?>>(properties.size());
+         final var multiValued = new ArrayList<String>(columns.size());
 -        for (final PropertyType pt : properties) {
 +        for (final AbstractIdentifiedType pt : properties) {
              /*
               * Get localized text to show in column header. Also remember
               * the plain property name; it will be needed for ValueGetter.
@@@ -308,7 -308,7 +307,7 @@@
               * gives the whole collection. Fetching a particular element in 
that collection will
               * be ElementCell's work.
               */
-             final TableColumn<AbstractFeature,Object> column = new 
TableColumn<>(title);
 -            final var column = new TableColumn<Feature, Object>(title);
++            final var column = new TableColumn<AbstractFeature, 
Object>(title);
              column.setCellValueFactory(new ValueGetter(name));
              column.setCellFactory(isMultiValued ? ElementCell::new : 
ValueCell::new);
              if (AttributeConvention.contains(qualifiedName)) {
@@@ -325,7 -325,7 +324,7 @@@
          } else {
              final ExpandableList list = getExpandableList();
              list.setMultivaluedColumns(multiValued);
-             final TableColumn<AbstractFeature,AbstractFeature> column = new 
TableColumn<>("▤");
 -            final var column = new TableColumn<Feature, Feature>("▤");
++            final var column = new TableColumn<AbstractFeature, 
AbstractFeature>("▤");
              column.setCellValueFactory(IdentityValueFactory.instance());
              column.setCellFactory(list);
              column.setReorderable(false);
@@@ -348,7 -348,7 +347,7 @@@
       * easy way to know the current row number. Fetching a particular element 
in that collection will be done by
       * {@link ExpandedFeature}.
       */
-     private static final class ValueGetter implements 
Callback<TableColumn.CellDataFeatures<AbstractFeature,Object>, 
ObservableValue<Object>> {
 -    private static final class ValueGetter implements 
Callback<TableColumn.CellDataFeatures<Feature, Object>, 
ObservableValue<Object>> {
++    private static final class ValueGetter implements 
Callback<TableColumn.CellDataFeatures<AbstractFeature, Object>, 
ObservableValue<Object>> {
          /**
           * The name of the feature property for which to fetch values.
           */
@@@ -382,13 -382,13 +381,13 @@@
       * A cell displaying a value in {@link FeatureTable}. This base class 
expects single values.
       * If the property values are collections, then {@link ElementCell} 
should be used instead.
       */
-     private static class ValueCell extends TableCell<AbstractFeature,Object> {
 -    private static class ValueCell extends TableCell<Feature, Object> {
++    private static class ValueCell extends TableCell<AbstractFeature, Object> 
{
          /**
           * Creates a new cell for feature property value.
           *
           * @param  column  the column where the cell will be shown.
           */
-         ValueCell(final TableColumn<AbstractFeature,Object> column) {
 -        ValueCell(final TableColumn<Feature, Object> column) {
++        ValueCell(final TableColumn<AbstractFeature, Object> column) {
              // Column not used at this time, but we need it in method 
signature.
          }
  
@@@ -430,7 -430,7 +429,7 @@@
           *
           * @param  column  the column where the cell will be shown.
           */
-         ElementCell(final TableColumn<AbstractFeature,Object> column) {
 -        ElementCell(final TableColumn<Feature, Object> column) {
++        ElementCell(final TableColumn<AbstractFeature, Object> column) {
              super(column);
          }
  


Reply via email to