You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2022/11/19 16:22:19 UTC
[sis] 01/01: Bug fixes related to unmarshalling of GML documents. Those bugs were identified by OGC TestBed 18 D025 scenario. This is a port of 3 commits on `master` branch.
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 ec0eaa68d945dadbc82f028fd79dc46b296aa2cb
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Sat Nov 19 17:04:11 2022 +0100
Bug fixes related to unmarshalling of GML documents.
Those bugs were identified by OGC TestBed 18 D025 scenario.
This is a port of 3 commits on `master` branch.
---
.../sis/internal/jaxb/IdentifierMapAdapter.java | 30 +++++-
.../sis/internal/jaxb/SpecializedIdentifier.java | 2 +
.../org/apache/sis/internal/jaxb/package-info.java | 2 +-
.../org/apache/sis/internal/metadata/Merger.java | 6 +-
.../java/org/apache/sis/xml/NilObjectHandler.java | 2 +-
.../java/org/apache/sis/xml/ReferenceResolver.java | 8 +-
.../referencing/CC_GeneralOperationParameter.java | 39 +++++--
.../jaxb/referencing/CC_GeneralParameterValue.java | 11 +-
.../jaxb/referencing/CC_OperationMethod.java | 11 +-
.../jaxb/referencing/CC_OperationParameter.java | 54 +++++++---
.../internal/jaxb/referencing/package-info.java | 2 +-
.../sis/internal/referencing/AxisDirections.java | 57 +++++++++--
.../sis/parameter/AbstractParameterDescriptor.java | 4 +-
.../sis/parameter/DefaultParameterDescriptor.java | 70 ++++++++++---
.../sis/parameter/DefaultParameterValue.java | 13 ++-
.../sis/parameter/DefaultParameterValueGroup.java | 8 +-
.../org/apache/sis/parameter/ParameterFormat.java | 3 +-
.../java/org/apache/sis/parameter/Parameters.java | 9 +-
.../sis/parameter/UnmodifiableParameterValue.java | 13 ++-
.../sis/referencing/crs/AbstractDerivedCRS.java | 13 +--
.../sis/referencing/cs/CoordinateSystems.java | 7 ++
.../org/apache/sis/referencing/cs/Normalizer.java | 26 +++--
.../operation/AbstractCoordinateOperation.java | 20 +---
.../operation/AbstractSingleOperation.java | 9 +-
.../operation/DefaultConcatenatedOperation.java | 2 +-
.../referencing/operation/DefaultConversion.java | 16 +--
.../operation/DefaultOperationMethod.java | 26 +++--
.../operation/DefaultPassThroughOperation.java | 112 +++++++++++++++------
.../apache/sis/referencing/operation/SubTypes.java | 2 +-
.../java/org/apache/sis/io/wkt/WKTParserTest.java | 1 +
.../storage/csv/MovingFeatureIterator.java | 3 +-
.../org/apache/sis/internal/storage/csv/Store.java | 2 +-
32 files changed, 406 insertions(+), 177 deletions(-)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
index 95dcf08a4c..2dc9ae3436 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/IdentifierMapAdapter.java
@@ -18,8 +18,10 @@ package org.apache.sis.internal.jaxb;
import java.net.URI;
import java.util.Set;
+import java.util.List;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.Collection;
import java.util.Collections;
@@ -81,7 +83,7 @@ import static org.apache.sis.util.collection.Containers.hashMapCapacity;
* This class is thread safe if the underlying identifier collection is thread safe.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.3
*
* @see org.apache.sis.xml.IdentifiedObject
*
@@ -101,7 +103,10 @@ public class IdentifierMapAdapter extends AbstractMap<Citation,String> implement
/**
* The identifiers to wrap in a map view.
+ *
+ * @see #getIdentifiers(Class)
*/
+ @SuppressWarnings("serial") // Not statically typed as Serializable.
public final Collection<Identifier> identifiers;
/**
@@ -113,6 +118,29 @@ public class IdentifierMapAdapter extends AbstractMap<Citation,String> implement
this.identifiers = identifiers;
}
+ /**
+ * Returns the identifiers as a collection of the specified type.
+ * The given type is the return type of the {@code getIdentifiers()} method which is delegating to this method.
+ * The returned collection is modifiable only if {@link #identifiers} is already of the desired type.
+ * This is the case for {@link org.apache.sis.metadata.iso.ISOMetadata#getIdentifiers()},
+ * which is the API for which we want modifiable collections.
+ *
+ * @param type {@code Collection.class}, {@code List.class} or {@code Set.class}.
+ * @return the identifiers as a collection of the specified type.
+ */
+ @SuppressWarnings("ReturnOfCollectionOrArrayField")
+ public final Collection<Identifier> getIdentifiers(final Class<?> type) {
+ if (!type.isInstance(identifiers)) {
+ if (type.isAssignableFrom(Set.class)) {
+ return new HashSet<>(identifiers); // TODO: use Set.copyOf in JDK10.
+ }
+ if (type.isAssignableFrom(List.class)) {
+ return new ArrayList<>(identifiers); // TODO: use List.copyOf in JDK10.
+ }
+ }
+ return identifiers;
+ }
+
/**
* If the given authority is a special case, returns its {@link NonMarshalledAuthority} integer enum.
* Otherwise returns -1. See javadoc for more information about special cases.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
index 235660151b..1f6f91b95d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/SpecializedIdentifier.java
@@ -60,6 +60,7 @@ public final class SpecializedIdentifier<T> implements Identifier, Cloneable, Se
*
* @see #getAuthority()
*/
+ @SuppressWarnings("serial") // Not statically typed as Serializable.
private final IdentifierSpace<T> authority;
/**
@@ -72,6 +73,7 @@ public final class SpecializedIdentifier<T> implements Identifier, Cloneable, Se
* @see #getValue()
* @see #getCode()
*/
+ @SuppressWarnings("serial") // Not statically typed as Serializable.
T value;
/**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/package-info.java
index 24080ec8e7..ba864f8ea2 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/package-info.java
@@ -35,7 +35,7 @@
* @author Cédric Briançon (Geomatys)
* @author Cullen Rombach (Image Matters)
* @author Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.3
* @since 0.3
* @module
*/
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
index d4e6d80b81..f1af008592 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Merger.java
@@ -146,13 +146,13 @@ public class Merger {
* we are going to merge those two metadata and verify that we are not in an infinite loop.
* We will also verify that the target metadata does not contain a source, or vice-versa.
*/
- { // For keeping 'sourceDone' and 'targetDone' more local.
+ { // For keeping `sourceDone` and `targetDone` more local.
final Boolean sourceDone = done.put(source, Boolean.FALSE);
final Boolean targetDone = done.put(target, Boolean.TRUE);
if (sourceDone != null || targetDone != null) {
if (Boolean.FALSE.equals(sourceDone) && Boolean.TRUE.equals(targetDone)) {
/*
- * At least, the 'source' and 'target' status are consistent. Pretend that we have already
+ * At least, the `source` and `target` status are consistent. Pretend that we have already
* merged those metadata since actually the merge operation is probably underway by the caller.
*/
return true;
@@ -265,7 +265,7 @@ distribute: while (it.hasNext()) {
if (!success) {
if (dryRun) break;
merge(target, propertyName, sourceValue, targetValue);
- success = true; // If no exception has been thrown by 'merged', assume the conflict solved.
+ success = true; // If no exception has been thrown by `merged`, assume the conflict solved.
}
}
}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/NilObjectHandler.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/NilObjectHandler.java
index bf4ce28745..4cb46aeeb6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/NilObjectHandler.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/NilObjectHandler.java
@@ -134,7 +134,7 @@ final class NilObjectHandler implements InvocationHandler {
}
case "getIdentifiers": {
return (attribute instanceof IdentifierMapAdapter) ?
- ((IdentifierMapAdapter) attribute).identifiers : null;
+ ((IdentifierMapAdapter) attribute).getIdentifiers(method.getReturnType()) : null;
}
case "toString": {
return Strings.bracket(getInterface(proxy), attribute);
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/xml/ReferenceResolver.java b/core/sis-metadata/src/main/java/org/apache/sis/xml/ReferenceResolver.java
index e570506272..9370c71f42 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/xml/ReferenceResolver.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/xml/ReferenceResolver.java
@@ -68,8 +68,8 @@ public class ReferenceResolver {
* <li>{@link IdentifiedObject#getIdentifierMap()} will return a {@link java.util.Map}
* view over the given identifiers.</li>
* <li>All other methods except the ones inherited from the {@link Object} class will return
- * an empty collection, an empty array, {@code null}, {@link Double#NaN NaN}, 0 or
- * {@code false}, depending on the method return type.</li>
+ * an empty collection, an empty array, {@code null}, {@link Double#NaN}, 0 or {@code false},
+ * depending on the method return type.</li>
* </ul>
*
* @param <T> the compile-time type of the {@code type} argument.
@@ -135,10 +135,10 @@ public class ReferenceResolver {
return type.cast(object);
} else {
final short key;
- final Object args;
+ final Object[] args;
if (object == null) {
key = Errors.Keys.NotABackwardReference_1;
- args = id;
+ args = new Object[] {id};
} else {
key = Errors.Keys.UnexpectedTypeForReference_3;
args = new Object[] {id, type, object.getClass()};
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
index 717cec4cd2..c67f5b7249 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
@@ -38,11 +38,15 @@ import org.apache.sis.parameter.DefaultParameterValueGroup;
import org.apache.sis.parameter.Parameters;
import org.apache.sis.referencing.NamedIdentifier;
import org.apache.sis.referencing.IdentifiedObjects;
+import org.apache.sis.referencing.GeodeticException;
import org.apache.sis.util.collection.Containers;
import org.apache.sis.util.CorruptedObjectException;
import org.apache.sis.internal.util.CollectionsExt;
import org.apache.sis.internal.jaxb.gco.PropertyType;
import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.xml.IdentifiedObject;
+import org.apache.sis.xml.IdentifierSpace;
/**
@@ -61,7 +65,7 @@ import org.apache.sis.internal.jaxb.Context;
* </ul>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -107,7 +111,7 @@ public final class CC_GeneralOperationParameter extends PropertyType<CC_GeneralO
}
/**
- * Constructor for the {@link #wrap} method only.
+ * Constructor for the {@link #wrap(GeneralParameterDescriptor)} method only.
*/
private CC_GeneralOperationParameter(final GeneralParameterDescriptor parameter) {
super(parameter);
@@ -161,9 +165,32 @@ public final class CC_GeneralOperationParameter extends PropertyType<CC_GeneralO
/**
* Verifies that the given descriptor is non-null and contains at least a name.
* This method is used after unmarshalling.
+ * We do this validation because parameter descriptors are mandatory and SIS classes need them.
+ * So we provide an error message here instead of waiting for a {@link NullPointerException}
+ * to occur in some arbitrary place.
+ *
+ * @param descriptor the descriptor to validate.
+ * @param parent the name of the element to report as the parent of {@code property}.
+ * @param property the name of the property to report as missing if an exception is thrown.
+ * @throws GeodeticException if the parameters are missing or invalid.
*/
- static boolean isValid(final GeneralParameterDescriptor descriptor) {
- return descriptor != null && descriptor.getName() != null;
+ static void validate(final GeneralParameterDescriptor descriptor, final String parent, final String property) {
+ if (descriptor == null || descriptor.getName() == null) {
+ short key = Errors.Keys.MissingComponentInElement_2;
+ String[] args = {parent, property};
+ /*
+ * The exception thrown by this method must be unchecked,
+ * otherwise JAXB just reports is without propagating it.
+ */
+ if (descriptor instanceof IdentifiedObject) {
+ final String link = ((IdentifiedObject) descriptor).getIdentifierMap().get(IdentifierSpace.XLINK);
+ if (link != null) {
+ key = Errors.Keys.NotABackwardReference_1;
+ args = new String[] {link};
+ }
+ }
+ throw new GeodeticException(Errors.format(key, args));
+ }
}
/**
@@ -259,8 +286,8 @@ public final class CC_GeneralOperationParameter extends PropertyType<CC_GeneralO
* be invoked recursively for each parameter in the group.
*/
final Map<String,Object> merged = new HashMap<>(expected);
- merged.putAll(actual); // May overwrite predefined properties.
- mergeArrays(GeneralParameterDescriptor.ALIAS_KEY, GenericName.class, provided.getAlias(), merged, complete.getName());
+ merged.putAll(actual); // May overwrite predefined properties.
+ mergeArrays(GeneralParameterDescriptor.ALIAS_KEY, GenericName.class, provided.getAlias(), merged, complete.getName());
mergeArrays(GeneralParameterDescriptor.IDENTIFIERS_KEY, Identifier.class, provided.getIdentifiers(), merged, null);
if (isGroup) {
final List<GeneralParameterDescriptor> descriptors = ((ParameterDescriptorGroup) provided).descriptors();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralParameterValue.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralParameterValue.java
index 04ce67518b..7856c9dc1d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralParameterValue.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralParameterValue.java
@@ -24,7 +24,6 @@ import org.opengis.parameter.GeneralParameterValue;
import org.apache.sis.parameter.DefaultParameterValue;
import org.apache.sis.parameter.DefaultParameterValueGroup;
import org.apache.sis.internal.jaxb.gco.PropertyType;
-import org.apache.sis.util.resources.Errors;
/**
@@ -32,7 +31,7 @@ import org.apache.sis.util.resources.Errors;
* package documentation for more information about JAXB and interface.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -110,13 +109,7 @@ public final class CC_GeneralParameterValue extends PropertyType<CC_GeneralParam
* @param parameter the unmarshalled element.
*/
public void setElement(final GeneralParameterValue parameter) {
- if (!CC_GeneralOperationParameter.isValid(parameter.getDescriptor())) {
- /*
- * Descriptors are mandatory and SIS classes need them. Provide an error message
- * here instead of waiting for a NullPointerException in some arbitrary place.
- */
- throw new IllegalArgumentException(Errors.format(Errors.Keys.MissingValueForProperty_1, "operationParameter"));
- }
metadata = parameter;
+ CC_GeneralOperationParameter.validate(parameter.getDescriptor(), "ParameterValue", "operationParameter");
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationMethod.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationMethod.java
index 0d565bc285..5d4ff2f852 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationMethod.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationMethod.java
@@ -32,7 +32,6 @@ import org.opengis.parameter.ParameterDescriptorGroup;
import org.opengis.referencing.operation.OperationMethod;
import org.apache.sis.internal.jaxb.Context;
import org.apache.sis.internal.jaxb.gco.PropertyType;
-import org.apache.sis.internal.metadata.Identifiers;
import org.apache.sis.internal.referencing.CoordinateOperations;
import org.apache.sis.internal.referencing.provider.MapProjection;
import org.apache.sis.parameter.DefaultParameterValue;
@@ -48,7 +47,7 @@ import org.apache.sis.util.ArraysExt;
* package documentation for more information about JAXB and interface.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -108,14 +107,8 @@ public final class CC_OperationMethod extends PropertyType<CC_OperationMethod, O
* @param method the unmarshalled element.
*/
public void setElement(final DefaultOperationMethod method) {
- if (!CC_GeneralOperationParameter.isValid(method.getParameters())) {
- /*
- * Parameters are mandatory and SIS classes need them. Provide an error message
- * here instead of waiting for a NullPointerException in some arbitrary place.
- */
- throw new IllegalArgumentException(Identifiers.missingValueForProperty(method.getName(), "parameters"));
- }
metadata = method;
+ CC_GeneralOperationParameter.validate(method.getParameters(), "OperationMethod", "parameter");
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameter.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameter.java
index a00d2a31f0..7970ef1f42 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameter.java
@@ -37,7 +37,7 @@ import org.apache.sis.parameter.DefaultParameterDescriptor;
* infer it from the actual value.</p>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -118,6 +118,40 @@ public final class CC_OperationParameter extends PropertyType<CC_OperationParame
metadata = parameter;
}
+ /**
+ * Returns the base class of parameter values, or {@code null} if unknown.
+ * This method assumes that the parameter value does not yet have a descriptor
+ * (which happens at GML unmarshalling time) and that the type must be derived
+ * from the actual value.
+ *
+ * @param param the parameter from which to get the value class.
+ * @return base class of values, or {@code null} if unknown.
+ */
+ public static Class<?> valueClass(final ParameterValue<?> param) {
+ final Object value = param.getValue();
+ return (value != null) ? value.getClass() : null;
+ }
+
+ /**
+ * Saves the unit of measurement in a boundless range. This method should be invoked only when
+ * {@link #valueClass} is {@link Double} or {@code double[]}. It is the case in a well-formed GML.
+ *
+ * @param param the parameter from which to get the unit of measurement.
+ * @return unit of measurement wrapped in a boundless range, or {@code null} if none.
+ */
+ public static MeasurementRange<?> valueDomain(final ParameterValue<?> param) {
+ Unit<?> unit = param.getUnit();
+ if (unit == null) {
+ return null;
+ }
+ unit = unit.getSystemUnit();
+ if (Units.RADIAN.equals(unit)) {
+ unit = Units.DEGREE;
+ }
+ return MeasurementRange.create(Double.NEGATIVE_INFINITY, false,
+ Double.POSITIVE_INFINITY, false, unit);
+ }
+
/**
* Invoked by JAXB during unmarshalling of the enclosing {@code <gml:OperationParameter>},
* before the child {@link DefaultParameterDescriptor}. This method stores the class and
@@ -129,21 +163,9 @@ public final class CC_OperationParameter extends PropertyType<CC_OperationParame
*/
private void beforeUnmarshal(final Unmarshaller unmarshaller, final Object parent) {
if (parent instanceof ParameterValue<?>) {
- final Object value = ((ParameterValue<?>) parent).getValue();
- if (value != null) {
- valueClass = value.getClass();
- Unit<?> unit = ((ParameterValue<?>) parent).getUnit();
- if (unit != null) {
- unit = unit.getSystemUnit();
- if (Units.RADIAN.equals(unit)) {
- unit = Units.DEGREE;
- }
- assert (valueClass == Double.class) || (valueClass == double[].class) : valueClass;
- valueDomain = MeasurementRange.create(Double.NEGATIVE_INFINITY, false,
- Double.POSITIVE_INFINITY, false, unit);
- }
- Context.setWrapper(Context.current(), this);
- }
+ valueClass = valueClass ((ParameterValue<?>) parent);
+ valueDomain = valueDomain((ParameterValue<?>) parent);
+ Context.setWrapper(Context.current(), this);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/package-info.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/package-info.java
index 90b01e5d26..f1ca5cea95 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/package-info.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/package-info.java
@@ -24,7 +24,7 @@
* @author Guilhem Legal (Geomatys)
* @author Cédric Briançon (Geomatys)
* @author Martin Desruisseaux (Geomatys)
- * @version 0.7
+ * @version 1.3
*
* @see javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
index 61b238cb1c..1ce30a6e87 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/AxisDirections.java
@@ -44,7 +44,7 @@ import static org.apache.sis.util.CharSequences.*;
* Utilities methods related to {@link AxisDirection}.
*
* @author Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.3
* @since 0.4
* @module
*/
@@ -76,17 +76,31 @@ public final class AxisDirections extends Static {
private static final int LAST_ORDINAL = DISPLAY_DOWN.ordinal();
/**
- * Distance from the origin in a polar coordinate system.
- * Specified in ISO 19162 but not yet in ISO 19111.
+ * Forward direction.
+ * For an observer at the centre of the object this is will be towards its front, bow or nose.
+ * Added in ISO 19111:2019 (was not in ISO 19111:2007).
*
- * @since 0.7
+ * @since 1.3
+ */
+ @UML(identifier="forward", obligation=CONDITIONAL, specification=ISO_19162)
+ public static final AxisDirection FORWARD = AxisDirection.valueOf("FORWARD");
+ /*
+ * TODO: remove @Ignore in `WKTParserTest` after the code list values in this class have been removed.
*/
- @UML(identifier="awayFrom", obligation=CONDITIONAL, specification=ISO_19162)
- public static final AxisDirection AWAY_FROM = AxisDirection.valueOf("AWAY_FROM");
+
+ /**
+ * Starboard direction.
+ * For an observer at the centre of the object this will be towards its right.
+ * Added in ISO 19111:2019 (was not in ISO 19111:2007).
+ *
+ * @since 1.3
+ */
+ @UML(identifier="starboard", obligation=CONDITIONAL, specification=ISO_19162)
+ public static final AxisDirection STARBOARD = AxisDirection.valueOf("STARBOARD");
/**
* Direction of geographic angles (bearing).
- * Specified in ISO 19162 but not yet in ISO 19111.
+ * Added in ISO 19111:2019 (was not in ISO 19111:2007).
*
* @since 0.7
*/
@@ -95,13 +109,22 @@ public final class AxisDirections extends Static {
/**
* Direction of arithmetic angles. Used in polar coordinate systems.
- * Specified in ISO 19162 but not yet in ISO 19111.
+ * Added in ISO 19111:2019 (was not in ISO 19111:2007).
*
* @since 0.7
*/
@UML(identifier="counterClockwise", obligation=CONDITIONAL, specification=ISO_19162)
public static final AxisDirection COUNTER_CLOCKWISE = AxisDirection.valueOf("COUNTER_CLOCKWISE");
+ /**
+ * Distance from the origin in a polar coordinate system.
+ * Added in ISO 19111:2019 (was not in ISO 19111:2007).
+ *
+ * @since 0.7
+ */
+ @UML(identifier="awayFrom", obligation=CONDITIONAL, specification=ISO_19162)
+ public static final AxisDirection AWAY_FROM = AxisDirection.valueOf("AWAY_FROM");
+
/**
* For each direction, the opposite direction.
* This map shall be immutable after construction.
@@ -345,6 +368,20 @@ public final class AxisDirections extends Static {
return ordinal >= COLUMN_POSITIVE.ordinal() && ordinal <= ROW_NEGATIVE.ordinal();
}
+ /**
+ * Arithmetic angle between forward/aft/port/starboard directions only.
+ * This is the angle as viewed from above the vehicle.
+ *
+ * @param source the start direction.
+ * @param target the final direction.
+ * @return the angle as a multiple of 90°, or {@link Integer#MIN_VALUE} if none.
+ */
+ public static int angleForVehicle(final AxisDirection source, final AxisDirection target) {
+ if (source == STARBOARD && target == FORWARD) return +1;
+ if (source == FORWARD && target == STARBOARD) return -1;
+ return Integer.MIN_VALUE;
+ }
+
/**
* Angle between geocentric directions only.
*
@@ -367,7 +404,7 @@ public final class AxisDirections extends Static {
}
/**
- * Angle between compass directions only (not for angle between direction along meridians).
+ * Arithmetic angle between compass directions only (not for angle between direction along meridians).
*
* @param source the start direction.
* @param target the final direction.
@@ -394,7 +431,7 @@ public final class AxisDirections extends Static {
}
/**
- * Angle between display directions only.
+ * Arithmetic angle between display directions only.
*
* @param source the start direction.
* @param target the final direction.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
index 7ad14d59cf..4e2d96d22d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
@@ -124,7 +124,7 @@ public abstract class AbstractParameterDescriptor extends AbstractIdentifiedObje
* The maximum number of times that values for this parameter group are required, as an unsigned short.
* Value {@code 0xFFFF} (or -1) means an unrestricted number of occurrences.
*
- * <p>We use a short because this value is usually 1 or a very small number like 2 or 3. This also serve
+ * <p>We use a short because this value is usually 1 or a very small number like 2 or 3. It also serves
* as a safety since a large number would be a bad idea with this parameter implementation.</p>
*
* <p><b>Consider this field as final!</b>
@@ -203,7 +203,7 @@ public abstract class AbstractParameterDescriptor extends AbstractIdentifiedObje
maximumOccurs = crop(descriptor.getMaximumOccurs());
}
- // NOTE: There is no 'castOrCopy' static method in this class because AbstractParameterDescriptor is abstract.
+ // NOTE: There is no `castOrCopy` static method in this class because AbstractParameterDescriptor is abstract.
// If nevertheless we choose to add such method in the future, then CC_GeneralOperationParameter.getElement()
// should be simplified.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
index e3005a2139..4e0cc586da 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
@@ -87,10 +87,12 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
/**
* The class that describe the type of parameter values.
+ * This field should be considered final after construction.
+ * This is declared non-final only for GML unmarshalling.
*
* @see #getValueClass()
*/
- private final Class<T> valueClass;
+ private Class<T> valueClass;
/**
* A set of valid values (usually from a {@linkplain CodeList code list})
@@ -112,9 +114,12 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
* <code>valueClass.{@linkplain Class#getComponentType() getComponentType()}</code>.</li>
* </ul>
*
+ * This field should be considered final after construction.
+ * This is declared non-final only for GML unmarshalling.
+ *
* @see #getValueDomain()
*/
- private final Range<?> valueDomain;
+ private Range<?> valueDomain;
/**
* The default value for the parameter, or {@code null}.
@@ -272,7 +277,6 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
*
* @see #castOrCopy(ParameterDescriptor)
*/
- @SuppressWarnings("unchecked")
protected DefaultParameterDescriptor(final ParameterDescriptor<T> descriptor) {
super(descriptor);
valueClass = descriptor.getValueClass();
@@ -399,6 +403,7 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
@Override
@SuppressWarnings("unchecked")
public Comparable<T> getMinimumValue() {
+ final Range<?> valueDomain = this.valueDomain;
return (valueDomain != null && valueDomain.getElementType() == valueClass)
? (Comparable<T>) valueDomain.getMinValue() : null;
}
@@ -417,6 +422,7 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
@Override
@SuppressWarnings("unchecked")
public Comparable<T> getMaximumValue() {
+ final Range<?> valueDomain = this.valueDomain;
return (valueDomain != null && valueDomain.getElementType() == valueClass)
? (Comparable<T>) valueDomain.getMaxValue() : null;
}
@@ -447,6 +453,7 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
*/
@Override
public Unit<?> getUnit() {
+ final Range<?> valueDomain = this.valueDomain;
return (valueDomain instanceof MeasurementRange<?>) ? ((MeasurementRange<?>) valueDomain).unit() : null;
}
@@ -517,10 +524,10 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
}
case STRICT: {
final DefaultParameterDescriptor<?> that = (DefaultParameterDescriptor<?>) object;
- return this.valueClass == that.valueClass &&
- Objects. equals(this.validValues, that.validValues) &&
- Objects. equals(this.valueDomain, that.valueDomain) &&
- Objects.deepEquals(this.defaultValue, that.defaultValue);
+ return valueClass == that.valueClass &&
+ Objects. equals(validValues, that.validValues) &&
+ Objects. equals(valueDomain, that.valueDomain) &&
+ Objects.deepEquals(defaultValue, that.defaultValue);
}
}
}
@@ -553,7 +560,7 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
/**
- * Constructs a new object in which every attributes are set to a null value.
+ * Constructs a new object in which attributes may be set to a null value.
* <strong>This is not a valid object.</strong> This constructor is strictly
* reserved to JAXB, which will assign values to the fields using reflection.
*
@@ -570,16 +577,55 @@ public class DefaultParameterDescriptor<T> extends AbstractParameterDescriptor i
* This unsafe cast would be forbidden if this constructor was public or used in any context where the
* user can choose the value of <T>. But this constructor should be invoked only during unmarshalling,
* after the creation of the ParameterValue (this is the reverse creation order than what we normally
- * do through the public API). The 'valueClass' should be compatible with DefaultParameterValue.value,
+ * do through the public API). The `valueClass` should be compatible with DefaultParameterValue.value,
* and the parameterized type visible to the user should be only <?>.
*/
valueClass = (Class) param.valueClass;
valueDomain = param.valueDomain;
- } else {
- valueClass = null;
- valueDomain = null;
}
validValues = null;
defaultValue = null;
}
+
+ /**
+ * Invoked by {@link DefaultParameterValue} when the descriptor is set after the value at unmarshalling time.
+ * There is two scenarios in a valid GML document. The first scenario is when the descriptor is defined inside
+ * the parameter value element, like below. In such case, {@link #valueClass} is defined at construction time
+ * by {@link #DefaultParameterDescriptor()} because the value is before the descriptor.
+ *
+ * {@preformat xml
+ * <gml:ParameterValue>
+ * <gml:value uom="…">…</gml:value>
+ * <gml:operationParameter>
+ * <gml:OperationParameter>
+ * …
+ * </gml:OperationParameter>
+ * </gml:operationParameter>
+ * </gml:ParameterValue>
+ * }
+ *
+ * In the second scenario shows below, the descriptor was defined before the value and is referenced by a link.
+ * In that case, {@link #valueClass} is {@code null} the first time that this method is invoked. It may become
+ * non-null if the same parameter descriptor is reused for many parameter values.
+ *
+ * {@preformat xml
+ * <gml:ParameterValue>
+ * <gml:value uom="…">…</gml:value>
+ * <gml:operationParameter xlink:href="#LongitudeRotation"/>
+ * </gml:ParameterValue>
+ * }
+ *
+ * This method modifies the state of this class despite the fact that it should be immutable.
+ * It is okay because we are updating an instance created during GML unmarshalling, and that
+ * instance should not have been given to user yet.
+ *
+ * @param param the parameter value from which to infer the value type.
+ */
+ @SuppressWarnings("unchecked")
+ final void setValueClass(final DefaultParameterValue<?> param) {
+ valueClass = (Class) Classes.findCommonClass(valueClass, CC_OperationParameter.valueClass(param));
+ if (valueDomain == null) {
+ valueDomain = CC_OperationParameter.valueDomain(param);
+ }
+ }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
index 3a3fd6be37..6c423cdcd0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
@@ -118,7 +118,7 @@ import static org.apache.sis.util.Utilities.deepEquals;
* for modifying the behavior of all getter and setter methods.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @param <T> the type of the value stored in this parameter.
*
@@ -1129,14 +1129,21 @@ convert: if (componentType != null) {
/**
* Invoked by JAXB at unmarshalling time.
- * May also be invoked by {@link DefaultParameterValueGroup} if the descriptor as been completed
+ * May also be invoked by {@link DefaultParameterValueGroup} if the descriptor has been completed
* with additional information provided in the {@code <gml:group>} element of a descriptor group.
*
* @see #getDescriptor()
*/
final void setDescriptor(final ParameterDescriptor<T> descriptor) {
this.descriptor = descriptor;
- assert (value == null) || descriptor.getValueClass().isInstance(value) : this;
+ if (descriptor instanceof DefaultParameterDescriptor<?>) {
+ ((DefaultParameterDescriptor<?>) descriptor).setValueClass(this);
+ }
+ /*
+ * A previous version was doing `assert descriptor.getValueClass().isInstance(value)`
+ * where the value class was inferred by `DefaultParameterDescriptor()`. But it does
+ * not always work, and the `NullPointerException` seems to be caught by JAXB.
+ */
}
/**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
index b0c28806aa..e28988010e 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
@@ -559,7 +559,7 @@ scan: for (final GeneralParameterValue param : actual.values()) {
/**
* Invoked by JAXB for setting the group parameter descriptor. Those parameter are redundant with
* the parameters associated to the values given to {@link #setValues(GeneralParameterValue[])},
- * except the the group identification (name, <i>etc.</i>) and for any optional parameters which
+ * except for the group identification (name, <i>etc.</i>) and for any optional parameters which
* were not present in the above {@code GeneralParameterValue} array.
*
* @see #getDescriptor()
@@ -611,9 +611,9 @@ scan: for (final GeneralParameterValue param : actual.values()) {
* Appends all parameter values. In this process, we may need to update the descriptor of some values
* if those descriptors changed as a result of the above merge process.
*
- * @param parameters The parameters to add, or {@code null} for {@link #values}.
- * @param replacements The replacements to apply in the {@code GeneralParameterValue} instances.
- * @param addTo Where to store the new values.
+ * @param parameters the parameters to add, or {@code null} for {@link #values}.
+ * @param replacements the replacements to apply in the {@code GeneralParameterValue} instances.
+ * @param addTo where to store the new values.
*/
@SuppressWarnings({"unchecked", "AssignmentToCollectionOrArrayFieldFromParameter"})
private void setValues(GeneralParameterValue[] parameters,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
index 7d7131bb37..e34af12dd4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
@@ -692,7 +692,8 @@ public class ParameterFormat extends TabularFormat<Object> {
/*
* Writes the values, each on its own line, together with their unit of measurement.
*/
- final byte alignment = Number.class.isAssignableFrom(valueClass) ? TableAppender.ALIGN_RIGHT : TableAppender.ALIGN_LEFT;
+ final byte alignment = (valueClass != null && Number.class.isAssignableFrom(valueClass))
+ ? TableAppender.ALIGN_RIGHT : TableAppender.ALIGN_LEFT;
table.setCellAlignment(alignment);
final int length = row.values.size();
for (int i=0; i<length; i++) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
index f20dd66569..ed74415469 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
@@ -38,6 +38,7 @@ import org.apache.sis.util.UnconvertibleObjectException;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ObjectConverters;
import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.Classes;
import org.apache.sis.util.Debug;
@@ -356,9 +357,15 @@ public abstract class Parameters implements ParameterValueGroup, Cloneable {
if (descriptor instanceof DefaultParameterDescriptor<?>) {
return ((DefaultParameterDescriptor<?>) descriptor).getValueDomain();
}
- final Class<?> valueClass = descriptor.getValueClass();
+ Class<?> valueClass = descriptor.getValueClass();
final Comparable<?> minimumValue = descriptor.getMinimumValue();
final Comparable<?> maximumValue = descriptor.getMaximumValue();
+ if (valueClass == null) { // Should never be null, but invalid objects exist.
+ valueClass = Classes.findCommonClass(Classes.getClass(minimumValue), Classes.getClass(maximumValue));
+ if (valueClass == null) {
+ valueClass = Object.class;
+ }
+ }
if ((minimumValue == null || valueClass.isInstance(minimumValue)) &&
(maximumValue == null || valueClass.isInstance(maximumValue)))
{
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java
index bccdeb3951..4fa432ec27 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/UnmodifiableParameterValue.java
@@ -49,7 +49,7 @@ import org.apache.sis.util.resources.Errors;
* </div>
*
* @author Martin Desruisseaux (Geomatys)
- * @version 0.6
+ * @version 1.3
*
* @param <T> the type of the value stored in this parameter.
*
@@ -100,10 +100,13 @@ final class UnmodifiableParameterValue<T> extends DefaultParameterValue<T> {
@Override
public T getValue() {
T value = super.getValue();
- if (value instanceof Cloneable) try {
- value = getDescriptor().getValueClass().cast(Cloner.cloneIfPublic(value));
- } catch (CloneNotSupportedException e) {
- throw new UnsupportedOperationException(Errors.format(Errors.Keys.CloneNotSupported_1, value.getClass()), e);
+ if (value instanceof Cloneable) {
+ final Class<T> type = getDescriptor().getValueClass(); // May be null after GML unmarshalling.
+ if (type != null) try {
+ value = type.cast(Cloner.cloneIfPublic(value));
+ } catch (CloneNotSupportedException e) {
+ throw new UnsupportedOperationException(Errors.format(Errors.Keys.CloneNotSupported_1, value.getClass()), e);
+ }
}
return value;
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
index 0f167cd410..4b3a1316d9 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
@@ -22,7 +22,6 @@ import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.bind.ValidationException;
import org.opengis.util.FactoryException;
import org.opengis.referencing.datum.Datum;
import org.opengis.referencing.crs.SingleCRS;
@@ -34,12 +33,12 @@ import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.MathTransformFactory;
import org.opengis.geometry.MismatchedDimensionException;
+import org.apache.sis.referencing.GeodeticException;
import org.apache.sis.referencing.operation.DefaultConversion;
import org.apache.sis.internal.jaxb.referencing.CC_Conversion;
import org.apache.sis.internal.referencing.ReferencingFactoryContainer;
import org.apache.sis.internal.metadata.ImplementationHelper;
import org.apache.sis.internal.metadata.Identifiers;
-import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.internal.system.Semaphores;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
@@ -54,7 +53,7 @@ import static org.apache.sis.util.Utilities.deepEquals;
* (not by a {@linkplain org.apache.sis.referencing.datum.AbstractDatum datum}).
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.2
+ * @version 1.3
*
* @param <C> the conversion type, either {@code Conversion} or {@code Projection}.
*
@@ -82,6 +81,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> extends AbstractCRS impl
*
* @see #getConversionFromBase()
*/
+ @SuppressWarnings("serial") // Not statically typed as Serializable.
private C conversionFromBase;
/**
@@ -162,9 +162,6 @@ abstract class AbstractDerivedCRS<C extends Conversion> extends AbstractCRS impl
if (properties != null) {
factory = (MathTransformFactory) properties.get(ReferencingFactoryContainer.MT_FACTORY);
}
- if (factory == null) {
- factory = DefaultFactories.forBuildin(MathTransformFactory.class);
- }
try {
return DefaultConversion.castOrCopy(conversion).specialize(getConversionType(), baseCRS, this, factory);
} catch (FactoryException e) {
@@ -332,7 +329,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> extends AbstractCRS impl
* coordinate system (CS). The CS information is required by {@code createConversionFromBase(…)}
* in order to create a {@link MathTransform} with correct axis swapping and unit conversions.
*/
- private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) throws ValidationException {
+ private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
String property = "conversion";
if (conversionFromBase != null) {
final SingleCRS baseCRS = CC_Conversion.setBaseCRS(conversionFromBase, null); // Clear the temporary value now.
@@ -350,6 +347,6 @@ abstract class AbstractDerivedCRS<C extends Conversion> extends AbstractCRS impl
* and call to `getConversionFromBase()` will throw a ClassCastException if this instance is actually
* a ProjectedCRS (because of the method overriding with return type covariance).
*/
- throw new ValidationException(Identifiers.missingValueForProperty(getName(), property));
+ throw new GeodeticException(Identifiers.missingValueForProperty(getName(), property));
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
index d8134a7a9c..531b4a2401 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/CoordinateSystems.java
@@ -239,6 +239,13 @@ public final class CoordinateSystems extends Static {
if (c != Integer.MIN_VALUE) {
return new Angle(c * 90);
}
+ /*
+ * Check for FORWARD, AFT, PORT, STARBOARD.
+ */
+ c = AxisDirections.angleForVehicle(source, target);
+ if (c != Integer.MIN_VALUE) {
+ return new Angle(c * 90);
+ }
/*
* Check for DISPLAY_UP, DISPLAY_DOWN, etc. assuming a flat screen.
* Note that we do not check for grid directions (COLUMN_POSITIVE,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
index dfdc5672c3..8010bc2365 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/Normalizer.java
@@ -106,7 +106,7 @@ final class Normalizer implements Comparable<Normalizer> {
*
* @see #order(AxisDirection)
*/
- private static final int SHIFT = 2;
+ private static final int SHIFT = 3;
/**
* Custom code list values to handle as if the where defined between two GeoAPI values.
@@ -115,12 +115,15 @@ final class Normalizer implements Comparable<Normalizer> {
*/
private static final Map<AxisDirection,Integer> ORDER = new HashMap<>();
static {
- final Map<AxisDirection,Integer> m = ORDER;
// Get ordinal of last compass direction defined by GeoAPI. We will continue on the horizontal plane.
- final int horizontal = (AxisDirection.NORTH.ordinal() + (AxisDirections.COMPASS_COUNT - 1)) << SHIFT;
- m.put(AxisDirections.AWAY_FROM, horizontal + 1);
- m.put(AxisDirections.COUNTER_CLOCKWISE, horizontal + 2);
- m.put(AxisDirections.CLOCKWISE, horizontal + 3);
+ int code = (AxisDirection.NORTH.ordinal() + (AxisDirections.COMPASS_COUNT - 1)) << SHIFT;
+ for (final AxisDirection d : new AxisDirection[] {
+ AxisDirections.FORWARD,
+ AxisDirections.STARBOARD,
+ AxisDirections.COUNTER_CLOCKWISE,
+ AxisDirections.CLOCKWISE,
+ AxisDirections.AWAY_FROM
+ }) ORDER.put(d, ++code);
}
/**
@@ -170,8 +173,9 @@ final class Normalizer implements Comparable<Normalizer> {
if (d == 0) {
final AxisDirection d1 = this.axis.getDirection();
final AxisDirection d2 = that.axis.getDirection();
- d = AxisDirections.angleForCompass(d2, d1);
- if (d == Integer.MIN_VALUE) {
+ if ((d = AxisDirections.angleForCompass(d2, d1)) == Integer.MIN_VALUE &&
+ (d = AxisDirections.angleForVehicle(d2, d1)) == Integer.MIN_VALUE)
+ {
if (meridian != null) {
if (that.meridian != null) {
d = meridian.compareTo(that.meridian);
@@ -445,10 +449,10 @@ final class Normalizer implements Comparable<Normalizer> {
*/
static AbstractCS forConvention(final CoordinateSystem cs, final AxesConvention convention) {
switch (convention) {
- case NORMALIZED: // Fall through
+ case NORMALIZED: // Fall through
case DISPLAY_ORIENTED: return normalize(cs, convention, true);
- case RIGHT_HANDED: return normalize(cs, null, true);
- case POSITIVE_RANGE: return shiftAxisRange(cs);
+ case RIGHT_HANDED: return normalize(cs, null, true);
+ case POSITIVE_RANGE: return shiftAxisRange(cs);
default: throw new AssertionError(convention);
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
index 1528ffa922..6f7b8d5b96 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
@@ -670,23 +670,8 @@ check: for (int isTarget=0; ; isTarget++) { // 0 == source check; 1
}
/**
- * Returns the object for transforming coordinates in the {@linkplain #getSourceCRS() source CRS}
- * to coordinates in the {@linkplain #getTargetCRS() target CRS}.
- *
- * <h4>Use with interpolation CRS</h4>
- * If the {@linkplain #getInterpolationCRS() interpolation CRS} is non-null, then the math transform
- * input coordinates shall by (<var>interpolation</var>, <var>source</var>) tuples: for each value
- * to transform, the interpolation point coordinates shall be first, followed by the source coordinates.
- *
- * <div class="note"><b>Example:</b>
- * in a transformation between two {@linkplain org.apache.sis.referencing.crs.DefaultVerticalCRS vertical CRS},
- * if the {@linkplain #getSourceCRS() source} coordinates are (<var>z</var>) values but the coordinate operation
- * additionally requires (<var>x</var>,<var>y</var>) values for {@linkplain #getInterpolationCRS() interpolation}
- * purpose, then the math transform input coordinates shall be (<var>x</var>,<var>y</var>,<var>z</var>) tuples in
- * that order.</div>
- *
- * The interpolation coordinates will {@linkplain DefaultPassThroughOperation pass through the operation}
- * and appear in the math transform outputs, in the same order than inputs.
+ * Returns the object for transforming coordinates in the source CRS to coordinates in the target CRS.
+ * The transform may be {@code null} if this coordinate operation is a defining conversion.
*
* @return the transform from source to target CRS, or {@code null} if not applicable.
*/
@@ -1208,6 +1193,7 @@ check: for (int isTarget=0; ; isTarget++) { // 0 == source check; 1
/**
* Invoked by JAXB after unmarshalling.
+ * May be overridden by subclasses.
*/
void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
computeTransientFields();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
index 128cea0c0c..a44cc95a55 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractSingleOperation.java
@@ -49,6 +49,7 @@ import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.metadata.ImplementationHelper;
import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.internal.metadata.Identifiers;
+import org.apache.sis.referencing.GeodeticException;
import org.apache.sis.util.collection.Containers;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.ComparisonMode;
@@ -408,7 +409,7 @@ class AbstractSingleOperation extends AbstractCoordinateOperation implements Sin
private void setParameters(final GeneralParameterValue[] values) {
if (parameters == null) {
if (!(method instanceof DefaultOperationMethod)) { // May be a non-null proxy if defined only by xlink:href.
- throw new IllegalStateException(Identifiers.missingValueForProperty(getName(), "method"));
+ throw new GeodeticException(Identifiers.missingValueForProperty(getName(), "method"));
}
/*
* The descriptors in the <gml:method> element do not know the class of parameter value
@@ -463,6 +464,12 @@ class AbstractSingleOperation extends AbstractCoordinateOperation implements Sin
@Override
final void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
super.afterUnmarshal(unmarshaller, parent);
+ if (parameters == null && method != null) {
+ final ParameterDescriptorGroup descriptor = method.getParameters();
+ if (descriptor != null && descriptor.descriptors().isEmpty()) {
+ parameters = descriptor.createValue();
+ }
+ }
final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
final CoordinateReferenceSystem targetCRS = super.getTargetCRS();
if (transform == null && sourceCRS != null && targetCRS != null && parameters != null) try {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
index 33808373a9..6106052ceb 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
@@ -242,7 +242,7 @@ final class DefaultConcatenatedOperation extends AbstractCoordinateOperation imp
} else if (!step.isIdentity()) {
flattened.add(op);
}
- if (mtFactory != null && step != null) {
+ if (mtFactory != null) {
transform = (transform != null) ? mtFactory.createConcatenatedTransform(transform, step) : step;
}
/*
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
index fe908c6503..ccc51273de 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConversion.java
@@ -36,6 +36,7 @@ import org.apache.sis.referencing.operation.transform.DefaultMathTransformFactor
import org.apache.sis.referencing.operation.matrix.Matrices;
import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.referencing.Resources;
+import org.apache.sis.internal.system.DefaultFactories;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.util.ArgumentChecks;
import org.apache.sis.util.Utilities;
@@ -217,8 +218,8 @@ public class DefaultConversion extends AbstractSingleOperation implements Conver
/**
* Constructs a new conversion with the same values than the specified one, together with the
- * specified source and target CRS. While the source conversion can be an arbitrary one, it is
- * typically a defining conversion.
+ * specified source and target CRS. While the source conversion can be an arbitrary one,
+ * it is typically a defining conversion.
*
* @param definition the defining conversion.
* @param source the new source CRS.
@@ -376,13 +377,14 @@ public class DefaultConversion extends AbstractSingleOperation implements Conver
*
* This {@code specialize(…)} method returns a conversion which implement at least the given {@code baseType}
* interface, but may also implement a more specific GeoAPI interface if {@code specialize(…)} has been able
- * to infer the type from this operation {@linkplain #getMethod() method}.
+ * to infer the type from the {@linkplain #getMethod() operation method}.
*
* @param <T> compile-time type of the {@code baseType} argument.
* @param baseType the base GeoAPI interface to be implemented by the conversion to return.
* @param sourceCRS the source CRS.
* @param targetCRS the target CRS.
- * @param factory the factory to use for creating a transform from the parameters or for performing axis changes.
+ * @param factory the factory to use for creating a transform from the parameters or for performing axis changes,
+ * or {@code null} for the default factory.
* @return the conversion of the given type between the given CRS.
* @throws ClassCastException if a contradiction is found between the given {@code baseType},
* the defining {@linkplain DefaultConversion#getInterface() conversion type} and
@@ -397,12 +399,11 @@ public class DefaultConversion extends AbstractSingleOperation implements Conver
*/
public <T extends Conversion> T specialize(final Class<T> baseType,
final CoordinateReferenceSystem sourceCRS, final CoordinateReferenceSystem targetCRS,
- final MathTransformFactory factory) throws FactoryException
+ MathTransformFactory factory) throws FactoryException
{
ArgumentChecks.ensureNonNull("baseType", baseType);
ArgumentChecks.ensureNonNull("sourceCRS", sourceCRS);
ArgumentChecks.ensureNonNull("targetCRS", targetCRS);
- ArgumentChecks.ensureNonNull("factory", factory);
/*
* Conceptual consistency check: verify that the new CRS use the same datum than the previous ones,
* since the purpose of this method is not to apply datum changes. Datum changes are the purpose of
@@ -425,6 +426,9 @@ public class DefaultConversion extends AbstractSingleOperation implements Conver
ensureCompatibleDatum("targetCRS", sourceCRS, super.getTargetCRS());
}
}
+ if (factory == null) {
+ factory = DefaultFactories.forBuildin(MathTransformFactory.class);
+ }
return SubTypes.create(baseType, this, sourceCRS, targetCRS, factory);
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
index 9d6b58bde6..e195d20aaf 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultOperationMethod.java
@@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Collections;
+import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@@ -117,7 +118,7 @@ import static org.apache.sis.util.ArgumentChecks.*;
* {@link org.apache.sis.referencing.operation.transform.DefaultMathTransformFactory}.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.3
*
* @see DefaultConversion
* @see DefaultTransformation
@@ -192,7 +193,8 @@ public class DefaultOperationMethod extends AbstractIdentifiedObject implements
* The set of parameters, or {@code null} if none.
*
* <p><b>Consider this field as final!</b>
- * This field is modified only at unmarshalling time by {@link #setDescriptors(GeneralParameterDescriptor[])}</p>
+ * This field is modified only at unmarshalling time by {@link #setDescriptors(GeneralParameterDescriptor[])}
+ * or {@link #afterUnmarshal(Unmarshaller, Object)}.</p>
*/
@SuppressWarnings("serial") // Not statically typed as Serializable.
private ParameterDescriptorGroup parameters;
@@ -303,10 +305,7 @@ public class DefaultOperationMethod extends AbstractIdentifiedObject implements
targetDimensions = transform.getTargetDimensions();
if (transform instanceof Parameterized) {
parameters = ((Parameterized) transform).getParameterDescriptors();
- } else {
- parameters = null;
}
- formula = null;
}
/**
@@ -632,9 +631,8 @@ public class DefaultOperationMethod extends AbstractIdentifiedObject implements
* Returns the set of parameters.
*
* <div class="note"><b>Departure from the ISO 19111 standard:</b>
- * this property is mandatory according ISO 19111, but may be null in Apache SIS if the
- * {@link #DefaultOperationMethod(MathTransform)} constructor has been unable to infer it
- * or if this {@code OperationMethod} has been read from an incomplete GML document.</div>
+ * this property is mandatory according ISO 19111, but may be {@code null} in Apache SIS if the
+ * {@link #DefaultOperationMethod(MathTransform)} constructor has been unable to infer it.</div>
*
* @return the parameters, or {@code null} if unknown.
*
@@ -971,4 +969,16 @@ public class DefaultOperationMethod extends AbstractIdentifiedObject implements
parameters = new DefaultParameterDescriptorGroup(IdentifiedObjects.getProperties(previous),
previous.getMinimumOccurs(), previous.getMaximumOccurs(), descriptors);
}
+
+ /**
+ * Invoked by JAXB after unmarshalling. If the {@code <gml:OperationMethod>} element does not contain
+ * any {@code <gml:parameter>}, we assume that this is a valid parameterless operation (as opposed to
+ * an operation with unknown parameters). We need this assumption because, contrarily to GeoAPI model,
+ * the GML schema does not differentiate "no parameters" from "unspecified parameters".
+ */
+ private void afterUnmarshal(final Unmarshaller unmarshaller, final Object parent) {
+ if (parameters == null) {
+ parameters = CC_OperationMethod.group(super.getName(), new GeneralParameterDescriptor[0]);
+ }
+ }
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
index 950731c638..1d3b09fc96 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
@@ -19,24 +19,29 @@ package org.apache.sis.referencing.operation;
import java.util.Map;
import java.util.Arrays;
import java.util.Objects;
+import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.util.FactoryException;
import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.Conversion;
import org.opengis.referencing.operation.CoordinateOperation;
import org.opengis.referencing.operation.PassThroughOperation;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.CompoundCRS;
+import org.apache.sis.referencing.GeodeticException;
import org.apache.sis.referencing.operation.transform.MathTransforms;
import org.apache.sis.referencing.operation.transform.PassThroughTransform;
import org.apache.sis.internal.referencing.ReferencingUtilities;
import org.apache.sis.internal.metadata.ImplementationHelper;
import org.apache.sis.util.UnsupportedImplementationException;
-import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.ArraysExt;
import org.apache.sis.util.ComparisonMode;
import org.apache.sis.util.resources.Errors;
import org.apache.sis.io.wkt.FormattableObject;
import org.apache.sis.io.wkt.Formatter;
+import org.apache.sis.referencing.CRS;
import static org.apache.sis.util.Utilities.deepEquals;
@@ -45,7 +50,7 @@ import static org.apache.sis.util.Utilities.deepEquals;
* Specifies that a subset of a coordinate tuple is subject to a specific coordinate operation.
*
* @author Martin Desruisseaux (IRD, Geomatys)
- * @version 0.7
+ * @version 1.3
* @since 0.6
* @module
*/
@@ -111,9 +116,8 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
final int firstAffectedCoordinate,
final int numTrailingCoordinates)
{
- super(properties, sourceCRS, targetCRS, null, MathTransforms.passThrough(
- firstAffectedCoordinate, operation.getMathTransform(), numTrailingCoordinates));
- ArgumentChecks.ensureNonNull("operation", operation);
+ super(properties, sourceCRS, targetCRS, null,
+ MathTransforms.passThrough(firstAffectedCoordinate, operation.getMathTransform(), numTrailingCoordinates));
this.operation = operation;
}
@@ -192,11 +196,11 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
final MathTransform transform = super.getMathTransform();
if (transform instanceof PassThroughTransform) {
return ((PassThroughTransform) transform).getModifiedCoordinates();
- } else {
+ } else if (operation != null) {
/*
- * Should not happen with objects created by public methods since the constructor created the transform
- * itself. However may happen with operations parsed from GML. As a fallback, search in the components
- * of CompoundCRS. This is not a universal fallback, but work for the most straightforward cases.
+ * Should not happen with objects created by public methods since the constructor created the transform itself.
+ * However may happen with operations parsed from GML. As a fallback, search in the components of CompoundCRS.
+ * This is not a universal fallback, but works for the most straightforward cases.
*/
final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
if (sourceCRS instanceof CompoundCRS) {
@@ -214,8 +218,8 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
firstAffectedCoordinate += dim;
}
}
- throw new UnsupportedImplementationException(transform.getClass());
}
+ throw new UnsupportedImplementationException(transform.getClass());
}
/**
@@ -300,8 +304,8 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
private DefaultPassThroughOperation() {
/*
* A sub-operation is mandatory for SIS working. We do not verify its presence here because the verification
- * would have to be done in an 'afterMarshal(…)' method and throwing an exception in that method causes the
- * whole unmarshalling to fail. But the CC_CoordinateOperation adapter does some verifications.
+ * would have to be done in an `afterMarshal(…)` method and throwing an exception in that method causes the
+ * whole unmarshalling to fail. But the `CC_CoordinateOperation` adapter does some verifications.
*/
}
@@ -327,37 +331,79 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
*/
@XmlElement(name = "modifiedCoordinate", required = true)
private int[] getIndices() {
- final int[] indices = getModifiedCoordinates();
- for (int i=0; i<indices.length; i++) {
- indices[i]++;
+ final int[] dimensions = getModifiedCoordinates();
+ for (int i=0; i<dimensions.length; i++) {
+ dimensions[i]++;
}
- return indices;
+ return dimensions;
}
/**
* Invoked by JAXB at unmarshalling time for setting the modified coordinates.
+ * This method needs to be invoked last, even if the {@code <gml:modifiedCoordinate>}
+ * elements are not last in the GML document. It is the case when using JAXB because
+ * multiple occurrences of {@code <gml:modifiedCoordinate>} are aggregated in an array.
*/
- private void setIndices(final int[] coordinates) {
- String missing = "sourceCRS";
- final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
- if (sourceCRS != null) {
- missing = "modifiedCoordinate";
- if (coordinates != null && coordinates.length != 0) {
- missing = "coordOperation";
- if (operation != null) {
- for (int i=1; i<coordinates.length; i++) {
- final int previous = coordinates[i-1];
- if (previous < 1 || coordinates[i] != previous + 1) {
- throw new IllegalArgumentException(Errors.format(
- Errors.Keys.CanNotAssign_2, missing, Arrays.toString(coordinates)));
+ private void setIndices(final int[] dimensions) {
+ /*
+ * Argument and state validation.
+ */
+ String missing = "modifiedCoordinate";
+ FactoryException cause = null;
+ final int n = dimensions.length;
+ if (n != 0) {
+ if (!ArraysExt.isRange(dimensions[0], dimensions)) {
+ throw new GeodeticException(Errors.format(Errors.Keys.CanNotAssign_2, missing, Arrays.toString(dimensions)));
+ }
+ missing = "sourceCRS";
+ final CoordinateReferenceSystem sourceCRS = super.getSourceCRS();
+ if (sourceCRS != null) {
+ missing = "targetCRS";
+ final CoordinateReferenceSystem targetCRS = super.getTargetCRS();
+ if (targetCRS != null) {
+ missing = "coordOperation";
+ if (operation != null) {
+ /*
+ * If the operation is a defining operation, we need to replace it by a full operation.
+ * After that, we can store the modified coordinate indices in the transform field.
+ */
+ MathTransform subTransform = operation.getMathTransform();
+ if (operation instanceof Conversion) {
+ CoordinateReferenceSystem sourceSub = operation.getSourceCRS();
+ CoordinateReferenceSystem targetSub = operation.getTargetCRS();
+ if (subTransform == null || sourceSub == null || targetSub == null) try {
+ final int[] zeroBased = dimensions.clone();
+ for (int i=0; i<n; i++) zeroBased[i]--;
+ if (sourceSub == null) sourceSub = CRS.selectDimensions(sourceCRS, zeroBased);
+ if (targetSub == null) targetSub = CRS.selectDimensions(targetCRS, zeroBased);
+ operation = DefaultConversion.castOrCopy((Conversion) operation)
+ .specialize(Conversion.class, sourceSub, targetSub, null);
+ subTransform = operation.getMathTransform();
+ } catch (FactoryException e) {
+ cause = e;
+ }
+ }
+ if (subTransform != null) {
+ transform = MathTransforms.passThrough(dimensions[0] - 1, subTransform,
+ ReferencingUtilities.getDimension(sourceCRS) - dimensions[n-1]);
+ return;
}
}
- transform = MathTransforms.passThrough(coordinates[0] - 1, operation.getMathTransform(),
- ReferencingUtilities.getDimension(sourceCRS) - coordinates[coordinates.length - 1]);
- return;
}
}
}
- throw new IllegalStateException(Errors.format(Errors.Keys.MissingComponentInElement_2, missing, "PassThroughOperation"));
+ throw new GeodeticException(Errors.format(Errors.Keys.MissingComponentInElement_2, "PassThroughOperation", missing), cause);
+ }
+
+ /**
+ * Invoked by JAXB after unmarshalling. If needed, this method tries to infer source/target CRS
+ * of the nested operation from the source/target CRS if the enclosing pass-through operation.
+ */
+ @Override
+ void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
+ super.afterUnmarshal(unmarshaller, parent);
+ if (transform == null) {
+ setIndices(ArraysExt.EMPTY_INT); // Cause an exception to be thrown.
+ }
}
}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
index 51e1e6445c..ea3e72e12f 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
@@ -168,7 +168,7 @@ final class SubTypes {
conversion = new DefaultConversion(definition, sourceCRS, targetCRS, factory, actual);
}
/*
- * The DefaultConversion constructor may have used by MathTransformFactory for creating the actual
+ * The DefaultConversion constructor may have used MathTransformFactory for creating the actual
* MathTransform object. In such case, we can use the knownledge that the factory has about the
* coordinate operation for refining again the type of the object to be returned.
*/
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java
index cb937dbd6c..9433d0f367 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/WKTParserTest.java
@@ -480,6 +480,7 @@ public final strictfp class WKTParserTest extends CRSParserTest {
*/
@Test
@Override
+ @org.junit.Ignore("Pending new AxisDirection code list in GeoAPI.")
public void testEngineeringForShip() throws FactoryException {
super.testEngineeringForShip();
final CoordinateSystem cs = object.getCoordinateSystem();
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureIterator.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureIterator.java
index ad85cad854..6dfb161f0c 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureIterator.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/MovingFeatureIterator.java
@@ -114,7 +114,8 @@ final class MovingFeatureIterator extends FeatureIterator implements Consumer<Lo
/**
* Executes the given action for the next moving feature or for all remaining moving features.
- * This method assumes that the 4 first columns are as documented in the code inside constructor.
+ * This method assumes that the 4 first columns are identifier, start time, end time and
+ * optional attributes in that order.
*
* @param action the action to execute as soon as the {@code mfidref} change, or {@code null} if none.
* @param all {@code true} for executing the given action on all remaining features.
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
index 1322b78f86..27f9685fb7 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/csv/Store.java
@@ -263,7 +263,7 @@ final class Store extends URIDataStore implements FeatureSet {
throw new DataStoreContentException(Resources.forLocale(getLocale())
.getString(Resources.Keys.ShallBeDeclaredBefore_2, "@columns", "@stboundedby"));
}
- envelope = parseEnvelope(elements); // Also set 'timeEncoding' and 'spatialDimensionCount'.
+ envelope = parseEnvelope(elements); // Also set `timeEncoding` and `spatialDimensionCount`.
dissociate |= (timeEncoding == null); // Need to be updated before parseFeatureType(…) execution.
break;
}