Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -40,7 +40,6 @@ import org.opengis.metadata.citation.Cit import org.opengis.referencing.ObjectFactory; import org.opengis.referencing.AuthorityFactory; import org.opengis.referencing.IdentifiedObject; -import org.apache.sis.internal.metadata.NameMeaning; import org.apache.sis.internal.jaxb.Context; import org.apache.sis.internal.jaxb.referencing.Code; import org.apache.sis.internal.util.Numerics; @@ -48,7 +47,6 @@ import org.apache.sis.internal.util.Unmo import org.apache.sis.internal.metadata.NameToIdentifier; import org.apache.sis.internal.referencing.WKTUtilities; import org.apache.sis.internal.referencing.ReferencingUtilities; -import org.apache.sis.internal.referencing.NilReferencingObject; import org.apache.sis.internal.system.DefaultFactories; import org.apache.sis.io.wkt.FormattableObject; import org.apache.sis.io.wkt.Formatter; @@ -67,7 +65,6 @@ import static org.apache.sis.util.Utilit import static org.apache.sis.internal.util.CollectionsExt.nonNull; import static org.apache.sis.internal.util.CollectionsExt.nonEmpty; import static org.apache.sis.internal.util.CollectionsExt.immutableSet; -import static org.apache.sis.internal.util.Utilities.appendUnicodeIdentifier; // Branch-dependent imports import org.opengis.referencing.ReferenceIdentifier; @@ -128,7 +125,7 @@ import org.apache.sis.internal.jdk7.Obje * @version 0.7 * @module */ -@XmlType(name="IdentifiedObjectType", propOrder={ +@XmlType(name = "IdentifiedObjectType", propOrder = { "description", "identifier", "names", @@ -208,9 +205,13 @@ public class AbstractIdentifiedObject ex /** * Comments on or information about this object, or {@code null} if none. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setRemarks(InternationalString)}</p> + * + * @see #getRemarks() */ - @XmlElement - private final InternationalString remarks; + private InternationalString remarks; /** * {@code true} if this object is deprecated. @@ -526,7 +527,7 @@ public class AbstractIdentifiedObject ex * * @since 0.6 */ - @XmlElement + @XmlElement(name = "description") public InternationalString getDescription() { final ReferenceIdentifier name = getName(); if (name instanceof ImmutableIdentifier) { @@ -546,7 +547,8 @@ public class AbstractIdentifiedObject ex * @return The remarks, or {@code null} if none. */ @Override - public InternationalString getRemarks(){ + @XmlElement(name = "remarks") + public InternationalString getRemarks() { return remarks; } @@ -900,17 +902,16 @@ public class AbstractIdentifiedObject ex * reserved to JAXB, which will assign values to the fields using reflexion. */ AbstractIdentifiedObject() { - remarks = null; deprecated = false; } /** * The {@code gml:id}, which is mandatory. The current implementation searches for the first identifier, - * regardless its authority. If no identifier is found, then the name is used. - * If no name is found (which should not occur for valid objects), then this method returns {@code null}. + * regardless its authority. If no identifier is found, then the name or aliases are used. If none of the + * above is found (which should not occur for valid objects), then this method returns {@code null}. * - * <p>If an identifier has been found, this method returns the concatenation of the following elements - * separated by hyphens:</p> + * <p>If an identifier or a name has been found, this method returns the concatenation of the following + * elements separated by hyphens:</p> * <ul> * <li>The code space in lower case, retaining only characters that are valid for Unicode identifiers.</li> * <li>The object type as defined in OGC's URN (see {@link org.apache.sis.internal.util.DefinitionURI})</li> @@ -928,59 +929,9 @@ public class AbstractIdentifiedObject ex @XmlAttribute(name = "id", namespace = Namespaces.GML, required = true) @XmlJavaTypeAdapter(CollapsedStringAdapter.class) final String getID() { - final Context context = Context.current(); - String candidate = Context.getObjectID(context, this); - if (candidate == null) { - final StringBuilder id = new StringBuilder(); - /* - * We will iterate over the identifiers first. Only after the iteration is over, - * if we found no suitable ID, then we will use the primary name as a last resort. - */ - if (identifiers != null) { - for (final ReferenceIdentifier identifier : identifiers) { - if (appendUnicodeIdentifier(id, '-', identifier.getCodeSpace(), ":", true) | // Really |, not || - appendUnicodeIdentifier(id, '-', NameMeaning.toObjectType(getClass()), ":", false) | - appendUnicodeIdentifier(id, '-', identifier.getCode(), ":", true)) - { - /* - * Check for ID uniqueness. If the ID is rejected, then we just need to clear - * the buffer and let the iteration continue the search for another ID. - */ - candidate = id.toString(); - if (Context.setObjectForID(context, this, candidate)) { - return candidate; - } - } - id.setLength(0); // Clear the buffer for another try. - } - } - /* - * In last ressort, use the name or an alias. The name will be used without codespace since - * names are often verbose. If that name is also used, append a number until we find a free ID. - */ - if (name == null || !appendUnicodeIdentifier(id, '-', name.getCode(), ":", false)) { - if (alias != null) { - for (final GenericName a : alias) { - if (appendUnicodeIdentifier(id, '-', a.toString(), ":", false)) { - break; - } - } - } - } - if (id.length() != 0) { - candidate = id.toString(); - if (!Context.setObjectForID(context, this, candidate)) { - final int s = id.append('-').length(); - int n = 0; - do { - if (++n == 100) return null; // Arbitrary limit. - candidate = id.append(n).toString(); - id.setLength(s); - } while (!Context.setObjectForID(context, this, candidate)); - } - } - } - return candidate; + // Implementation is provided in the NameIterator class for reducing the size of + // AbstractIdentifiedObject.class file in the common case where XML is not needed. + return NameIterator.getID(Context.current(), this, name, alias, identifiers); } /** @@ -1009,7 +960,7 @@ public class AbstractIdentifiedObject ex * <li>The first identifier, converted to the {@code "urn:} syntax if possible.</li> * </ul> */ - @XmlElement(name = "identifier") + @XmlElement(required = true) final Code getIdentifier() { return Code.forIdentifiedObject(getClass(), identifiers); } @@ -1057,6 +1008,13 @@ public class AbstractIdentifiedObject ex * by all {@linkplain AbstractIdentifiedObject#getAlias() aliases} which are instance of {@link Identifier}. * Used by JAXB only at (un)marshalling time because GML merges the name and aliases in a single {@code <gml:name>} * property. + * + * <div class="section">Why we do not use {@code Identifier[]} array instead</div> + * It would be easier to define a {@code getNames()} method returning all identifiers in an array, and let JAXB + * invoke {@code setNames(Identifier[])} at unmarshalling time. But methods expecting an array in argument are + * invoked by JAXB only after the full element has been unmarshalled. For some {@code AbstractIdentifiedObject} + * subclasses, this is too late. For example {@code DefaultOperationMethod} may need to know the operation name + * before to parse the parameters. */ private final class Names extends AbstractCollection<ReferenceIdentifier> { /** @@ -1094,46 +1052,51 @@ public class AbstractIdentifiedObject ex */ @Override public boolean add(final ReferenceIdentifier id) { - addName(id); + if (NameIterator.isUnnamed(name)) { + name = id; + } else { + /* + * Our Code and RS_Identifier implementations should always create NamedIdentifier instance, + * so the 'instanceof' check should not be necessary. But we do a paranoiac check anyway. + */ + final GenericName n = id instanceof GenericName ? (GenericName) id : new NamedIdentifier(id); + if (alias == null) { + alias = Collections.singleton(n); + } else { + /* + * This implementation is inefficient since each addition copies the array, but we rarely + * have more than two aliases. This implementation is okay for a small number of aliases + * and ensures that the enclosing AbstractIdentifiedObject is unmodifiable except by this + * add(…) method. + * + * Note about alternative approaches + * --------------------------------- + * An alternative approach could be to use an ArrayList and replace it by an unmodifiable + * list only after unmarshalling (using an afterUnmarshal(Unmarshaller, Object) method), + * but we want to avoid Unmarshaller dependency (for reducing classes loading for users + * who are not interrested in XML) and it may actually be less efficient for the vast + * majority of cases where there is less than 3 aliases. + */ + final int size = alias.size(); + final GenericName[] names = alias.toArray(new GenericName[size + 1]); + names[size] = n; + alias = UnmodifiableArrayList.wrap(names); + } + } return true; } } /** - * Implementation of {@link Names#add(Identifier)}, defined in the enclosing class - * for access to private fields without compiler-generated bridge methods. + * Invoked by JAXB for setting the remarks. + * + * @see #getRemarks() */ - final void addName(final ReferenceIdentifier id) { - if (name == NilReferencingObject.UNNAMED) { - name = id; + private void setRemarks(final InternationalString value) { + if (remarks == null) { + remarks = value; } else { - /* - * Our Code and RS_Identifier implementations should always create NamedIdentifier instance, - * so the 'instanceof' check should not be necessary. But we do a paranoiac check anyway. - */ - final GenericName n = id instanceof GenericName ? (GenericName) id : new NamedIdentifier(id); - if (alias == null) { - alias = Collections.singleton(n); - } else { - /* - * This implementation is inefficient since each addition copies the array, but we rarely - * have more than two aliases. This implementation is okay for a small number of aliases - * and ensures that the enclosing AbstractIdentifiedObject is unmodifiable except by this - * add(…) method. - * - * Note about alternative approaches - * --------------------------------- - * An alternative approach could be to use an ArrayList and replace it by an unmodifiable - * list only after unmarshalling (using an afterUnmarshal(Unmarshaller, Object) method), - * but we want to avoid Unmarshaller dependency (for reducing classes loading for users - * who are not interrested in XML) and it may actually be less efficient for the vast - * majority of cases where there is less than 3 aliases. - */ - final int size = alias.size(); - final GenericName[] names = alias.toArray(new GenericName[size + 1]); - names[size] = n; - alias = UnmodifiableArrayList.wrap(names); - } + ReferencingUtilities.propertyAlreadySet(AbstractIdentifiedObject.class, "setRemarks", "remarks"); } } }
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractReferenceSystem.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -19,13 +19,17 @@ package org.apache.sis.referencing; import java.util.Map; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlTransient; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.opengis.util.GenericName; import org.opengis.util.InternationalString; import org.opengis.referencing.ReferenceSystem; import org.opengis.referencing.ReferenceIdentifier; import org.opengis.metadata.extent.Extent; +import org.apache.sis.util.Workaround; import org.apache.sis.util.ComparisonMode; import org.apache.sis.util.iso.Types; +import org.apache.sis.internal.jaxb.metadata.EX_Extent; +import org.apache.sis.internal.referencing.ReferencingUtilities; import static org.apache.sis.util.Utilities.deepEquals; import static org.apache.sis.util.collection.Containers.property; @@ -62,7 +66,7 @@ import org.apache.sis.internal.jdk7.Obje * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ @XmlTransient @@ -75,18 +79,23 @@ public class AbstractReferenceSystem ext /** * Area for which the (coordinate) reference system is valid. * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDomainOfValidity(Extent)}</p> + * * @see #getDomainOfValidity() */ - private final Extent domainOfValidity; + private Extent domainOfValidity; /** * Description of domain of usage, or limitations of usage, * for which this (coordinate) reference system object is valid. * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setScope(InternationalString)}</p> + * * @see #getScope() */ - @XmlElement(required = true) - private final InternationalString scope; + private InternationalString scope; /** * Constructs a reference system from the given properties. @@ -172,14 +181,17 @@ public class AbstractReferenceSystem ext } /** - * Returns the region or timeframe in which this reference system is valid, - * or {@code null} if unspecified. + * Returns the region or timeframe in which this reference system is valid, or {@code null} if unspecified. * * @return Area or region or timeframe in which this (coordinate) reference system is valid, or {@code null}. * * @see org.apache.sis.metadata.iso.extent.DefaultExtent */ @Override + @XmlElement(name = "domainOfValidity") + // For an unknown reason, JAXB does not take the adapter declared in package-info for this particular property. + @Workaround(library = "JDK", version = "1.8") + @XmlJavaTypeAdapter(EX_Extent.class) public Extent getDomainOfValidity() { return domainOfValidity; } @@ -191,6 +203,7 @@ public class AbstractReferenceSystem ext * (coordinate) reference system object is valid, or {@code null}. */ @Override + @XmlElement(name ="scope", required = true) public InternationalString getScope() { return scope; } @@ -263,7 +276,31 @@ public class AbstractReferenceSystem ext * reserved to JAXB, which will assign values to the fields using reflexion. */ AbstractReferenceSystem() { - domainOfValidity = null; - scope = null; + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getDomainOfValidity() + */ + private void setDomainOfValidity(final Extent value) { + if (domainOfValidity == null) { + domainOfValidity = value; + } else { + ReferencingUtilities.propertyAlreadySet(AbstractReferenceSystem.class, "setDomainOfValidity", "domainOfValidity"); + } + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getScope() + */ + private void setScope(final InternationalString value) { + if (scope == null) { + scope = value; + } else { + ReferencingUtilities.propertyAlreadySet(AbstractReferenceSystem.class, "setScope", "scope"); + } } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -37,7 +37,7 @@ import org.apache.sis.util.iso.Types; import org.apache.sis.util.Deprecable; import org.apache.sis.util.resources.Errors; -import static org.apache.sis.util.ArgumentChecks.ensureNonNull; +import static org.apache.sis.util.ArgumentChecks.*; // Branch-dependent imports import org.apache.sis.internal.jdk8.JDK8; @@ -754,32 +754,40 @@ public abstract class Builder<B extends int next = 0; int insertAt = aliases.size(); for (int i = -1; i < aliases.size(); i++) { - final Object name = (i < 0) ? properties.get(IdentifiedObject.NAME_KEY) : aliases.get(i); - if (name != null) { // Actually only the primary name can be null. - final boolean isIdentifier = (name instanceof Identifier); - if (authority.equals(isIdentifier ? ((Identifier) name).getAuthority() : getAuthority())) { - /* - * Found a name associated to the given authority. Process to the replacement if we still - * have some elements to take in the 'replacements' array, otherwise remove the name. - */ - if (next < length) { - final CharSequence code = replacements[next++]; - if (!code.toString().equals(isIdentifier ? ((Identifier) name).getCode() : name.toString())) { - if (i < 0) { - properties.put(IdentifiedObject.NAME_KEY, (authority != getAuthority()) - ? new NamedIdentifier(authority, code) : code.toString()); - } else { - aliases.set(i, createName(authority, code)); - } - insertAt = i + 1; - } + final Object old = (i < 0) ? properties.get(IdentifiedObject.NAME_KEY) : aliases.get(i); + if (old == null) { + continue; // Actually only the primary name can be null. + } + final boolean wasID = (old instanceof Identifier); // Usually true even for aliases. + if (!authority.equals(wasID ? ((Identifier) old).getAuthority() : getAuthority())) { + continue; // Current name is not for the authority we are looking for. + } + /* + * Found a name associated to the given authority. Process to the replacement if we still + * have some elements to take in the 'replacements' array, otherwise remove the name. + */ + if (next < length) { + final CharSequence name; + ensureNonNullElement("replacements", next, name = replacements[next++]); + /* + * If the current name matches the specified replacement, we can leave the name as-is. + * Only if the name (in its local part) is not the same, proceed to the replacement. + */ + final String code = name.toString(); + if (!code.equals(wasID ? ((Identifier) old).getCode() : old.toString())) { + if (i < 0) { + properties.put(IdentifiedObject.NAME_KEY, + (authority != getAuthority()) ? new NamedIdentifier(authority, name) : code); } else { - if (i < 0) { - properties.remove(IdentifiedObject.NAME_KEY); - } else { - aliases.remove(i--); - } + aliases.set(i, createName(authority, name)); } + insertAt = i + 1; + } + } else { + if (i < 0) { + properties.remove(IdentifiedObject.NAME_KEY); + } else { + aliases.remove(i--); } } } @@ -788,7 +796,9 @@ public abstract class Builder<B extends * element of the given authority that we found (so we keep together the names of the same authority). */ while (next < length) { - aliases.add(insertAt++, createName(authority, replacements[next++])); + final CharSequence name; + ensureNonNullElement("replacements", next, name = replacements[next++]); + aliases.add(insertAt++, createName(authority, name)); } /* * If the primary name has been removed as a result of this method execution, Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -17,24 +17,29 @@ package org.apache.sis.referencing; import java.util.Iterator; +import java.util.Collection; import org.opengis.util.GenericName; import org.opengis.referencing.IdentifiedObject; import org.opengis.referencing.ReferenceIdentifier; +import org.apache.sis.internal.jaxb.Context; +import org.apache.sis.internal.metadata.NameMeaning; import org.apache.sis.internal.referencing.NilReferencingObject; +import static org.apache.sis.internal.util.Utilities.appendUnicodeIdentifier; + /** * An iterator over the {@linkplain IdentifiedObject#getName() name} of an identified object followed by * {@linkplain IdentifiedObject#getAlias() aliases} which are instance of {@link ReferenceIdentifier}. - * This iterator is used for {@link AbstractIdentifiedObject} marshalling because GML merges the name and - * aliases in a single {@code <gml:name>} property. + * This iterator is used for {@link AbstractIdentifiedObject} XML marshalling because GML merges the name + * and aliases in a single {@code <gml:name>} property. However this iterator is useful only if the aliases + * are instances of {@link NamedIdentifier}, or any other implementation which is both a name and an identifier. * - * <p>Note that this iterator is useful only if the aliases are instances of {@link NamedIdentifier}, - * or any other implementation which is both a name and an identifier.</p> + * <p>This class also opportunistically provide helper methods for {@link AbstractIdentifiedObject} marshalling.</p> * * @author Martin Desruisseaux (Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ final class NameIterator implements Iterator<ReferenceIdentifier> { @@ -55,12 +60,19 @@ final class NameIterator implements Iter alias = object.getAlias().iterator(); next = object.getName(); // Should never be null in a well-formed IdentifiedObject, but let be safe. - if (next == null || next == NilReferencingObject.UNNAMED) { + if (isUnnamed(next)) { next(); } } /** + * Returns {@code true} if the given identifier is null or the {@link NilReferencingObject#UNNAMED} instance. + */ + static boolean isUnnamed(final ReferenceIdentifier name) { + return (name == null) || (name == NilReferencingObject.UNNAMED); + } + + /** * Returns {@code true} if there is an other name or alias to return. */ @Override @@ -108,4 +120,87 @@ final class NameIterator implements Iter } return c; } + + /** + * Implementation of {@link AbstractIdentifiedObject#getID()}, provided here for reducing the amount of code + * to load in the common case where XML support is not needed. + * + * <p>The current implementation searches for the first identifier, regardless its authority. + * If no identifier is found, then the name and aliases are used. + * Then, this method returns the concatenation of the following elements separated by hyphens:</p> + * <ul> + * <li>The code space in lower case, retaining only characters that are valid for Unicode identifiers.</li> + * <li>The object type as defined in OGC's URN (see {@link org.apache.sis.internal.util.DefinitionURI})</li> + * <li>The object code, retaining only characters that are valid for Unicode identifiers.</li> + * </ul> + * + * Example: {@code "epsg-crs-4326"}. + * + * <p>The returned ID needs to be unique only in the XML document being marshalled. + * Consecutive invocations of this method do not need to return the same value, + * since it may depends on the marshalling context.</p> + * + * @param context The (un)marshalling context. + * @param object The object for which to get a {@code gml:id}. + * @param name The identified object name, or {@code null} if none. + * @param alias The identified object aliases, or {@code null} if none. + * @param identifiers The identifiers, or {@code null} if none. + * @return Proposed value for {@code gml:id} attribute, or {@code null} if none. + */ + static String getID(final Context context, final IdentifiedObject object, final ReferenceIdentifier name, + final Collection<? extends GenericName> alias, final Collection<? extends ReferenceIdentifier> identifiers) + { + String candidate = Context.getObjectID(context, object); + if (candidate == null) { + final StringBuilder id = new StringBuilder(); + /* + * We will iterate over the identifiers first. Only after the iteration is over, + * if we found no suitable ID, then we will use the primary name as a last resort. + */ + if (identifiers != null) { + for (final ReferenceIdentifier identifier : identifiers) { + if (appendUnicodeIdentifier(id, '-', identifier.getCodeSpace(), ":", true) | // Really |, not || + appendUnicodeIdentifier(id, '-', NameMeaning.toObjectType(object.getClass()), ":", false) | + appendUnicodeIdentifier(id, '-', identifier.getCode(), ":", true)) + { + /* + * Check for ID uniqueness. If the ID is rejected, then we just need to clear + * the buffer and let the iteration continue the search for another ID. + */ + candidate = id.toString(); + if (Context.setObjectForID(context, object, candidate)) { + return candidate; + } + } + id.setLength(0); // Clear the buffer for another try. + } + } + /* + * In last ressort, use the name or an alias. The name will be used without codespace since + * names are often verbose. If that name is also used, append a number until we find a free ID. + */ + if (isUnnamed(name) || !appendUnicodeIdentifier(id, '-', name.getCode(), ":", false)) { + if (alias != null) { + for (final GenericName a : alias) { + if (appendUnicodeIdentifier(id, '-', a.toString(), ":", false)) { + break; + } + } + } + } + if (id.length() != 0) { + candidate = id.toString(); + if (!Context.setObjectForID(context, object, candidate)) { + final int s = id.append('-').length(); + int n = 0; + do { + if (++n == 100) return null; // Arbitrary limit. + candidate = id.append(n).toString(); + id.setLength(s); + } while (!Context.setObjectForID(context, object, candidate)); + } + } + } + return candidate; + } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -80,13 +80,16 @@ import org.apache.sis.internal.jdk7.Obje * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module * * @see AbstractCS * @see org.apache.sis.referencing.datum.AbstractDatum */ -@XmlType(name="AbstractCRSType") +@XmlType(name = "AbstractCRSType", propOrder = { + "domainOfValidity", + "scope" +}) @XmlRootElement(name = "AbstractCRS") @XmlSeeAlso({ AbstractDerivedCRS.class, @@ -511,6 +514,12 @@ public class AbstractCRS extends Abstrac */ AbstractCRS() { super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE); + /* + * The coordinate system 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 SC_CRS adapter + * does some verifications. + */ } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -59,7 +59,7 @@ import static org.apache.sis.util.Utilit * @version 0.6 * @module */ -@XmlType(name="AbstractGeneralDerivedCRSType") +@XmlType(name = "AbstractGeneralDerivedCRSType") @XmlRootElement(name = "AbstractGeneralDerivedCRS") @XmlSeeAlso({ DefaultDerivedCRS.class, @@ -312,7 +312,7 @@ abstract class AbstractDerivedCRS<C exte ReferencingUtilities.propertyAlreadySet(AbstractDerivedCRS.class, "setBaseCRS", name); } } else { - throw new IllegalStateException(Errors.format(Errors.Keys.MissingValueForProperty_1, "conversion")); + throw new IllegalStateException(Errors.format(Errors.Keys.MissingComponentInElement_2, getInterface(), "conversion")); } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultCompoundCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -20,6 +20,7 @@ import java.util.Map; import java.util.List; import java.util.Arrays; import java.util.ArrayList; +import java.util.Collections; import java.io.IOException; import java.io.ObjectInputStream; import javax.xml.bind.annotation.XmlType; @@ -112,7 +113,7 @@ import static org.apache.sis.internal.re * @version 0.7 * @module */ -@XmlType(name="CompoundCRSType") +@XmlType(name = "CompoundCRSType") @XmlRootElement(name = "CompoundCRS") public class DefaultCompoundCRS extends AbstractCRS implements CompoundCRS { /** @@ -341,6 +342,7 @@ public class DefaultCompoundCRS extends @SuppressWarnings("unchecked") private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); + final List<? extends CoordinateReferenceSystem> components = this.components; if (components instanceof CheckedContainer<?>) { final Class<?> type = ((CheckedContainer<?>) components).getElementType(); if (type == SingleCRS.class) { @@ -538,13 +540,11 @@ public class DefaultCompoundCRS extends crs = getSingleComponents(); isStandardCompliant = isStandardCompliant(crs); } - if (crs != null) { // Should never be null, except e.g. if unmarshalling invalid GML. - for (final CoordinateReferenceSystem element : crs) { - formatter.newLine(); - formatter.append(toFormattable(element)); - } - formatter.newLine(); // For writing the ID[…] element on its own line. + for (final CoordinateReferenceSystem element : crs) { + formatter.newLine(); + formatter.append(toFormattable(element)); } + formatter.newLine(); // For writing the ID[…] element on its own line. if (!isStandardCompliant) { formatter.setInvalidWKT(this, null); } @@ -566,11 +566,19 @@ public class DefaultCompoundCRS extends ////////////////////////////////////////////////////////////////////////////////////////////////// /** - * 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. + * 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. */ private DefaultCompoundCRS() { + components = Collections.emptyList(); + singles = Collections.emptyList(); + /* + * At least one component CRS is 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 SC_CRS adapter does + * some verifications (indirectly, by testing for coordinate system existence). + */ } /** @@ -590,7 +598,7 @@ public class DefaultCompoundCRS extends @XmlElement(name = "componentReferenceSystem", required = true) private CoordinateReferenceSystem[] getXMLComponents() { final List<SingleCRS> crs = getSingleComponents(); - return (crs != null) ? crs.toArray(new CoordinateReferenceSystem[crs.size()]) : null; + return crs.toArray(new CoordinateReferenceSystem[crs.size()]); } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -452,7 +452,7 @@ public class DefaultDerivedCRS extends A * @return The coordinate system. */ @Override - @XmlElement(name="coordinateSystem", required = true) + @XmlElement(name = "coordinateSystem", required = true) @XmlJavaTypeAdapter(CS_CoordinateSystem.class) public CoordinateSystem getCoordinateSystem() { return super.getCoordinateSystem(); Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultEngineeringCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -26,6 +26,7 @@ import org.opengis.referencing.crs.Engin import org.opengis.referencing.datum.EngineeringDatum; import org.apache.sis.referencing.cs.*; import org.apache.sis.referencing.AbstractReferenceSystem; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.internal.metadata.WKTKeywords; import org.apache.sis.io.wkt.Formatter; @@ -58,7 +59,7 @@ import static org.apache.sis.util.Argume * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module */ @XmlType(name = "EngineeringCRSType", propOrder = { @@ -74,9 +75,13 @@ public class DefaultEngineeringCRS exten /** * The datum. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDatum(EngineeringDatum)}</p> + * + * @see #getDatum() */ - @XmlElement(name = "engineeringDatum", required = true) - private final EngineeringDatum datum; + private EngineeringDatum datum; /** * Creates a coordinate reference system from the given properties, datum and coordinate system. @@ -189,7 +194,8 @@ public class DefaultEngineeringCRS exten * @return The datum. */ @Override - public final EngineeringDatum getDatum() { + @XmlElement(name = "engineeringDatum", required = true) + public EngineeringDatum getDatum() { return datum; } @@ -265,7 +271,25 @@ public class DefaultEngineeringCRS exten * reserved to JAXB, which will assign values to the fields using reflexion. */ private DefaultEngineeringCRS() { - datum = null; + /* + * The datum and the coordinate system 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 SC_CRS adapter does some + * verifications. + */ + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getDatum() + */ + private void setDatum(final EngineeringDatum value) { + if (datum == null) { + datum = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultEngineeringCRS.class, "setDatum", "engineeringDatum"); + } } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeodeticCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -55,7 +55,7 @@ import static org.apache.sis.util.Argume * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ @XmlType(name = "GeodeticCRSType", propOrder = { @@ -73,9 +73,13 @@ class DefaultGeodeticCRS extends Abstrac /** * The datum. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDatum(GeodeticDatum)}</p> + * + * @see #getDatum() */ - @XmlElement(name = "geodeticDatum", required = true) - private final GeodeticDatum datum; + private GeodeticDatum datum; /** * Creates a coordinate reference system from the given properties, datum and coordinate system. @@ -126,13 +130,15 @@ class DefaultGeodeticCRS extends Abstrac /** * Returns the datum. * - * This method is overridden is subclasses for documentation purpose only, mostly for showing this method in - * the appropriate position in javadoc (instead than at the bottom of the page). If {@code DefaultGeodeticCRS} - * is made public in a future SIS version, then we should make this method final and remove the overridden methods. + * This method is overridden is subclasses for documentation purpose only, mostly for showing + * this method in the appropriate position in javadoc (instead than at the bottom of the page). + * If {@code DefaultGeodeticCRS} is made public in a future SIS version, then we could remove + * the overridden methods. * * @return The datum. */ @Override + @XmlElement(name = "geodeticDatum", required = true) public GeodeticDatum getDatum() { return datum; } @@ -251,7 +257,25 @@ class DefaultGeodeticCRS extends Abstrac * reserved to JAXB, which will assign values to the fields using reflexion. */ DefaultGeodeticCRS() { - datum = null; + /* + * The datum and the coordinate system 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 SC_CRS adapter does some + * verifications. + */ + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getDatum() + */ + private void setDatum(final GeodeticDatum value) { + if (datum == null) { + datum = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultGeodeticCRS.class, "setDatum", "geodeticDatum"); + } } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultImageCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -26,6 +26,7 @@ import org.opengis.referencing.crs.Image import org.opengis.referencing.cs.CartesianCS; import org.opengis.referencing.datum.ImageDatum; import org.apache.sis.internal.metadata.WKTKeywords; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.referencing.cs.AxesConvention; import org.apache.sis.referencing.AbstractReferenceSystem; import org.apache.sis.io.wkt.Formatter; @@ -50,7 +51,7 @@ import static org.apache.sis.util.Argume * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ @XmlType(name = "ImageCRSType", propOrder = { @@ -67,9 +68,13 @@ public class DefaultImageCRS extends Abs /** * The datum. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDatum(ImageDatum)}</p> + * + * @see #getDatum() */ - @XmlElement(name = "imageDatum", required = true) - private final ImageDatum datum; + private ImageDatum datum; /** * Creates a coordinate reference system from the given properties, datum and coordinate system. @@ -182,7 +187,8 @@ public class DefaultImageCRS extends Abs * @return The datum. */ @Override - public final ImageDatum getDatum() { + @XmlElement(name = "imageDatum", required = true) + public ImageDatum getDatum() { return datum; } @@ -253,7 +259,25 @@ public class DefaultImageCRS extends Abs * reserved to JAXB, which will assign values to the fields using reflexion. */ private DefaultImageCRS() { - datum = null; + /* + * The datum and the coordinate system 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 SC_CRS adapter does some + * verifications. + */ + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getDatum() + */ + private void setDatum(final ImageDatum value) { + if (datum == null) { + datum = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultImageCRS.class, "setDatum", "imageDatum"); + } } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -256,7 +256,7 @@ public class DefaultProjectedCRS extends * Returns the coordinate system. */ @Override - @XmlElement(name="cartesianCS", required = true) + @XmlElement(name = "cartesianCS", required = true) public final CartesianCS getCoordinateSystem() { // See AbstractDerivedCRS.createConversionFromBase(…) for // an explanation about why this method is declared final. Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultTemporalCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -29,6 +29,7 @@ import org.opengis.referencing.crs.Tempo import org.opengis.referencing.datum.TemporalDatum; import org.apache.sis.referencing.cs.AxesConvention; import org.apache.sis.referencing.AbstractReferenceSystem; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.internal.metadata.WKTKeywords; import org.apache.sis.io.wkt.Formatter; import org.apache.sis.measure.Units; @@ -56,7 +57,7 @@ import static org.apache.sis.util.Argume * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module * * @see org.apache.sis.referencing.datum.DefaultTemporalDatum @@ -75,9 +76,13 @@ public class DefaultTemporalCRS extends /** * The datum. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDatum(TemporalDatum)}</p> + * + * @see #getDatum() */ - @XmlElement(name = "temporalDatum", required = true) - private final TemporalDatum datum; + private TemporalDatum datum; /** * A converter from values in this CRS to values in milliseconds. @@ -211,7 +216,8 @@ public class DefaultTemporalCRS extends * @return The datum. */ @Override - public final TemporalDatum getDatum() { + @XmlElement(name = "temporalDatum", required = true) + public TemporalDatum getDatum() { return datum; } @@ -321,7 +327,25 @@ public class DefaultTemporalCRS extends * reserved to JAXB, which will assign values to the fields using reflexion. */ private DefaultTemporalCRS() { - datum = null; + /* + * The datum and the coordinate system 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 SC_CRS adapter does some + * verifications. + */ + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getDatum() + */ + private void setDatum(final TemporalDatum value) { + if (datum == null) { + datum = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultVerticalCRS.class, "setDatum", "temporalDatum"); + } } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultVerticalCRS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -27,6 +27,7 @@ import org.opengis.referencing.datum.Ver import org.apache.sis.referencing.cs.AxesConvention; import org.apache.sis.referencing.AbstractReferenceSystem; import org.apache.sis.internal.metadata.WKTKeywords; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.io.wkt.Formatter; import static org.apache.sis.util.ArgumentChecks.ensureNonNull; @@ -48,7 +49,7 @@ import static org.apache.sis.util.Argume * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module * * @see org.apache.sis.referencing.datum.DefaultVerticalDatum @@ -67,9 +68,13 @@ public class DefaultVerticalCRS extends /** * The datum. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDatum(VerticalDatum)}</p> + * + * @see #getDatum() */ - @XmlElement(name = "verticalDatum", required = true) - private final VerticalDatum datum; + private VerticalDatum datum; /** * Creates a coordinate reference system from the given properties, datum and coordinate system. @@ -182,7 +187,8 @@ public class DefaultVerticalCRS extends * @return The datum. */ @Override - public final VerticalDatum getDatum() { + @XmlElement(name = "verticalDatum", required = true) + public VerticalDatum getDatum() { return datum; } @@ -250,7 +256,25 @@ public class DefaultVerticalCRS extends * reserved to JAXB, which will assign values to the fields using reflexion. */ private DefaultVerticalCRS() { - datum = null; + /* + * The datum and the coordinate system 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 SC_CRS adapter does some + * verifications. + */ + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getDatum() + */ + private void setDatum(final VerticalDatum value) { + if (datum == null) { + datum = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultVerticalCRS.class, "setDatum", "verticalDatum"); + } } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/SubTypes.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -119,15 +119,19 @@ final class SubTypes implements Comparat if (object instanceof GeocentricCRS) { return DefaultGeocentricCRS.castOrCopy((GeocentricCRS) object); } - if (object instanceof DefaultGeodeticCRS) { // Result of XML unmarshalling - keep as-is. - return (DefaultGeodeticCRS) object; - } /* * The GeographicCRS and GeocentricCRS types are not part of ISO 19111. * ISO uses a single type, GeodeticCRS, for both of them and infer the * geographic or geocentric type from the coordinate system. We do this - * check here for instantiating the most appropriate SIS type. + * check here for instantiating the most appropriate SIS type, but only + * if we need to create a new object anyway (see below for rational). */ + if (object instanceof DefaultGeodeticCRS) { + // Result of XML unmarshalling — keep as-is. We avoid creating a new object because it + // would break object identities specified in GML document by the xlink:href attribute. + // However we may revisit this policy in the future. See SC_CRS.setElement(AbstractCRS). + return (DefaultGeodeticCRS) object; + } final Map<String,?> properties = IdentifiedObjects.getProperties(object); final GeodeticDatum datum = ((GeodeticCRS) object).getDatum(); final CoordinateSystem cs = object.getCoordinateSystem(); Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/package-info.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -77,7 +77,9 @@ * @version 0.7 * @module */ -@XmlSchema(elementFormDefault= XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = { +@XmlSchema(location = "http://schemas.opengis.net/gml/3.2.1/coordinateReferenceSystems.xsd", + elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = +{ @XmlNs(prefix = "gml", namespaceURI = Namespaces.GML), @XmlNs(prefix = "xsi", namespaceURI = Namespaces.XSI) }) Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/AbstractCS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -66,7 +66,7 @@ import static org.apache.sis.util.Utilit * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module * * @see DefaultCoordinateSystemAxis @@ -99,9 +99,13 @@ public class AbstractCS extends Abstract /** * 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) */ - @XmlElement(name = "axis") - private final CoordinateSystemAxis[] axes; + private CoordinateSystemAxis[] axes; /** * Other coordinate systems derived from this coordinate systems for other axes conventions. @@ -210,14 +214,18 @@ public class AbstractCS extends Abstract */ protected AbstractCS(final CoordinateSystem cs) { super(cs); - if (cs instanceof AbstractCS) { - axes = ((AbstractCS) cs).axes; // Share the array. - } else { - axes = new CoordinateSystemAxis[cs.getDimension()]; - for (int i=0; i<axes.length; i++) { - axes[i] = cs.getAxis(i); - } + 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; } /** @@ -483,5 +491,27 @@ public class AbstractCS extends Abstract 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; } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCompoundCS.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -18,6 +18,7 @@ package org.apache.sis.referencing.cs; import java.util.Map; import java.util.List; +import javax.xml.bind.annotation.XmlTransient; import org.opengis.referencing.cs.CoordinateSystem; import org.opengis.referencing.cs.CoordinateSystemAxis; import org.apache.sis.internal.metadata.AxisDirections; @@ -54,6 +55,7 @@ import static org.apache.sis.util.Utilit * @version 0.6 * @module */ +@XmlTransient public class DefaultCompoundCS extends AbstractCS { /** * Serial number for inter-operability with different versions. @@ -168,8 +170,9 @@ public class DefaultCompoundCS extends A * * @return All coordinate systems in this compound CS. */ + @SuppressWarnings("ReturnOfCollectionOrArrayField") public List<CoordinateSystem> getComponents() { - return components; + return components; // Unmodifiable. } /* Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/DefaultCoordinateSystemAxis.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -180,22 +180,34 @@ public class DefaultCoordinateSystemAxis /** * The abbreviation used for this coordinate system axes. * Examples are <cite>"X"</cite> and <cite>"Y"</cite>. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setAbbreviation(String)}</p> + * + * @see #getAbbreviation() */ - @XmlElement(name = "axisAbbrev", required = true) - private final String abbreviation; + private String abbreviation; /** * Direction of this coordinate system axis. In the case of Cartesian projected * coordinates, this is the direction of this coordinate system axis locally. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDirection(AxisDirection)}</p> + * + * @see #getDirection() */ - @XmlElement(name = "axisDirection", required = true) - private final AxisDirection direction; + private AxisDirection direction; /** * The unit of measure used for this coordinate system axis. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setUnit(Unit)}</p> + * + * @see #getUnit() */ - @XmlAttribute(name= "uom", required = true) - private final Unit<?> unit; + private Unit<?> unit; /** * Minimal and maximal value for this axis, or negative/positive infinity if none. @@ -208,9 +220,13 @@ public class DefaultCoordinateSystemAxis /** * The range meaning for this axis, or {@code null} if unspecified. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setRangeMeaning(RangeMeaning)}</p> + * + * @see #getRangeMeaning() */ - @XmlElement - private final RangeMeaning rangeMeaning; + private RangeMeaning rangeMeaning; /** * Constructs an axis from a set of properties. The properties given in argument follow the same rules @@ -397,6 +413,7 @@ public class DefaultCoordinateSystemAxis * @return The direction of this coordinate system axis. */ @Override + @XmlElement(name = "axisDirection", required = true) public AxisDirection getDirection() { return direction; } @@ -408,6 +425,7 @@ public class DefaultCoordinateSystemAxis * @return The coordinate system axis abbreviation. */ @Override + @XmlElement(name = "axisAbbrev", required = true) public String getAbbreviation() { return abbreviation; } @@ -420,6 +438,7 @@ public class DefaultCoordinateSystemAxis * @return The unit of measure used for ordinate values along this coordinate system axis. */ @Override + @XmlAttribute(name= "uom", required = true) public Unit<?> getUnit() { return unit; } @@ -469,6 +488,7 @@ public class DefaultCoordinateSystemAxis * @return The meaning of axis value range, or {@code null} if unspecified. */ @Override + @XmlElement(name = "rangeMeaning") public RangeMeaning getRangeMeaning() { return rangeMeaning; } @@ -854,12 +874,66 @@ public class DefaultCoordinateSystemAxis */ private DefaultCoordinateSystemAxis() { super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE); - abbreviation = null; - direction = null; - unit = null; - rangeMeaning = null; minimumValue = NEGATIVE_INFINITY; maximumValue = POSITIVE_INFINITY; + /* + * Direction and unit of measurement 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 CD_CoordinateSystemAxis adapter does some + * verifications. + */ + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getAbbreviation() + */ + private void setAbbreviation(final String value) { + if (abbreviation == null) { + abbreviation = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultCoordinateSystemAxis.class, "setAbbreviation", "abbreviation"); + } + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getDirection() + */ + private void setDirection(final AxisDirection value) { + if (direction == null) { + direction = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultCoordinateSystemAxis.class, "setDirection", "direction"); + } + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getUnit() + */ + private void setUnit(final Unit<?> value) { + if (unit == null) { + unit = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultCoordinateSystemAxis.class, "setUnit", "unit"); + } + } + + /** + * Invoked by JAXB at unmarshalling time. + * + * @see #getRangeMeaning() + */ + private void setRangeMeaning(final RangeMeaning value) { + if (rangeMeaning == null) { + rangeMeaning = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultCoordinateSystemAxis.class, "setRangeMeaning", "rangeMeaning"); + } } /** Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/cs/package-info.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -34,10 +34,12 @@ * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module */ -@XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = { +@XmlSchema(location = "http://schemas.opengis.net/gml/3.2.1/coordinateSystems.xsd", + elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns = +{ @XmlNs(prefix = "gml", namespaceURI = Namespaces.GML), @XmlNs(prefix = "xsi", namespaceURI = Namespaces.XSI) }) Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/AbstractDatum.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -65,7 +65,7 @@ import org.apache.sis.internal.jdk7.Obje * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.6 + * @version 0.7 * @module * * @see org.apache.sis.referencing.cs.AbstractCS @@ -74,7 +74,7 @@ import org.apache.sis.internal.jdk7.Obje @XmlType(name = "AbstractDatumType", propOrder = { "domainOfValidity", "scope", - "anchorDefinition", + "anchorPoint", "realizationEpoch" }) @XmlRootElement(name = "AbstractDatum") @@ -99,9 +99,13 @@ public class AbstractDatum extends Abstr /** * Description, possibly including coordinates, of the point or points used to anchor the datum * to the Earth. Also known as the "origin", especially for Engineering and Image Datums. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setAnchorPoint(InternationalString)}</p> + * + * @see #getAnchorPoint() */ - @XmlElement - private final InternationalString anchorDefinition; + private InternationalString anchorDefinition; /** * The time after which this datum definition is valid. This time may be precise @@ -115,15 +119,23 @@ public class AbstractDatum extends Abstr /** * Area or region in which this datum object is valid. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setDomainOfValidity(Extent)}</p> + * + * @see #getDomainOfValidity() */ - @XmlElement - private final Extent domainOfValidity; + private Extent domainOfValidity; /** * Description of domain of usage, or limitations of usage, for which this datum object is valid. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setScope(InternationalString)}</p> + * + * @see #getScope() */ - @XmlElement - private final InternationalString scope; + private InternationalString scope; /** * Creates a datum from the given properties. @@ -274,6 +286,7 @@ public class AbstractDatum extends Abstr * @return Description, possibly including coordinates, of the point or points used to anchor the datum to the Earth. */ @Override + @XmlElement(name = "anchorDefinition") public InternationalString getAnchorPoint() { return anchorDefinition; } @@ -302,6 +315,7 @@ public class AbstractDatum extends Abstr * @see org.apache.sis.metadata.iso.extent.DefaultExtent */ @Override + @XmlElement(name = "domainOfValidity") public Extent getDomainOfValidity() { return domainOfValidity; } @@ -312,6 +326,7 @@ public class AbstractDatum extends Abstr * @return Description of domain of usage, or limitations of usage, for which this datum object is valid. */ @Override + @XmlElement(name = "scope", required = true) public InternationalString getScope() { return scope; } @@ -462,14 +477,26 @@ public class AbstractDatum extends Abstr */ AbstractDatum() { super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE); - anchorDefinition = null; realizationEpoch = Long.MIN_VALUE; - domainOfValidity = null; - scope = null; } /** * Invoked by JAXB only at unmarshalling time. + * + * @see #getAnchorPoint() + */ + private void setAnchorPoint(final InternationalString value) { + if (anchorDefinition == null) { + anchorDefinition = value; + } else { + ReferencingUtilities.propertyAlreadySet(AbstractDatum.class, "setAnchorPoint", "anchorDefinition"); + } + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getRealizationEpoch() */ private void setRealizationEpoch(final Date value) { if (realizationEpoch == Long.MIN_VALUE) { @@ -478,4 +505,30 @@ public class AbstractDatum extends Abstr ReferencingUtilities.propertyAlreadySet(AbstractDatum.class, "setRealizationEpoch", "realizationEpoch"); } } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getDomainOfValidity() + */ + private void setDomainOfValidity(final Extent value) { + if (domainOfValidity == null) { + domainOfValidity = value; + } else { + ReferencingUtilities.propertyAlreadySet(AbstractDatum.class, "setDomainOfValidity", "domainOfValidity"); + } + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getScope() + */ + private void setScope(final InternationalString value) { + if (scope == null) { + scope = value; + } else { + ReferencingUtilities.propertyAlreadySet(AbstractDatum.class, "setScope", "scope"); + } + } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultEllipsoid.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -31,9 +31,9 @@ import org.opengis.referencing.datum.Ell import org.opengis.referencing.ReferenceIdentifier; import org.apache.sis.geometry.DirectPosition2D; import org.apache.sis.internal.util.Numerics; -import org.apache.sis.internal.jaxb.Context; import org.apache.sis.internal.jaxb.gml.Measure; import org.apache.sis.internal.jaxb.referencing.SecondDefiningParameter; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.internal.referencing.Formulas; import org.apache.sis.internal.metadata.WKTKeywords; import org.apache.sis.referencing.IdentifiedObjects; @@ -112,12 +112,12 @@ import org.apache.sis.internal.jdk7.Obje * @author Martin Desruisseaux (IRD, Geomatys) * @author Cédric Briançon (Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module * * @see org.apache.sis.referencing.CommonCRS#ellipsoid() */ -@XmlType(name="EllipsoidType", propOrder={ +@XmlType(name = "EllipsoidType", propOrder = { "semiMajorAxisMeasure", "secondDefiningParameter" }) @@ -698,8 +698,12 @@ public class DefaultEllipsoid extends Ab */ private DefaultEllipsoid() { super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE); - // We need to let the DefaultEllipsoid fields unitialized - // because afterUnmarshal(…) will check for zero values. + /* + * We need to let the DefaultEllipsoid fields unitialized because afterUnmarshal(…) + * will check for zero values. We can not thrown an exception from 'afterUnmarshal' + * because it would cause the whole unmarshalling to fail. But the CD_Ellipsoid + * adapter does some verifications. + */ } /** @@ -722,6 +726,7 @@ public class DefaultEllipsoid extends Ab } } if (unit == null) { + unit = SI.METRE; Measure.missingUOM(DefaultEllipsoid.class, "semiMajorAxis"); } } @@ -743,13 +748,13 @@ public class DefaultEllipsoid extends Ab * @see #afterUnmarshal(Unmarshaller, Object) */ private void setSemiMajorAxisMeasure(final Measure measure) { - if (semiMajorAxis != 0) { - warnDuplicated("semiMajorAxis"); - } else { + if (semiMajorAxis == 0) { final Unit<Length> uom = unit; // In case semi-minor were defined before semi-major. ensureStrictlyPositive("semiMajorAxis", semiMajorAxis = measure.value); unit = measure.getUnit(Length.class); harmonizeAxisUnits(uom); + } else { + ReferencingUtilities.propertyAlreadySet(DefaultEllipsoid.class, "setSemiMajorAxisMeasure", "semiMajorAxis"); } } @@ -758,7 +763,7 @@ public class DefaultEllipsoid extends Ab * returned object contains the values for {@link #semiMinorAxis} or {@link #inverseFlattening}, * according to the {@link #isIvfDefinitive()} value. This method is for JAXB marshalling only. */ - @XmlElement(name = "secondDefiningParameter") + @XmlElement(name = "secondDefiningParameter", required = true) private SecondDefiningParameter getSecondDefiningParameter() { return new SecondDefiningParameter(this, true); } @@ -778,9 +783,7 @@ public class DefaultEllipsoid extends Ab final Measure measure = second.measure; if (measure != null) { final boolean isIvfDefinitive = second.isIvfDefinitive(); - if ((isIvfDefinitive ? inverseFlattening : semiMinorAxis) != 0) { - warnDuplicated("secondDefiningParameter"); - } else { + if ((isIvfDefinitive ? inverseFlattening : semiMinorAxis) == 0) { ivfDefinitive = isIvfDefinitive; double value = measure.value; if (isIvfDefinitive) { @@ -792,6 +795,9 @@ public class DefaultEllipsoid extends Ab ensureStrictlyPositive("semiMinorAxis", semiMinorAxis = value); harmonizeAxisUnits(measure.getUnit(Length.class)); } + } else { + ReferencingUtilities.propertyAlreadySet(DefaultEllipsoid.class, + "setSecondDefiningParameter", "secondDefiningParameter"); } } } @@ -809,13 +815,4 @@ public class DefaultEllipsoid extends Ab semiMinorAxis = uom.getConverterTo(unit).convert(semiMinorAxis); } } - - /** - * Emits a warning telling that the given element is repeated twice. - */ - private static void warnDuplicated(final String element) { - // We cheat a bit for the "unmarshal" method name since there is not such method... - Context.warningOccured(Context.current(), DefaultEllipsoid.class, "unmarshal", - Errors.class, Errors.Keys.DuplicatedElement_1, element); - } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -37,6 +37,7 @@ import org.apache.sis.metadata.iso.exten import org.apache.sis.internal.metadata.WKTKeywords; import org.apache.sis.internal.metadata.ReferencingServices; import org.apache.sis.internal.referencing.ExtentSelector; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.internal.util.CollectionsExt; import org.apache.sis.internal.system.Loggers; import org.apache.sis.util.logging.Logging; @@ -122,7 +123,7 @@ import org.apache.sis.internal.jdk7.Obje * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.5 + * @version 0.7 * @module * * @see DefaultEllipsoid @@ -153,15 +154,23 @@ public class DefaultGeodeticDatum extend /** * The ellipsoid. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setEllipsoid(Ellipsoid)}</p> + * + * @see #getEllipsoid() */ - @XmlElement - private final Ellipsoid ellipsoid; + private Ellipsoid ellipsoid; /** * The prime meridian. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setPrimeMeridian(PrimeMeridian)}</p> + * + * @see #getPrimeMeridian() */ - @XmlElement - private final PrimeMeridian primeMeridian; + private PrimeMeridian primeMeridian; /** * Bursa-Wolf parameters for datum shifts, or {@code null} if none. @@ -313,6 +322,7 @@ public class DefaultGeodeticDatum extend * @return The ellipsoid. */ @Override + @XmlElement(name = "ellipsoid", required = true) public Ellipsoid getEllipsoid() { return ellipsoid; } @@ -323,6 +333,7 @@ public class DefaultGeodeticDatum extend * @return The prime meridian. */ @Override + @XmlElement(name = "primeMeridian", required = true) public PrimeMeridian getPrimeMeridian() { return primeMeridian; } @@ -590,8 +601,38 @@ public class DefaultGeodeticDatum extend * reserved to JAXB, which will assign values to the fields using reflexion. */ private DefaultGeodeticDatum() { - ellipsoid = null; - primeMeridian = null; - bursaWolf = null; + bursaWolf = null; + /* + * Ellipsoid and PrimeMeridian 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 CD_GeodeticDatum + * adapter does some verifications. + */ + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getEllipsoid() + */ + private void setEllipsoid(final Ellipsoid value) { + if (ellipsoid == null) { + ellipsoid = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultGeodeticDatum.class, "setEllipsoid", "ellipsoid"); + } + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getPrimeMeridian() + */ + private void setPrimeMeridian(final PrimeMeridian value) { + if (primeMeridian == null) { + primeMeridian = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultGeodeticDatum.class, "setPrimeMeridian", "primeMeridian"); + } } } Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java?rev=1709637&r1=1709636&r2=1709637&view=diff ============================================================================== --- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java [UTF-8] (original) +++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultImageDatum.java [UTF-8] Tue Oct 20 16:24:53 2015 @@ -26,6 +26,7 @@ import org.opengis.referencing.Reference import org.opengis.referencing.datum.ImageDatum; import org.opengis.referencing.datum.PixelInCell; import org.apache.sis.internal.metadata.WKTKeywords; +import org.apache.sis.internal.referencing.ReferencingUtilities; import org.apache.sis.io.wkt.Formatter; import org.apache.sis.io.wkt.Convention; import org.apache.sis.util.ComparisonMode; @@ -48,7 +49,7 @@ import org.apache.sis.internal.jdk7.Obje * * @author Martin Desruisseaux (IRD, Geomatys) * @since 0.4 - * @version 0.4 + * @version 0.7 * @module */ @XmlType(name = "ImageDatumType") @@ -61,9 +62,13 @@ public class DefaultImageDatum extends A /** * Specification of the way the image grid is associated with the image data attributes. + * + * <p><b>Consider this field as final!</b> + * This field is modified only at unmarshalling time by {@link #setPixelInCell(PixelInCell)}</p> + * + * @see #getPixelInCell() */ - @XmlElement(required = true) - private final PixelInCell pixelInCell; + private PixelInCell pixelInCell; /** * Creates an image datum from the given properties. The properties map is given @@ -181,6 +186,7 @@ public class DefaultImageDatum extends A * @return The way image grid is associated with image data attributes. */ @Override + @XmlElement(required = true) public PixelInCell getPixelInCell() { return pixelInCell; } @@ -266,6 +272,18 @@ public class DefaultImageDatum extends A * reserved to JAXB, which will assign values to the fields using reflexion. */ private DefaultImageDatum() { - pixelInCell = null; + } + + /** + * Invoked by JAXB only at unmarshalling time. + * + * @see #getPixelInCell() + */ + private void setPixelInCell(final PixelInCell value) { + if (pixelInCell == null) { + pixelInCell = value; + } else { + ReferencingUtilities.propertyAlreadySet(DefaultImageDatum.class, "setPixelInCell", "pixelInCell"); + } } }