| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.sis.referencing.cs; |
| |
| import java.util.Map; |
| import java.util.EnumMap; |
| import java.util.Arrays; |
| import javax.measure.Unit; |
| import javax.xml.bind.annotation.XmlType; |
| import javax.xml.bind.annotation.XmlElement; |
| import javax.xml.bind.annotation.XmlRootElement; |
| import javax.xml.bind.annotation.XmlSeeAlso; |
| import org.opengis.util.FactoryException; |
| import org.opengis.util.InternationalString; |
| import org.opengis.util.GenericName; |
| import org.opengis.metadata.Identifier; |
| import org.opengis.referencing.cs.AxisDirection; |
| import org.opengis.referencing.cs.CoordinateSystem; |
| import org.opengis.referencing.cs.CoordinateSystemAxis; |
| import org.opengis.referencing.cs.CSAuthorityFactory; |
| import org.opengis.referencing.AuthorityFactory; |
| import org.opengis.geometry.MismatchedDimensionException; |
| import org.apache.sis.metadata.iso.citation.Citations; |
| import org.apache.sis.referencing.AbstractIdentifiedObject; |
| import org.apache.sis.referencing.IdentifiedObjects; |
| import org.apache.sis.referencing.CRS; |
| import org.apache.sis.internal.referencing.WKTUtilities; |
| import org.apache.sis.internal.referencing.AxisDirections; |
| import org.apache.sis.internal.referencing.WKTKeywords; |
| import org.apache.sis.internal.referencing.Resources; |
| import org.apache.sis.internal.system.Modules; |
| import org.apache.sis.internal.util.Constants; |
| import org.apache.sis.io.wkt.ElementKind; |
| import org.apache.sis.io.wkt.Formatter; |
| import org.apache.sis.util.Utilities; |
| import org.apache.sis.util.ComparisonMode; |
| import org.apache.sis.util.logging.Logging; |
| import org.apache.sis.util.resources.Errors; |
| |
| import static org.apache.sis.util.ArgumentChecks.*; |
| |
| |
| /** |
| * The set of {@linkplain DefaultCoordinateSystemAxis coordinate system axes} that spans a given coordinate space. |
| * The type of the coordinate system implies the set of mathematical rules for calculating geometric properties |
| * like angles, distances and surfaces. |
| * |
| * <p>This class is conceptually <cite>abstract</cite>, even if it is technically possible to instantiate it. |
| * Typical applications should create instances of the most specific subclass with {@code Default} prefix instead. |
| * An exception to this rule may occurs when it is not possible to identify the exact type. For example it is not |
| * possible to infer the exact coordinate system from <cite>Well Known Text</cite> (WKT) version 1 in some cases |
| * (e.g. in a {@code LOCAL_CS} element). In such exceptional situation, a plain {@code AbstractCS} object may be |
| * instantiated.</p> |
| * |
| * <h2>Immutability and thread safety</h2> |
| * This base class is immutable and thus thread-safe if the property <em>values</em> (not necessarily the map itself) |
| * and the {@link CoordinateSystemAxis} instances given to the constructor are also immutable. Most SIS subclasses and |
| * related classes are immutable under similar conditions. This means that unless otherwise noted in the javadoc, |
| * {@code CoordinateSystem} instances created using only SIS factories and static constants can be shared by many |
| * objects and passed between threads without synchronization. |
| * |
| * @author Martin Desruisseaux (IRD, Geomatys) |
| * @version 1.0 |
| * |
| * @see DefaultCoordinateSystemAxis |
| * @see org.apache.sis.referencing.crs.AbstractCRS |
| * |
| * @since 0.4 |
| * @module |
| */ |
| @XmlType(name = "AbstractCoordinateSystemType") |
| @XmlRootElement(name = "AbstractCoordinateSystem") |
| @XmlSeeAlso({ |
| DefaultAffineCS.class, |
| DefaultCartesianCS.class, // Not an AffineCS subclass in GML schema. |
| DefaultSphericalCS.class, |
| DefaultEllipsoidalCS.class, |
| DefaultCylindricalCS.class, |
| DefaultPolarCS.class, |
| DefaultLinearCS.class, |
| DefaultVerticalCS.class, |
| DefaultTimeCS.class, |
| DefaultParametricCS.class, |
| DefaultUserDefinedCS.class |
| }) |
| public class AbstractCS extends AbstractIdentifiedObject implements CoordinateSystem { |
| /** |
| * Serial number for inter-operability with different versions. |
| */ |
| private static final long serialVersionUID = 6757665252533744744L; |
| |
| /** |
| * Return value for {@link #validateAxis(AxisDirection, Unit)} |
| */ |
| static final int VALID = 0, INVALID_DIRECTION = 1, INVALID_UNIT = 2; |
| |
| /** |
| * The sequence of axes for this coordinate system. |
| * |
| * <p><b>Consider this field as final!</b> |
| * This field is modified only at unmarshalling time by {@link #setAxis(CoordinateSystemAxis[])}</p> |
| * |
| * @see #getAxis(int) |
| */ |
| private CoordinateSystemAxis[] axes; |
| |
| /** |
| * Other coordinate systems derived from this coordinate systems for other axes conventions. |
| * Created only when first needed. |
| * |
| * @see #forConvention(AxesConvention) |
| */ |
| private transient Map<AxesConvention,AbstractCS> derived; |
| |
| /** |
| * Constructs a coordinate system from a set of properties and a sequence of axes. |
| * The properties map is given unchanged to the |
| * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}. |
| * The following table is a reminder of main (not all) properties: |
| * |
| * <table class="sis"> |
| * <caption>Recognized properties (non exhaustive list)</caption> |
| * <tr> |
| * <th>Property name</th> |
| * <th>Value type</th> |
| * <th>Returned by</th> |
| * </tr> |
| * <tr> |
| * <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td> |
| * <td>{@link Identifier} or {@link String}</td> |
| * <td>{@link #getName()}</td> |
| * </tr> |
| * <tr> |
| * <td>{@value org.opengis.referencing.IdentifiedObject#ALIAS_KEY}</td> |
| * <td>{@link GenericName} or {@link CharSequence} (optionally as array)</td> |
| * <td>{@link #getAlias()}</td> |
| * </tr> |
| * <tr> |
| * <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td> |
| * <td>{@link Identifier} (optionally as array)</td> |
| * <td>{@link #getIdentifiers()}</td> |
| * </tr> |
| * <tr> |
| * <td>{@value org.opengis.referencing.IdentifiedObject#REMARKS_KEY}</td> |
| * <td>{@link InternationalString} or {@link String}</td> |
| * <td>{@link #getRemarks()}</td> |
| * </tr> |
| * </table> |
| * |
| * @param properties the properties to be given to the identified object. |
| * @param axes the sequence of axes. |
| */ |
| @SuppressWarnings("OverridableMethodCallDuringObjectConstruction") |
| public AbstractCS(final Map<String,?> properties, CoordinateSystemAxis... axes) { |
| super(properties); |
| ensureNonNull("axes", axes); |
| this.axes = axes = axes.clone(); |
| for (int i=0; i<axes.length; i++) { |
| final CoordinateSystemAxis axis = axes[i]; |
| ensureNonNullElement("axes", i, axis); |
| final Identifier name = axis.getName(); |
| ensureNonNullElement("axes[#].name", i, name); |
| final AxisDirection direction = axis.getDirection(); |
| ensureNonNullElement("axes[#].direction", i, direction); |
| final Unit<?> unit = axis.getUnit(); |
| ensureNonNullElement("axes[#].unit", i, unit); |
| /* |
| * Ensures that axis direction and units are compatible with the |
| * coordinate system to be created. For example CartesianCS will |
| * accept only linear or dimensionless units. |
| */ |
| switch (validateAxis(direction, unit)) { |
| case INVALID_DIRECTION: { |
| throw new IllegalArgumentException(Resources.forProperties(properties).getString( |
| Resources.Keys.IllegalAxisDirection_2, getClass(), direction)); |
| } |
| case INVALID_UNIT: { |
| throw new IllegalArgumentException(Resources.forProperties(properties).getString( |
| Resources.Keys.IllegalUnitFor_2, name, unit)); |
| } |
| } |
| /* |
| * Ensures there is no axis along the same direction (e.g. two North axes, or an East and a West axis). |
| * An exception to this rule is the time axis, since ISO 19107 explicitly allows compound CRS to have |
| * more than one time axis. Such case happen in meteorological models. |
| */ |
| final AxisDirection dir = AxisDirections.absolute(direction); |
| if (!dir.equals(AxisDirection.OTHER)) { |
| for (int j=i; --j>=0;) { |
| final AxisDirection other = axes[j].getDirection(); |
| final AxisDirection abs = AxisDirections.absolute(other); |
| if (dir.equals(abs) && !abs.equals(AxisDirection.FUTURE)) { |
| throw new IllegalArgumentException(Resources.forProperties(properties).getString( |
| Resources.Keys.ColinearAxisDirections_2, direction, other)); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Creates a new coordinate system with the same values than the specified one. |
| * This copy constructor provides a way to convert an arbitrary implementation into a SIS one |
| * or a user-defined one (as a subclass), usually in order to leverage some implementation-specific API. |
| * |
| * <p>This constructor performs a shallow copy, i.e. the properties are not cloned.</p> |
| * |
| * @param cs the coordinate system to copy. |
| * |
| * @see #castOrCopy(CoordinateSystem) |
| */ |
| protected AbstractCS(final CoordinateSystem cs) { |
| super(cs); |
| axes = (cs instanceof AbstractCS) ? ((AbstractCS) cs).axes : getAxes(cs); |
| } |
| |
| /** |
| * Returns the axes of the given coordinate system. |
| */ |
| private static CoordinateSystemAxis[] getAxes(final CoordinateSystem cs) { |
| final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[cs.getDimension()]; |
| for (int i=0; i<axes.length; i++) { |
| axes[i] = cs.getAxis(i); |
| } |
| return axes; |
| } |
| |
| /** |
| * Returns a SIS coordinate system implementation with the values of the given arbitrary implementation. |
| * This method performs the first applicable action in the following choices: |
| * |
| * <ul> |
| * <li>If the given object is {@code null}, then this method returns {@code null}.</li> |
| * <li>Otherwise if the given object is an instance of |
| * {@link org.opengis.referencing.cs.AffineCS}, |
| * {@link org.opengis.referencing.cs.CartesianCS}, |
| * {@link org.opengis.referencing.cs.SphericalCS}, |
| * {@link org.opengis.referencing.cs.EllipsoidalCS}, |
| * {@link org.opengis.referencing.cs.CylindricalCS}, |
| * {@link org.opengis.referencing.cs.PolarCS}, |
| * {@link org.opengis.referencing.cs.LinearCS}, |
| * {@link org.opengis.referencing.cs.VerticalCS}, |
| * {@link org.opengis.referencing.cs.TimeCS} or |
| * {@link org.opengis.referencing.cs.UserDefinedCS}, |
| * then this method delegates to the {@code castOrCopy(…)} method of the corresponding SIS subclass. |
| * Note that if the given object implements more than one of the above-cited interfaces, |
| * then the {@code castOrCopy(…)} method to be used is unspecified.</li> |
| * <li>Otherwise if the given object is already an instance of |
| * {@code AbstractCS}, then it is returned unchanged.</li> |
| * <li>Otherwise a new {@code AbstractCS} instance is created using the |
| * {@linkplain #AbstractCS(CoordinateSystem) copy constructor} |
| * and returned. Note that this is a <cite>shallow</cite> copy operation, since the other |
| * properties contained in the given object are not recursively copied.</li> |
| * </ul> |
| * |
| * @param object the object to get as a SIS implementation, or {@code null} if none. |
| * @return a SIS implementation containing the values of the given object (may be the |
| * given object itself), or {@code null} if the argument was null. |
| */ |
| public static AbstractCS castOrCopy(final CoordinateSystem object) { |
| return SubTypes.castOrCopy(object); |
| } |
| |
| /** |
| * Returns {@link #VALID} if the given argument values are allowed for an axis in this coordinate system, |
| * or an {@code INVALID_*} error code otherwise. This method is invoked at construction time for checking |
| * argument validity. The default implementation returns {@code VALID} in all cases. Subclasses override |
| * this method in order to put more restrictions on allowed axis directions and check for compatibility |
| * with {@linkplain org.apache.sis.measure.Units#METRE metre} or |
| * {@linkplain org.apache.sis.measure.Units#DEGREE degree} units. |
| * |
| * <p><b>Note for implementers:</b> since this method is invoked at construction time, it shall not depend |
| * on this object's state. This method is not in public API for that reason.</p> |
| * |
| * @param direction the direction to test for compatibility (never {@code null}). |
| * @param unit the unit to test for compatibility (never {@code null}). |
| * @return {@link #VALID} if the given direction and unit are compatible with this coordinate system, |
| * {@link #INVALID_DIRECTION} if the direction is invalid or {@link #INVALID_UNIT} if the unit |
| * is invalid. |
| */ |
| int validateAxis(final AxisDirection direction, final Unit<?> unit) { |
| return VALID; |
| } |
| |
| /** |
| * Returns the GeoAPI interface implemented by this class. |
| * The default implementation returns {@code CoordinateSystem.class}. |
| * Subclasses implementing a more specific GeoAPI interface shall override this method. |
| * |
| * @return the coordinate system interface implemented by this class. |
| */ |
| @Override |
| public Class<? extends CoordinateSystem> getInterface() { |
| return CoordinateSystem.class; |
| } |
| |
| /** |
| * Returns the number of dimensions of this coordinate system. |
| * This is the number of axes given at construction time. |
| * |
| * @return the number of dimensions of this coordinate system. |
| */ |
| @Override |
| public final int getDimension() { |
| return axes.length; |
| } |
| |
| /** |
| * Returns the axis for this coordinate system at the specified dimension. |
| * |
| * @param dimension the zero based index of axis. |
| * @return the axis at the specified dimension. |
| * @throws IndexOutOfBoundsException if {@code dimension} is out of bounds. |
| */ |
| @Override |
| public final CoordinateSystemAxis getAxis(final int dimension) throws IndexOutOfBoundsException { |
| return axes[dimension]; |
| } |
| |
| /** |
| * Returns a coordinate system equivalent to this one but with axes rearranged according the given convention. |
| * If this coordinate system is already compatible with the given convention, then this method returns {@code this}. |
| * |
| * @param convention the axes convention for which a coordinate system is desired. |
| * @return a coordinate system compatible with the given convention (may be {@code this}). |
| * |
| * @see org.apache.sis.referencing.crs.AbstractCRS#forConvention(AxesConvention) |
| */ |
| public synchronized AbstractCS forConvention(final AxesConvention convention) { |
| ensureNonNull("convention", convention); |
| if (derived == null) { |
| derived = new EnumMap<>(AxesConvention.class); |
| } |
| AbstractCS cs = derived.get(convention); |
| if (cs == null) { |
| cs = Normalizer.forConvention(this, convention); |
| if (cs == null) { |
| cs = this; // This coordinate system is already normalized. |
| } else if (convention != AxesConvention.POSITIVE_RANGE) { |
| cs = cs.resolveEPSG(this); |
| } |
| /* |
| * It happen often that the CRS created by RIGHT_HANDED, DISPLAY_ORIENTED and |
| * NORMALIZED are the same. If this is the case, sharing the same instance |
| * not only save memory but can also make future comparisons faster. |
| */ |
| for (final AbstractCS existing : derived.values()) { |
| if (cs.equals(existing)) { |
| cs = existing; |
| break; |
| } |
| } |
| derived.put(convention, cs); |
| } |
| return cs; |
| } |
| |
| /** |
| * Returns a coordinate system usually of the same type than this CS but with different axes. |
| * This method shall be overridden by all {@code AbstractCS} subclasses in this package. |
| * |
| * <p>This method returns a coordinate system of the same type if the number of axes is unchanged. |
| * But if the given {@code axes} array has less elements than this coordinate system dimension, then |
| * this method may return an other kind of coordinate system. See {@link AxisFilter} for an example.</p> |
| * |
| * @param axes the set of axes to give to the new coordinate system. |
| * @return a new coordinate system of the same type than {@code this}, but using the given axes. |
| * @throws IllegalArgumentException if {@code axes} contains an unexpected number of axes, |
| * or if an axis has an unexpected direction or unexpected unit of measurement. |
| */ |
| AbstractCS createForAxes(final Map<String,?> properties, final CoordinateSystemAxis[] axes) { |
| return new AbstractCS(properties, axes); |
| } |
| |
| /** |
| * Verify if we can get a coordinate system from the EPSG database with the same axes. |
| * Such CS gives more information (better name and remarks). This is a "would be nice" |
| * feature; if we fail, we keep the CS built by {@link Normalizer}. |
| * |
| * @param original the coordinate system from which this CS is derived. |
| * @return the resolved CS, or {@code this} if none. |
| */ |
| private AbstractCS resolveEPSG(final AbstractCS original) { |
| if (IdentifiedObjects.getIdentifier(original, Citations.EPSG) != null) { |
| final Integer epsg = CoordinateSystems.getEpsgCode(getInterface(), axes); |
| if (epsg != null) try { |
| final AuthorityFactory factory = CRS.getAuthorityFactory(Constants.EPSG); |
| if (factory instanceof CSAuthorityFactory) { |
| final CoordinateSystem fromDB = ((CSAuthorityFactory) factory).createCoordinateSystem(epsg.toString()); |
| if (fromDB instanceof AbstractCS) { |
| /* |
| * We should compare axes strictly using Arrays.equals(…). However axes in different order |
| * get different codes in EPSG database, which may them not strictly equal. We would need |
| * another comparison mode ignoring only the authority code. We don't add this complexity |
| * for now, and rather rely on the check for EPSG code done by the caller. If the original |
| * CS was an EPSG object, then we assume that we still want an EPSG object here. |
| */ |
| if (Utilities.equalsIgnoreMetadata(axes, ((AbstractCS) fromDB).axes)) { |
| return (AbstractCS) fromDB; |
| } |
| } |
| } |
| } catch (FactoryException e) { |
| /* |
| * NoSuchAuthorityCodeException may happen if factory is EPSGFactoryFallback. |
| * Other exceptions would probably be more serious errors, but it still non-fatal |
| * for this method since we can continue with what Normalizer created. |
| */ |
| Logging.recoverableException(Logging.getLogger(Modules.REFERENCING), getClass(), "forConvention", e); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * Convenience method for implementations of {@link #createForAxes(Map, CoordinateSystemAxis[])} |
| * when the resulting coordinate system would have an unexpected number of dimensions. |
| * |
| * @param properties the properties which was supposed to be given to the constructor. |
| * @param axes the axes which was supposed to be given to the constructor. |
| * @param expected the minimal expected number of dimensions (may be less than {@link #getDimension()}). |
| */ |
| static IllegalArgumentException unexpectedDimension(final Map<String,?> properties, |
| final CoordinateSystemAxis[] axes, final int expected) |
| { |
| return new MismatchedDimensionException(Errors.getResources(properties).getString( |
| Errors.Keys.MismatchedDimension_3, "filter(cs)", expected, axes.length)); |
| } |
| |
| /** |
| * Compares the specified object with this coordinate system for equality. |
| * |
| * @param object the object to compare to {@code this}. |
| * @param mode {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or |
| * {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only |
| * properties relevant to coordinate transformations. |
| * @return {@code true} if both objects are equal. |
| */ |
| @Override |
| @SuppressWarnings("fallthrough") |
| public boolean equals(final Object object, final ComparisonMode mode) { |
| if (object == this) { |
| return true; // Slight optimization. |
| } |
| if (!super.equals(object, mode)) { |
| return false; |
| } |
| switch (mode) { |
| case STRICT: { |
| // No need to check the class - this check has been done by super.equals(…). |
| return Arrays.equals(axes, ((AbstractCS) object).axes); |
| } |
| case DEBUG: { |
| final int d1, d2; |
| assert (d1 = axes.length) == (d2 = ((CoordinateSystem) object).getDimension()) |
| : Errors.format(Errors.Keys.MismatchedDimension_2, d1, d2); |
| // Fall through |
| } |
| default: { |
| final CoordinateSystem that = (CoordinateSystem) object; |
| final int dimension = getDimension(); |
| if (dimension != that.getDimension()) { |
| return false; |
| } |
| if (mode != ComparisonMode.ALLOW_VARIANT) { |
| for (int i=0; i<dimension; i++) { |
| if (!Utilities.deepEquals(getAxis(i), that.getAxis(i), mode)) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| } |
| } |
| |
| /** |
| * Invoked by {@code hashCode()} for computing the hash code when first needed. |
| * See {@link org.apache.sis.referencing.AbstractIdentifiedObject#computeHashCode()} |
| * for more information. |
| * |
| * @return the hash code value. This value may change in any future Apache SIS version. |
| */ |
| @Override |
| protected long computeHashCode() { |
| return super.computeHashCode() + Arrays.hashCode(axes); |
| } |
| |
| /** |
| * Formats the inner part of the <cite>Well Known Text</cite> (WKT) representation of this coordinate system. |
| * This method does <strong>not</strong> format the axes, because they shall appear outside |
| * the {@code CS[…]} element for historical reasons. Axes shall be formatted by the enclosing |
| * element (usually an {@link org.apache.sis.referencing.crs.AbstractCRS}). |
| * |
| * <div class="note"><b>Example:</b> Well-Known Text of a two-dimensional {@code EllipsoidalCS} |
| * having (φ,λ) axes in a unit defined by the enclosing CRS (usually degrees). |
| * |
| * {@preformat wkt |
| * CS[ellipsoidal, 2], |
| * Axis["latitude", north], |
| * Axis["longitude", east] |
| * } |
| * </div> |
| * |
| * <div class="note"><b>Compatibility note:</b> |
| * {@code CS} is defined in the WKT 2 specification only.</div> |
| * |
| * @return {@code "CS"}. |
| * |
| * @see <a href="http://docs.opengeospatial.org/is/12-063r5/12-063r5.html#36">WKT 2 specification §7.5</a> |
| */ |
| @Override |
| protected String formatTo(final Formatter formatter) { |
| final String type = WKTUtilities.toType(CoordinateSystem.class, getInterface()); |
| if (type == null) { |
| formatter.setInvalidWKT(this, null); |
| } |
| formatter.append(type, ElementKind.CODE_LIST); |
| formatter.append(getDimension()); |
| return WKTKeywords.CS; |
| } |
| |
| |
| |
| |
| ////////////////////////////////////////////////////////////////////////////////////////////////// |
| //////// //////// |
| //////// XML support with JAXB //////// |
| //////// //////// |
| //////// The following methods are invoked by JAXB using reflection (even if //////// |
| //////// they are private) or are helpers for other methods invoked by JAXB. //////// |
| //////// Those methods can be safely removed if Geographic Markup Language //////// |
| //////// (GML) support is not needed. //////// |
| //////// //////// |
| ////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| /** |
| * An empty array of axes, used only for JAXB. |
| */ |
| private static final CoordinateSystemAxis[] EMPTY = new CoordinateSystemAxis[0]; |
| |
| /** |
| * Constructs a new object in which every attributes are set to a null or empty 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. |
| */ |
| AbstractCS() { |
| super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE); |
| axes = EMPTY; |
| /* |
| * Coordinate system axes are mandatory for SIS working. We do not verify their 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 CS_CoordinateSystem |
| * adapter does some verifications. |
| */ |
| } |
| |
| /** |
| * Invoked by JAXB at marshalling time. |
| */ |
| @XmlElement(name = "axis") |
| private CoordinateSystemAxis[] getAxis() { |
| return getAxes(this); // Give a chance to users to override getAxis(int). |
| } |
| |
| /** |
| * Invoked by JAXB at unmarshalling time. |
| */ |
| @SuppressWarnings("AssignmentToCollectionOrArrayFieldFromParameter") |
| private void setAxis(final CoordinateSystemAxis[] values) { |
| axes = values; |
| } |
| } |