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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
new dfb19c1 Allow `getAuthorityCodes(Class)` to filter by WKT keywords.
Build the code list under write lock. Cache results.
dfb19c1 is described below
commit dfb19c152eabfe09b190274a8becfe93f7db0705
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Wed Nov 11 11:28:23 2020 +0100
Allow `getAuthorityCodes(Class)` to filter by WKT keywords.
Build the code list under write lock. Cache results.
---
.../internal/referencing/ReferencingUtilities.java | 30 +++++---
.../sis/internal/referencing/WKTKeywords.java | 84 +++++++++++++++++++++-
.../java/org/apache/sis/io/wkt/WKTDictionary.java | 82 ++++++++++++++++++---
.../apache/sis/referencing/GeodeticCalculator.java | 6 +-
.../factory/GeodeticAuthorityFactory.java | 2 +-
.../apache/sis/referencing/operation/CRSPair.java | 13 ++--
.../operation/CoordinateOperationRegistry.java | 17 ++---
.../sis/internal/referencing/WKTKeywordsTest.java | 41 ++++++++++-
.../org/apache/sis/io/wkt/WKTDictionaryTest.java | 14 +++-
9 files changed, 240 insertions(+), 49 deletions(-)
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
index 35e6745..03c02a2 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
@@ -37,6 +37,7 @@ import org.opengis.referencing.datum.GeodeticDatum;
import org.opengis.referencing.datum.VerticalDatum;
import org.opengis.referencing.datum.VerticalDatumType;
import org.apache.sis.util.Static;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.Utilities;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.resources.Errors;
@@ -61,7 +62,7 @@ import static java.util.Collections.singletonMap;
* <p><strong>Do not rely on this API!</strong> It may change in incompatible
way in any future release.</p>
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.1
* @since 0.5
* @module
*/
@@ -147,20 +148,33 @@ public final class ReferencingUtilities extends Static {
* Returns the GeoAPI interface implemented by the given object, or the
implementation class
* if the interface is unknown.
*
- * @param object the object for which to get the GeoAPI interface, or
{@code null}.
+ * @param <T> compile-time value of {@code baseType}.
+ * @param baseType parent interface of the desired type.
+ * @param object the object for which to get the GeoAPI interface, or
{@code null}.
* @return GeoAPI interface or implementation class of the given object,
or {@code null} if the given object is null.
*/
- public static Class<?> getInterface(final IdentifiedObject object) {
- if (object == null) {
- return null;
- } else if (object instanceof AbstractIdentifiedObject) {
- return ((AbstractIdentifiedObject) object).getInterface();
+ public static <T extends IdentifiedObject> Class<? extends T>
getInterface(final Class<T> baseType, final T object) {
+ if (object instanceof AbstractIdentifiedObject) {
+ return ((AbstractIdentifiedObject)
object).getInterface().asSubclass(baseType);
} else {
- return object.getClass();
+ return getInterface(baseType, Classes.getClass(object));
}
}
/**
+ * Returns the GeoAPI interface implemented by the given class, or the
class itself if the interface is unknown.
+ *
+ * @param <T> compile-time value of {@code baseType}.
+ * @param baseType parent interface of the desired type.
+ * @param type type of object for which to get the GeoAPI interface,
or {@code null}.
+ * @return GeoAPI interface or implementation class, or {@code null} if
the given type is null.
+ */
+ public static <T extends IdentifiedObject> Class<? extends T>
getInterface(final Class<T> baseType, final Class<? extends T> type) {
+ final Class<? extends T>[] types = Classes.getLeafInterfaces(type,
baseType);
+ return (types.length != 0) ? types[0] : type;
+ }
+
+ /**
* Copies all {@link SingleCRS} components from the given source to the
given collection.
* For each {@link CompoundCRS} element found in the iteration, this
method replaces the
* {@code CompoundCRS} by its {@linkplain CompoundCRS#getComponents()
components}, which
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTKeywords.java
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTKeywords.java
index 241a6ce..aab1794 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTKeywords.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/WKTKeywords.java
@@ -16,7 +16,10 @@
*/
package org.apache.sis.internal.referencing;
+import java.util.Map;
+import java.util.HashMap;
import org.apache.sis.util.Static;
+import org.apache.sis.util.ArraysExt;
/**
@@ -30,12 +33,12 @@ import org.apache.sis.util.Static;
* without affecting GML for instance.</p>
*
* <div class="note"><b>Note:</b>
- * this class should not contain any method or non-final constant, in order to
avoid class loading.
- * This class is intended to be used only at compile-time and could be omitted
from the JAR file.</div>
+ * all constants in this class are static and final. The Java compiler should
replace those constants
+ * by their literal values at compile time, which avoid the loading of this
class at run-time.</div>
*
* @author Martin Desruisseaux (Geomatys)
* @author Johann Sorel (Geomatys)
- * @version 1.0
+ * @version 1.1
*
* @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html">WKT
2 specification</a>
* @see <a
href="http://www.geoapi.org/3.0/javadoc/org/opengis/referencing/doc-files/WKT.html">Legacy
WKT 1</a>
@@ -220,4 +223,79 @@ public final class WKTKeywords extends Static {
*/
public static final String
Point = "Point";
+
+ /**
+ * Mapping between types of object and WKT keywords. Each GeoAPI
interfaces is associated to one
+ * or many WKT keywords: new keywords defined by version 2 (sometime with
synonymous) and legacy
+ * keywords defined by WKT 1.
+ *
+ * @see #forType(Class)
+ */
+ private static final Map<Class<?>,String[]> TYPES = new HashMap<>(30);
+ static {
+ /*
+ * `SingleCRS` subtypes. The `GeodeticCRS` is a common parent of
+ * `GeographicCRS` and `GeocentricCRS`, repeated for both of them.
+ */
+ addType(org.opengis.referencing.crs.GeocentricCRS.class, GeodeticCRS,
GeodCRS, GeocCS);
+ addType(org.opengis.referencing.crs.GeographicCRS.class, GeodeticCRS,
GeodCRS, GeogCS);
+ String[][] subtypes;
+ subtypes = new String[][] {
+ addType(org.opengis.referencing.crs.GeodeticCRS.class,
GeodeticCRS, GeodCRS, GeocCS, GeogCS),
+ addType(org.opengis.referencing.crs.ProjectedCRS.class,
ProjectedCRS, ProjCRS, ProjCS),
+ addType(org.opengis.referencing.crs.VerticalCRS.class,
VerticalCRS, VertCRS, Vert_CS),
+ addType(org.opengis.referencing.crs.EngineeringCRS.class,
EngineeringCRS, EngCRS, Local_CS),
+ addType(org.opengis.referencing.crs.DerivedCRS.class, /* TODO:
check ISO. */ Fitted_CS),
+ addType(org.opengis.referencing.crs.TemporalCRS.class, TimeCRS)
+ };
+ /*
+ * `CoordinateReferenceSystem` subtypes: all `SingleCRS` + the
`CompoundCRS`.
+ */
+ subtypes = new String[][] {
+ addType(org.opengis.referencing.crs.SingleCRS.class,
ArraysExt.concatenate(subtypes)),
+ addType(org.opengis.referencing.crs.CompoundCRS.class,
CompoundCRS, Compd_CS),
+ };
+ addType(org.opengis.referencing.crs.CoordinateReferenceSystem.class,
ArraysExt.concatenate(subtypes));
+ /*
+ * `Datum` subtypes.
+ */
+ subtypes = new String[][] {
+ addType(org.opengis.referencing.datum.GeodeticDatum.class,
GeodeticDatum, Datum),
+ addType(org.opengis.referencing.datum.TemporalDatum.class,
TimeDatum, TDatum),
+ addType(org.opengis.referencing.datum.VerticalDatum.class,
VerticalDatum, VDatum, Vert_Datum),
+ addType(org.opengis.referencing.datum.EngineeringDatum.class,
EngineeringDatum, EDatum, Local_Datum)
+ };
+ addType(org.opengis.referencing.datum.Datum.class,
ArraysExt.concatenate(subtypes));
+ /*
+ * Other types having no common parent (ignoring `IdentifiedObject`).
+ */
+ addType(org.opengis.referencing.datum.Ellipsoid.class,
Ellipsoid, Spheroid);
+ addType(org.opengis.referencing.datum.PrimeMeridian.class,
PrimeMeridian, PrimeM);
+ addType(org.opengis.referencing.cs.CoordinateSystemAxis.class,
Axis);
+ addType(org.apache.sis.referencing.datum.BursaWolfParameters.class,
ToWGS84);
+ addType(org.opengis.referencing.operation.MathTransform.class,
Param_MT, Concat_MT, Inverse_MT, PassThrough_MT);
+ addType(org.opengis.geometry.DirectPosition.class,
Point);
+ }
+
+ /**
+ * Adds WKT keywords for the specified type.
+ */
+ private static String[] addType(final Class<?> type, final String...
keywords) {
+ if (TYPES.put(type, keywords) != null) {
+ throw new AssertionError(type);
+ }
+ return keywords;
+ }
+
+ /**
+ * Returns the WKT keywords for an object of the specified type.
+ * This method returns a direct reference to internal array;
+ * <strong>do not modify</strong>.
+ *
+ * @param type the GeoAPI interface of the element.
+ * @return the WKT keywords, or {@code null} if none or unknown.
+ */
+ public static String[] forType(final Class<?> type) {
+ return TYPES.get(type);
+ }
}
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
index 0f69a1f..62a0840 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/io/wkt/WKTDictionary.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.stream.Stream;
+import java.util.function.Predicate;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.io.LineNumberReader;
@@ -38,6 +39,7 @@ import org.opengis.referencing.IdentifiedObject;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
import org.apache.sis.referencing.factory.FactoryDataException;
+import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.referencing.Resources;
import org.apache.sis.internal.referencing.WKTKeywords;
import org.apache.sis.internal.util.CollectionsExt;
@@ -47,9 +49,9 @@ import org.apache.sis.internal.jdk9.JDK9;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.util.CharSequences;
import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.Exceptions;
import org.apache.sis.util.resources.Errors;
-import org.apache.sis.util.collection.Containers;
import org.apache.sis.util.collection.FrequencySortedSet;
@@ -115,6 +117,12 @@ public class WKTDictionary extends
GeodeticAuthorityFactory {
private final Set<String> codespaces;
/**
+ * Cache of authority codes computed by {@link #getAuthorityCodes(Class)}.
+ * This cache can be cleared at any time; values are recomputed when
needed.
+ */
+ private final Map<Class<?>, Set<String>> codeCaches;
+
+ /**
* The parser to use for creating geodetic objects from WKT definitions.
* All uses of this parser shall be synchronized by the <code>{@linkplain
#lock}.writeLock()</code>.
*/
@@ -295,13 +303,16 @@ public class WKTDictionary extends
GeodeticAuthorityFactory {
*
* @param choices end of a linked list of {@code Disambiguation}s.
* @param code authority code (code space and version may vary).
+ * @param filter filter to apply of elements to add in the set.
* @param addTo where to add the {@code codespace:version:code}
tuples.
*
* @see WKTDictionary#getAuthorityCodes(Class)
*/
- static void list(Disambiguation choices, final String code, final
Set<String> addTo) {
+ static void list(Disambiguation choices, final String code, final
Predicate<Object> filter, final Set<String> addTo) {
do {
- addTo.add(choices.identifier(code));
+ if (filter.test(choices.value)) {
+ addTo.add(choices.identifier(code));
+ }
choices = choices.previous;
} while (choices != null);
}
@@ -349,6 +360,7 @@ public class WKTDictionary extends GeodeticAuthorityFactory
{
* methods are not invoked.
*/
definitions = new HashMap<>();
+ codeCaches = new HashMap<>();
codespaces = new FrequencySortedSet<>(true);
parser = new WKTFormat(null, null);
lock = new ReentrantReadWriteLock();
@@ -361,6 +373,7 @@ public class WKTDictionary extends GeodeticAuthorityFactory
{
* in all WKT strings. This method should be invoked after new WKTs have
been added.
*/
private void updateAuthority() {
+ codeCaches.clear();
if (authorities != null) {
String name = CollectionsExt.first(authorities); // Most
frequently declared authority.
if (name == null) {
@@ -842,6 +855,7 @@ public class WKTDictionary extends GeodeticAuthorityFactory
{
} else {
definitions.put(localCode, value);
}
+ codeCaches.clear();
if (cause != null) {
throw new FactoryException(resources().getString(
Resources.Keys.CanNotInstantiateGeodeticObject_1, code), cause);
@@ -869,14 +883,60 @@ public class WKTDictionary extends
GeodeticAuthorityFactory {
*/
@Override
public Set<String> getAuthorityCodes(Class<? extends IdentifiedObject>
type) throws FactoryException {
- final Set<String> codes = new
HashSet<>(Containers.hashMapCapacity(definitions.size()));
- for (final Map.Entry<String,Object> entry : definitions.entrySet()) {
- final String code = entry.getKey();
- final Object value = entry.getValue();
- if (value instanceof Disambiguation) {
- Disambiguation.list((Disambiguation) value, code, codes);
- } else {
- codes.add(code);
+ ArgumentChecks.ensureNonNull("type", type);
+ if (!type.isInterface()) {
+ type = ReferencingUtilities.getInterface(IdentifiedObject.class,
type);
+ }
+ Set<String> codes;
+ lock.readLock().lock();
+ try {
+ codes = codeCaches.get(type);
+ } finally {
+ lock.readLock().unlock();
+ }
+ if (codes == null) {
+ final String[] keywords = WKTKeywords.forType(type);
+ final Class<? extends IdentifiedObject> baseType = type;
// Because lambdas require final.
+ final Predicate<Object> filter = (element) -> {
+ if (element instanceof Element) {
+ return (keywords == null) ||
ArraysExt.containsIgnoreCase(keywords, ((Element) element).keyword);
+ } else {
+ return baseType.isInstance(element);
+ }
+ };
+ lock.writeLock().lock();
+ try {
+ codes = codeCaches.get(type); // In
case it has been computed concurrently.
+ if (codes == null) {
+ codes = new HashSet<>();
+ for (final Map.Entry<String,Object> entry :
definitions.entrySet()) {
+ final String code = entry.getKey();
+ final Object value = entry.getValue();
+ if (value instanceof Disambiguation) {
+ Disambiguation.list((Disambiguation) value, code,
filter, codes);
+ } else if (filter.test(value)) {
+ codes.add(code);
+ }
+ }
+ /*
+ * Verify if an existing collection (assigned to another
type) provides the same values.
+ * If we find one, we will share the same instances.
+ */
+ boolean share = false;
+ for (final Set<String> other : codeCaches.values()) {
+ if (codes.equals(other)) {
+ codes = other;
+ share = true;
+ break;
+ }
+ }
+ if (!share) {
+ codes = CollectionsExt.unmodifiableOrCopy(codes);
+ }
+ codeCaches.put(type, codes);
+ }
+ } finally {
+ lock.writeLock().unlock();
}
}
return codes;
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
index 4226f76..6161778 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/GeodeticCalculator.java
@@ -277,7 +277,8 @@ public class GeodeticCalculator {
GeodeticCalculator(final CoordinateReferenceSystem crs, final Ellipsoid
ellipsoid) {
final GeographicCRS geographic =
ReferencingUtilities.toNormalizedGeographicCRS(crs, true, true);
if (geographic == null) {
- throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalCRSType_1,
ReferencingUtilities.getInterface(crs)));
+ throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalCRSType_1,
+
ReferencingUtilities.getInterface(CoordinateReferenceSystem.class, crs)));
}
this.ellipsoid = ellipsoid;
semiMajorAxis = ellipsoid.getSemiMajorAxis();
@@ -301,7 +302,8 @@ public class GeodeticCalculator {
ArgumentChecks.ensureNonNull("crs", crs);
final Ellipsoid ellipsoid = ReferencingUtilities.getEllipsoid(crs);
if (ellipsoid == null) {
- throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalCRSType_1,
ReferencingUtilities.getInterface(crs)));
+ throw new
IllegalArgumentException(Errors.format(Errors.Keys.IllegalCRSType_1,
+
ReferencingUtilities.getInterface(CoordinateReferenceSystem.class, crs)));
}
if (ellipsoid.isSphere()) {
return new GeodeticCalculator(crs, ellipsoid);
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
index 48726ab..a99f832 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticAuthorityFactory.java
@@ -1308,7 +1308,7 @@ public abstract class GeodeticAuthorityFactory extends
AbstractFactory implement
* Get the actual type of the object. Returns the GeoAPI type if
possible,
* or fallback on the implementation class otherwise.
*/
- final Class<?> actual = ReferencingUtilities.getInterface(object);
+ final Class<?> actual =
ReferencingUtilities.getInterface(IdentifiedObject.class, object);
/*
* Get the authority from the object if possible, in order to avoid a
call
* to the potentially costly (for EPSGDataAccess) getAuthority()
method.
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
index 95f9cbc..e0cd5b7 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CRSPair.java
@@ -21,7 +21,7 @@ import org.opengis.referencing.cs.EllipsoidalCS;
import org.opengis.referencing.cs.CoordinateSystem;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.IdentifiedObject;
-import org.apache.sis.referencing.AbstractIdentifiedObject;
+import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.referencing.IdentifiedObjects;
import org.apache.sis.internal.util.Strings;
import org.apache.sis.util.CharSequences;
@@ -33,7 +33,7 @@ import org.apache.sis.util.Classes;
* Used as key in hash map.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.1
* @since 0.7
* @module
*/
@@ -88,13 +88,8 @@ final class CRSPair {
if (object == null) {
return null;
}
- Class<? extends IdentifiedObject> type;
- if (object instanceof AbstractIdentifiedObject) {
- type = ((AbstractIdentifiedObject) object).getInterface();
- } else {
- type = Classes.getLeafInterfaces(object.getClass(),
IdentifiedObject.class)[0];
- }
- String suffix, label = Classes.getShortName(type);
+ String suffix;
+ String label =
Classes.getShortName(ReferencingUtilities.getInterface(IdentifiedObject.class,
object));
if (label.endsWith((suffix = "CRS")) || label.endsWith(suffix = "CS"))
{
Object cs = object;
if (object instanceof CoordinateReferenceSystem) {
diff --git
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
index 0152e58..dcbcb97 100644
---
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
+++
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
@@ -49,7 +49,6 @@ import org.apache.sis.referencing.CRS;
import org.apache.sis.referencing.CommonCRS;
import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.referencing.IdentifiedObjects;
-import org.apache.sis.referencing.AbstractIdentifiedObject;
import org.apache.sis.referencing.cs.CoordinateSystems;
import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.referencing.operation.transform.MathTransforms;
@@ -73,7 +72,6 @@ import org.apache.sis.internal.system.Loggers;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.Utilities;
-import org.apache.sis.util.Classes;
import org.apache.sis.util.Deprecable;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.util.collection.Containers;
@@ -513,7 +511,7 @@ class CoordinateOperationRegistry {
final boolean inverse =
Containers.isNullOrEmpty(authoritatives);
if (inverse) {
/*
- * No operation from 'source' to 'target'
available. But maybe there is an inverse operation.
+ * No operation from `source` to `target`
available. But maybe there is an inverse operation.
* This is typically the case when the user wants
to convert from a projected to a geographic CRS.
* The EPSG database usually contains
transformation paths for geographic to projected CRS only.
*/
@@ -869,20 +867,15 @@ class CoordinateOperationRegistry {
* Determine whether the operation to create is a Conversion or a
Transformation
* (could also be a Conversion subtype like Projection, but this is
less important).
* We want the GeoAPI interface, not the implementation class.
- * The most reliable way is to ask to the
'AbstractOperation.getInterface()' method,
+ * The most reliable way is to ask to the
`AbstractOperation.getInterface()` method,
* but this is SIS-specific. The fallback uses reflection.
*/
- final Class<? extends IdentifiedObject> type;
- if (operation instanceof AbstractIdentifiedObject) {
- type = ((AbstractIdentifiedObject) operation).getInterface();
- } else {
- type = Classes.getLeafInterfaces(operation.getClass(),
CoordinateOperation.class)[0];
- }
- properties.put(CoordinateOperations.OPERATION_TYPE_KEY, type);
+ properties.put(CoordinateOperations.OPERATION_TYPE_KEY,
+ ReferencingUtilities.getInterface(CoordinateOperation.class,
operation));
/*
* Reuse the same operation method, but we may need to change its
number of dimension.
* The capability to resize an OperationMethod is specific to Apache
SIS, so we must
- * be prepared to see the 'redimension' call fails. In such case, we
will try to get
+ * be prepared to see the `redimension` call fails. In such case, we
will try to get
* the SIS implementation of the operation method and try again.
*/
if (operation instanceof SingleOperation) {
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTKeywordsTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTKeywordsTest.java
index e6f296a..a54d91f 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTKeywordsTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/WKTKeywordsTest.java
@@ -16,8 +16,12 @@
*/
package org.apache.sis.internal.referencing;
+import java.util.Set;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
+import org.opengis.referencing.crs.*;
+import org.opengis.referencing.datum.*;
+import org.apache.sis.internal.jdk9.JDK9;
import org.apache.sis.test.TestCase;
import org.junit.Test;
@@ -28,7 +32,7 @@ import static org.junit.Assert.*;
* Tests the {@link WKTKeywords} class.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.1
* @since 0.6
* @module
*/
@@ -48,10 +52,45 @@ public final strictfp class WKTKeywordsTest extends
TestCase {
for (final Field field : WKTKeywords.class.getDeclaredFields()) {
final String name = field.getName();
final int modifiers = field.getModifiers();
+ if (name.equals("TYPES")) {
+ assertFalse(name, Modifier.isPublic(modifiers));
+ continue;
+ }
assertTrue(name, Modifier.isPublic(modifiers));
assertTrue(name, Modifier.isStatic(modifiers));
assertTrue(name, Modifier.isFinal (modifiers));
assertEquals("As a policy of WKTKeywords, constants value should
be equal to field name.", name, field.get(null));
}
}
+
+ /**
+ * Verifies that {@link SingleCRS}, {@link CoordinateReferenceSystem} and
{@link Datum} base types
+ * contain all WKT keywords associated to subtypes.
+ */
+ @Test
+ public void verifyTypeHierarchy() {
+ verifyTypeHierarchy(SingleCRS.class, GeocentricCRS.class,
GeographicCRS.class, ProjectedCRS.class,
+ VerticalCRS.class, TemporalCRS.class,
EngineeringCRS.class);
+ verifyTypeHierarchy(CoordinateReferenceSystem.class, SingleCRS.class,
CompoundCRS.class,
+ GeocentricCRS.class, GeographicCRS.class,
ProjectedCRS.class,
+ VerticalCRS.class, TemporalCRS.class,
EngineeringCRS.class);
+ verifyTypeHierarchy(Datum.class, GeodeticDatum.class,
VerticalDatum.class, TemporalDatum.class,
+ EngineeringDatum.class);
+ }
+
+ /**
+ * Verify that the specified {@code base} type contain all WKT keywords
associated to specified subtypes.
+ */
+ @SafeVarargs
+ private static <T> void verifyTypeHierarchy(final Class<T> base, final
Class<? extends T>... subtypes) {
+ final Set<String> all = JDK9.setOf(WKTKeywords.forType(base));
+ assertNotNull(base.getName(), all);
+ for (final Class<? extends T> subtype : subtypes) {
+ final Set<String> specialized =
JDK9.setOf(WKTKeywords.forType(subtype));
+ final String name = subtype.getName();
+ assertNotNull(name, specialized);
+ assertTrue(name, all.size() > specialized.size());
+ assertTrue(name, all.containsAll(specialized));
+ }
+ }
}
diff --git
a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTDictionaryTest.java
b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTDictionaryTest.java
index 1e32651..5ae1678 100644
---
a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTDictionaryTest.java
+++
b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTDictionaryTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.sis.io.wkt;
+import java.util.Set;
import java.util.Arrays;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@@ -24,7 +25,9 @@ import org.opengis.util.FactoryException;
import org.opengis.referencing.crs.SingleCRS;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.crs.GeographicCRS;
+import org.opengis.referencing.crs.GeodeticCRS;
import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.IdentifiedObject;
import org.apache.sis.metadata.iso.citation.Citations;
import org.apache.sis.test.DependsOn;
import org.apache.sis.test.TestCase;
@@ -64,8 +67,15 @@ public final strictfp class WKTDictionaryTest extends
TestCase {
*/
assertArrayEquals("getCodeSpaces()", new String[] {"ESRI",
"MyCodeSpace"}, factory.getCodeSpaces().toArray());
assertSame("getAuthority()", Citations.ESRI, factory.getAuthority());
- assertSetEquals(Arrays.asList("102018", "ESRI::102021",
"MyCodeSpace::102021", "MyCodeSpace:v2:102021"),
- factory.getAuthorityCodes(SingleCRS.class));
+ Set<String> codes = factory.getAuthorityCodes(IdentifiedObject.class);
+ assertSame(codes, factory.getAuthorityCodes(IdentifiedObject.class));
// Test caching.
+ assertSame(codes, factory.getAuthorityCodes(SingleCRS.class));
// Test sharing.
+ assertSetEquals(Arrays.asList("102018", "ESRI::102021",
"MyCodeSpace::102021", "MyCodeSpace:v2:102021"), codes);
+ assertSetEquals(Arrays.asList("102018", "ESRI::102021"),
factory.getAuthorityCodes(ProjectedCRS.class));
+ codes = factory.getAuthorityCodes(GeographicCRS.class);
+ assertSetEquals(Arrays.asList("MyCodeSpace::102021",
"MyCodeSpace:v2:102021"), codes);
+ assertSame(codes, factory.getAuthorityCodes(GeodeticCRS.class));
// Test sharing.
+ assertSame(codes, factory.getAuthorityCodes(GeographicCRS.class));
// Test caching.
/*
* Tests CRS creation.
*/