This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sis.git
commit a7d1c7e0a3ce4b1b1f746df133571a2d9d02ddc4 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Mon Oct 31 12:35:59 2022 +0100 If the unmarshalled operation in <gml:PassThroughOperation> is a defining conversion, complete the conversion. --- .../referencing/CC_GeneralOperationParameter.java | 10 +- .../jaxb/referencing/CC_GeneralParameterValue.java | 2 +- .../jaxb/referencing/CC_OperationMethod.java | 2 +- .../sis/referencing/crs/AbstractDerivedCRS.java | 13 +-- .../operation/AbstractCoordinateOperation.java | 20 +--- .../operation/AbstractSingleOperation.java | 3 +- .../referencing/operation/DefaultConversion.java | 18 ++-- .../operation/DefaultPassThroughOperation.java | 116 +++++++++++++++------ .../apache/sis/referencing/operation/SubTypes.java | 2 +- 9 files changed, 112 insertions(+), 74 deletions(-) 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 bc58625c90..f99929afff 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 @@ -171,12 +171,14 @@ public final class CC_GeneralOperationParameter extends PropertyType<CC_GeneralO * 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 void validate(final GeneralParameterDescriptor descriptor, String property) { + static void validate(final GeneralParameterDescriptor descriptor, final String parent, final String property) { if (descriptor == null || descriptor.getName() == null) { - short key = Errors.Keys.MissingValueForProperty_1; + 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. @@ -185,10 +187,10 @@ public final class CC_GeneralOperationParameter extends PropertyType<CC_GeneralO final String link = ((IdentifiedObject) descriptor).getIdentifierMap().get(IdentifierSpace.XLINK); if (link != null) { key = Errors.Keys.NotABackwardReference_1; - property = link; + args = new String[] {link}; } } - throw new GeodeticException(Errors.format(key, property)); + throw new GeodeticException(Errors.format(key, args)); } } 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 ba45ef344c..b52c4952ff 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 @@ -110,6 +110,6 @@ public final class CC_GeneralParameterValue extends PropertyType<CC_GeneralParam */ public void setElement(final GeneralParameterValue parameter) { metadata = parameter; - CC_GeneralOperationParameter.validate(parameter.getDescriptor(), "<gml:operationParameter>"); + 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 6eb815ffad..ed050b78ba 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 @@ -108,7 +108,7 @@ public final class CC_OperationMethod extends PropertyType<CC_OperationMethod, O */ public void setElement(final DefaultOperationMethod method) { metadata = method; - CC_GeneralOperationParameter.validate(method.getParameters(), "<gml:parameter>"); + CC_GeneralOperationParameter.validate(method.getParameters(), "OperationMethod", "parameter"); } /** 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 e4547697b6..e3b6407963 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/operation/AbstractCoordinateOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java index 589e5f7781..f7db0369b3 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 8d89447e1c..6fa4250a43 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 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 3fff4153d9..1732f7c091 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); } @@ -505,7 +509,7 @@ public class DefaultConversion extends AbstractSingleOperation implements Conver /** * Constructs a new object in which every attributes are 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 reflexion. + * reserved to JAXB, which will assign values to the fields using reflection. */ private DefaultConversion() { } 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 411ea47aab..60749dbaa6 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,36 +19,43 @@ 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.parameter.ParameterValueGroup; import org.opengis.referencing.operation.MathTransform; 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; +import org.opengis.referencing.operation.Conversion; +// Branch-dependent imports import org.opengis.referencing.operation.OperationMethod; import org.opengis.referencing.operation.SingleOperation; + /** * 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 */ @@ -114,9 +121,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; } @@ -223,11 +229,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) { @@ -245,8 +251,8 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp firstAffectedCoordinate += dim; } } - throw new UnsupportedImplementationException(transform.getClass()); } + throw new UnsupportedImplementationException(transform.getClass()); } /** @@ -326,13 +332,13 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp /** * Constructs a new object in which every attributes are 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 reflexion. + * reserved to JAXB, which will assign values to the fields using reflection. */ 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. */ } @@ -358,37 +364,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 f525f8d809..90670bad4b 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 @@ -179,7 +179,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. */