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 b9ad7e86ef7f862e6655ea723335cc96247c0461 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Wed Aug 2 12:03:35 2023 +0200 Add a `GeometryType.getTypeName(Geometries)` method. The Java class associated to the `TypeName` depends on the geometry library. --- .../apache/sis/internal/feature/GeometryType.java | 85 ++++++++++++++++++++-- .../sis/internal/feature/GeometryTypeTest.java | 28 ++++++- .../org/apache/sis/util/iso/DefaultTypeName.java | 5 ++ .../java/org/apache/sis/util/iso/TypeNames.java | 6 +- .../org/apache/sis/util/iso/TypeNamesTest.java | 17 +++-- 5 files changed, 126 insertions(+), 15 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/GeometryType.java b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/GeometryType.java index 0476da682e..69db5d343e 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/GeometryType.java +++ b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/GeometryType.java @@ -17,6 +17,13 @@ package org.apache.sis.internal.feature; import java.util.Locale; +import java.util.EnumMap; +import org.opengis.util.TypeName; +import org.opengis.util.NameSpace; +import org.apache.sis.util.iso.Names; +import org.apache.sis.setup.GeometryLibrary; +import org.apache.sis.internal.util.Constants; +import org.apache.sis.util.iso.DefaultNameFactory; /** @@ -36,7 +43,7 @@ public enum GeometryType { * * @see Geometries#rootClass */ - GEOMETRY, + GEOMETRY("Geometry"), /** * Zero-dimensional geometry containing a single point. @@ -45,7 +52,7 @@ public enum GeometryType { * * @see Geometries#pointClass */ - POINT, + POINT("Point"), /** * Sequence of points connected by straight, non-self intersecting line pieces. @@ -53,7 +60,7 @@ public enum GeometryType { * * @see Geometries#polylineClass */ - LINESTRING, + LINESTRING("LineString"), /** * Geometry with a positive area (two-dimensional). @@ -61,27 +68,89 @@ public enum GeometryType { * * @see Geometries#polygonClass */ - POLYGON, + POLYGON("Polygon"), /** * Set of points. */ - MULTIPOINT, + MULTIPOINT("MultiPoint"), /** * Set of linestrings. */ - MULTILINESTRING, + MULTILINESTRING("MultiLineString"), /** * Set of polygons. */ - MULTIPOLYGON, + MULTIPOLYGON("MultiPolygon"), /** * Set of geometries of any type except other geometry collection. */ - GEOMETRYCOLLECTION; + GEOMETRYCOLLECTION("GeometryCollection"); + + /** + * Camel-case name of this geometry type. + * The upper-case variant of this name is equal to {@link #name()}. + */ + public final String name; + + /** + * The geometry types as ISO 19103 type names, created when first needed. + * For a given enumeration value, all {@code typeNames} values are identical + * except for the associated Java class, which depends on the geometry library. + * + * @see #getTypeName(Geometries) + */ + private final EnumMap<GeometryLibrary, TypeName> typeNames; + + /** + * The "OGC" namespace for geometry names. Fetched when first needed. + */ + private static volatile NameSpace namespace; + + /** + * Creates a new enumeration value. + * + * @param name camel-case name of the geometry. + */ + private GeometryType(final String name) { + this.name = name; + typeNames = new EnumMap<>(GeometryLibrary.class); + } + + /** + * {@return the name of this geometry type as an ISO 19103 object}. + * The namespace is "OGC". The Java type depends on the geometry library. + * + * @param library the geometry library that determine geometry classes. + */ + public final TypeName getTypeName(final Geometries<?> library) { + TypeName value; + synchronized (typeNames) { + value = typeNames.get(library.library); + } + if (value == null) { + NameSpace scope = namespace; + if (scope == null) { + /* + * The `Names.createTypeName(…)` method creates a `TypeName` associated to the + * `org.opengis.geometry.Geometry` type, which is not necessarily what we want. + * So we keep only the namespace. + */ + namespace = scope = Names.createTypeName(Constants.OGC, null, "Geometry").scope(); + } + value = DefaultNameFactory.provider().createTypeName(scope, name, library.getGeometryClass(this)); + synchronized (typeNames) { + final TypeName existing = typeNames.put(library.library, value); + if (existing != null) { + typeNames.put(library.library, value = existing); + } + } + } + return value; + } /** * The type of this geometry as specified in Well-Known Binary (WKB) specification. diff --git a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometryTypeTest.java b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometryTypeTest.java index bb339e60f3..3ca324c7ce 100644 --- a/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometryTypeTest.java +++ b/core/sis-feature/src/test/java/org/apache/sis/internal/feature/GeometryTypeTest.java @@ -16,6 +16,8 @@ */ package org.apache.sis.internal.feature; +import java.util.Locale; +import org.opengis.util.TypeName; import org.apache.sis.test.TestCase; import org.junit.Test; @@ -26,7 +28,7 @@ import static org.junit.Assert.*; * Tests {@link GeometryType}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.4 * @since 1.1 */ public final class GeometryTypeTest extends TestCase { @@ -36,6 +38,30 @@ public final class GeometryTypeTest extends TestCase { public GeometryTypeTest() { } + /** + * Verifies {@link GeometryType#name} values. + */ + @Test + public void verifyCamelCaseName() { + for (final GeometryType type : GeometryType.values()) { + assertEquals(type.name(), type.name.toUpperCase(Locale.US)); + } + } + + /** + * Tests {@link GeometryType#getTypeName(Geometries)}. + */ + @Test + public void testTypeName() { + TypeName name = GeometryType.LINESTRING.getTypeName(org.apache.sis.internal.feature.jts.Factory.INSTANCE); + assertEquals("OGC:LineString", name.toFullyQualifiedName().toString()); + assertEquals(org.locationtech.jts.geom.LineString.class, name.toJavaType().get()); + + name = GeometryType.LINESTRING.getTypeName(org.apache.sis.internal.feature.esri.Factory.INSTANCE); + assertEquals("OGC:LineString", name.toFullyQualifiedName().toString()); + assertEquals(com.esri.core.geometry.Polyline.class, name.toJavaType().get()); + } + /** * Tests {@link GeometryType#forBinaryType(int)} and verifies {@link GeometryType#binaryType()} values. */ diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java index adc6beb0d6..f906117c2d 100644 --- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java +++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/DefaultTypeName.java @@ -108,6 +108,11 @@ import org.apache.sis.util.UnknownNameException; * <td class="sep"></td> * <td></td> * </tr><tr> + * <td>{@link org.opengis.geometry.Geometry}</td> + * <td>{@code OGC:Geometry}</td> + * <td class="sep"></td> + * <td></td> + * </tr><tr> * <td>Unknown Java class</td> * <td>{@code class:}<the class name></td> * <td class="sep"></td> diff --git a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/TypeNames.java b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/TypeNames.java index 46253fa9a2..308c555238 100644 --- a/core/sis-metadata/src/main/java/org/apache/sis/util/iso/TypeNames.java +++ b/core/sis-metadata/src/main/java/org/apache/sis/util/iso/TypeNames.java @@ -28,6 +28,7 @@ import org.opengis.util.TypeName; import org.opengis.util.NameSpace; import org.opengis.util.NameFactory; import org.opengis.util.InternationalString; +import org.opengis.geometry.Geometry; import org.apache.sis.internal.util.Constants; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.Numbers; @@ -37,7 +38,7 @@ import org.apache.sis.util.Numbers; * Implements the mapping between {@link Class} and {@link TypeName} documented in {@link DefaultTypeName}. * * @author Martin Desruisseaux (Geomatys) - * @version 1.3 + * @version 1.4 * @since 0.5 */ final class TypeNames { @@ -57,9 +58,12 @@ final class TypeNames { m.put("URI", URI.class); m.put("DateTime", Date.class); m.put("PT_Locale", Locale.class); + m.put("Geometry", Geometry.class); // Was GM_Object in ISO 19107:2003. m.put("Decimal", BigDecimal.class); m.put("Boolean", Boolean.class); // Used as a sentinel value for stopping iteration. + // MD_Metadata is not specified because it is handled through UML annotations. + // Entries below this point are handled in a special way. m.put("FreeText", InternationalString.class); m.put("CharacterString", String.class); diff --git a/core/sis-metadata/src/test/java/org/apache/sis/util/iso/TypeNamesTest.java b/core/sis-metadata/src/test/java/org/apache/sis/util/iso/TypeNamesTest.java index 7d95bb94cc..7686934a3d 100644 --- a/core/sis-metadata/src/test/java/org/apache/sis/util/iso/TypeNamesTest.java +++ b/core/sis-metadata/src/test/java/org/apache/sis/util/iso/TypeNamesTest.java @@ -23,6 +23,7 @@ import org.opengis.util.TypeName; import org.opengis.util.NameFactory; import org.opengis.util.InternationalString; import org.opengis.metadata.Metadata; +import org.opengis.geometry.Geometry; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.apache.sis.test.DependsOn; import org.apache.sis.test.TestCase; @@ -52,8 +53,10 @@ public final class TypeNamesTest extends TestCase { } /** - * Verifies that the call to {@link TypeNames#toTypeName(NameFactory, Class)} returns a {@code TypeName} having the - * given name and namespace, then tests the reverse operation with {@link TypeNames#toClass(String, String)}. + * Tests fetching a name from a Java class and a fetching a Java class from a name. + * This method verifies that the call to {@link TypeNames#toTypeName(NameFactory, Class)} + * returns a {@code TypeName} having the given name and namespace, + * then tests the reverse operation with {@link TypeNames#toClass(String, String)}. */ private static void verifyLookup(final String namespace, final String name, final Class<?> valueClass) throws ClassNotFoundException @@ -77,7 +80,8 @@ public final class TypeNamesTest extends TestCase { /** * Tests the mapping of basic types like strings, URI, dates and numbers. * - * @throws ClassNotFoundException should not happen since we do invoke {@link Class#forName(String)} in this test. + * @throws ClassNotFoundException should not happen since we do not + * invoke {@link Class#forName(String)} in this test. */ @Test public void testBasicTypes() throws ClassNotFoundException { @@ -106,10 +110,12 @@ public final class TypeNamesTest extends TestCase { /** * Tests the mapping of more complex object that are not basic types. * - * @throws ClassNotFoundException should not happen since we do invoke {@link Class#forName(String)} in this test. + * @throws ClassNotFoundException should not happen since we do not + * invoke {@link Class#forName(String)} in this test. */ @Test public void testMetadataClasses() throws ClassNotFoundException { + verifyLookup(OGC, "Geometry", Geometry.class); verifyLookup(OGC, "MD_Metadata", Metadata.class); verifyLookup(OGC, "SC_CRS", CoordinateReferenceSystem.class); } @@ -127,7 +133,8 @@ public final class TypeNamesTest extends TestCase { /** * Checks for the sentinel values in case of invalid names. * - * @throws ClassNotFoundException should not happen since we do invoke {@link Class#forName(String)} in this test. + * @throws ClassNotFoundException should not happen since we do not + * invoke {@link Class#forName(String)} in this test. */ @Test public void testInvalidNames() throws ClassNotFoundException {