sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1701520 [2/6] - in /sis/trunk: ./ core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/ core/sis-metadata/src/test/java/org/apache/sis/metadata/ core/sis-me...
Date Sun, 06 Sep 2015 19:52:38 GMT
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroup.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroup.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroup.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_OperationParameterGroup.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -16,10 +16,18 @@
  */
 package org.apache.sis.internal.jaxb.referencing;
 
+import java.util.Map;
+import java.util.List;
+import java.util.LinkedHashMap;
 import javax.xml.bind.annotation.XmlElement;
+import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
+import org.opengis.parameter.GeneralParameterDescriptor;
 import org.apache.sis.internal.jaxb.gco.PropertyType;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
+import org.apache.sis.util.CorruptedObjectException;
+import org.apache.sis.util.collection.Containers;
+import org.apache.sis.util.resources.Errors;
 
 
 /**
@@ -89,4 +97,125 @@ public final class CC_OperationParameter
     public void setElement(final DefaultParameterDescriptorGroup parameter) {
         metadata = parameter;
     }
+
+    /**
+     * Invoked by {@link DefaultParameterDescriptorGroup#setDescriptors(GeneralParameterDescriptor[])}
+     * for merging into a single set the descriptors which are repeated twice in a GML document.
+     *
+     * <p>The {@code descriptors} argument gives the descriptors listed explicitely inside a
+     * {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>} element. Those
+     * descriptors are said "incomplete" (from SIS point of view) because they are missing the
+     * {@link ParameterDescriptor#getValueClass()} property, which does not exist in GML but
+     * is mandatory for us. However an exception to this "incompleteness" happen when SIS has
+     * been able to match the {@code <gml:OperationMethod>} parent to one of the pre-defined
+     * operations in the {@link org.apache.sis.internal.referencing.provider} package.</p>
+     *
+     * <p>The {@code fromValues} argument gives the descriptors declared in each {@code <gml:ParameterValue>}
+     * instances of a {@code <gml:ParameterValueGroup>} or {@code <gml:AbstractSingleOperation>} element.
+     * Contrarily to the {@code descriptors} argument, the {@code fromValues} instances should have non-null
+     * {@link ParameterDescriptor#getValueClass()} property inferred by SIS from the parameter value.</p>
+     *
+     * <p>So the preferred descriptors from more complete to less complete are:</p>
+     * <ol>
+     *   <li>{@code descriptors} if and only if they contain pre-defined parameters inferred by SIS from the {@code <gml:OperationMethod>} name.</li>
+     *   <li>{@code fromValues}, which contain the descriptors declared in the {@code <gml:ParameterValue>} instances.</li>
+     *   <li>{@code descriptors}, which contain the descriptor listed in {@code <gml:OperationParameterGroup>} or {@code <gml:OperationMethod>}.</li>
+     * </ol>
+     *
+     * <div class="note"><b>Note:</b>
+     * this code is defined in this {@code CC_OperationParameterGroup} class instead than in the
+     * {@link DefaultParameterDescriptorGroup} class in the hope to reduce the amount of code
+     * processed by the JVM in the common case where JAXB (un)marshalling is not needed.</div>
+     *
+     * @param  descriptors  The descriptors declared in the {@code ParameterDescriptorGroup}.
+     * @param  fromValues   The descriptors declared in the {@code ParameterValue} instances.
+     *                      They are said "valid" because they contain the mandatory {@code valueClass} property.
+     * @param  replacements An {@code IdentityHashMap} where to store the replacements that the caller needs
+     *                      to apply in the {@code GeneralParameterValue} instances.
+     * @return A sequence containing the merged set of parameter descriptors.
+     *
+     * @see <a href="http://issues.apache.org/jira/browse/SIS-290">SIS-290</a>
+     */
+    public static GeneralParameterDescriptor[] merge(
+            final List<GeneralParameterDescriptor> descriptors,
+            final GeneralParameterDescriptor[] fromValues,
+            final Map<GeneralParameterDescriptor,GeneralParameterDescriptor> replacements)
+    {
+        if (descriptors.isEmpty()) {
+            return fromValues;
+        }
+        final Map<String,GeneralParameterDescriptor> union =
+                new LinkedHashMap<String,GeneralParameterDescriptor>(Containers.hashMapCapacity(descriptors.size()));
+        /*
+         * Collect the descriptors declared explicitely in the ParameterDescriptorGroup. We should never have
+         * two descriptors of the same name since the DefaultParameterDescriptorGroup constructor checked for
+         * name ambiguity. If a name collision is nevertheless detected, this would mean that a descriptor's
+         * name mutated.
+         */
+        for (final GeneralParameterDescriptor p : descriptors) {
+            final String name = p.getName().getCode();
+            if (union.put(name, p) != null) {
+                throw new CorruptedObjectException(name);
+            }
+        }
+        /*
+         * Verify if any descriptors found in the ParameterValue instances could replace the descriptors in the group.
+         * We give precedence to the descriptors having a non-null 'valueClass' property, which normally appear in the
+         * 'fromValues' array.
+         */
+        for (final GeneralParameterDescriptor valueDescriptor : fromValues) {
+            final String name = valueDescriptor.getName().getCode();
+            GeneralParameterDescriptor complete = valueDescriptor;
+            GeneralParameterDescriptor previous = union.put(name, complete);
+            if (previous != null) {
+                if (previous instanceof ParameterDescriptor<?>) {
+                    verifyEquivalence(name, complete instanceof ParameterDescriptor<?>);
+                    final Class<?> valueClass = ((ParameterDescriptor<?>) previous).getValueClass();
+                    if (valueClass != null) {
+                        /*
+                         * This may happen if the 'descriptors' argument contain the parameters of a pre-defined
+                         * method from the 'org.apache.sis.internal.referencing.provider' package instead than a
+                         * descriptor from the GML file.  In such case, presume that 'previous' is actually more
+                         * complete than 'complete'.
+                         *
+                         * Note that 'r' should never be null unless JAXB unmarshalled the elements in reverse
+                         * order (e.g. <gml:ParameterValue> before <gml:OperationMethod>). Since this behavior
+                         * may depend on JAXB implementation, we are better to check for such case.
+                         */
+                        final Class<?> r = ((ParameterDescriptor<?>) complete).getValueClass();
+                        if (r != null) {
+                            verifyEquivalence(name, valueClass == r);
+                        }
+                        // Restore the previous value in the map and swap 'previous' with 'replacement'.
+                        previous = union.put(name, complete = previous);
+                    }
+                } else if (previous instanceof ParameterDescriptorGroup) {
+                    verifyEquivalence(name, complete instanceof ParameterDescriptorGroup);
+                }
+                /*
+                 * Verify that the replacement contains at least all the information provided by the previous
+                 * descriptor. The replacement is allowed to contain more information however.
+                 */
+                final GeneralParameterDescriptor replacement = CC_GeneralOperationParameter.merge(previous, complete);
+                if (replacement != valueDescriptor) {
+                    union.put(name, replacement);
+                    if (replacements.put(valueDescriptor, replacement) != null) {
+                        // Should never happen, unless the parameter name changed during execution of this loop.
+                        throw new CorruptedObjectException(name);
+                    }
+                }
+            }
+        }
+        return union.values().toArray(new GeneralParameterDescriptor[union.size()]);
+    }
+
+    /**
+     * Throws an exception for mismatched descriptor if a condition is false.
+     * This is used for verifying that a descriptors has the expected properties.
+     */
+    private static void verifyEquivalence(final String name, final boolean condition) {
+        if (!condition) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.MismatchedParameterDescriptor_1, name));
+        }
+    }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/ReferencingUtilities.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -27,6 +27,7 @@ import org.opengis.referencing.datum.Ell
 import org.opengis.referencing.datum.PrimeMeridian;
 import org.apache.sis.util.Static;
 import org.apache.sis.util.Utilities;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.referencing.CommonCRS;
@@ -224,6 +225,41 @@ public final class ReferencingUtilities
     }
 
     /**
+     * Returns the XML property name of the given interface.
+     *
+     * For {@link CoordinateSystem} base type, the returned value shall be one of
+     * {@code affineCS}, {@code cartesianCS}, {@code cylindricalCS}, {@code ellipsoidalCS}, {@code linearCS},
+     * {@code parametricCS}, {@code polarCS}, {@code sphericalCS}, {@code timeCS} or {@code verticalCS}.
+     *
+     * @param  base The abstract base interface.
+     * @param  type The interface or classes for which to get the XML property name.
+     * @return The XML property name for the given class or interface, or {@code null} if none.
+     *
+     * @since 0.6
+     */
+    public static StringBuilder toPropertyName(final Class<?> base, final Class<?> type) {
+        final UML uml = type.getAnnotation(UML.class);
+        if (uml != null && uml.specification() == Specification.ISO_19111) {
+            final String name = uml.identifier();
+            final int length = name.length();
+            final StringBuilder buffer = new StringBuilder(length).append(name, name.indexOf('_') + 1, length);
+            if (buffer.length() != 0) {
+                buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0)));
+                return buffer;
+            }
+        }
+        for (final Class<?> c : type.getInterfaces()) {
+            if (base.isAssignableFrom(c)) {
+                final StringBuilder name = toPropertyName(base, c);
+                if (name != null) {
+                    return name;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
      * Returns the WKT type of the given interface.
      *
      * For {@link CoordinateSystem} base type, the returned value shall be one of
@@ -236,28 +272,18 @@ public final class ReferencingUtilities
      */
     public static String toWKTType(final Class<?> base, final Class<?> type) {
         if (type != base) {
-            final UML uml = type.getAnnotation(UML.class);
-            if (uml != null && uml.specification() == Specification.ISO_19111) {
-                String name = uml.identifier();
-                final int length = name.length() - 5; // Length without "CS_" and "CS".
-                if (length >= 1 && name.startsWith("CS_") && name.endsWith("CS")) {
-                    final StringBuilder buffer = new StringBuilder(length).append(name, 3, 3 + length);
-                    if (!name.regionMatches(3, "Cartesian", 0, 9)) {
-                        buffer.setCharAt(0, Character.toLowerCase(buffer.charAt(0)));
+            final StringBuilder name = toPropertyName(base, type);
+            if (name != null) {
+                int end = name.length() - 2;
+                if (CharSequences.regionMatches(name, end, "CS")) {
+                    name.setLength(end);
+                    if ("time".contentEquals(name)) {
+                        return "temporal";
                     }
-                    name = buffer.toString();
-                    if (name.equals("time")) {
-                        name = "temporal";
-                    }
-                    return name;
-                }
-            }
-            for (final Class<?> c : type.getInterfaces()) {
-                if (base.isAssignableFrom(c)) {
-                    final String name = toWKTType(base, c);
-                    if (name != null) {
-                        return name;
+                    if (CharSequences.regionMatches(name, 0, "cartesian")) {
+                        name.setCharAt(0, 'C');     // "Cartesian"
                     }
+                    return name.toString();
                 }
             }
         }
@@ -265,9 +291,9 @@ public final class ReferencingUtilities
     }
 
     /**
-     * Ensures that the given argument value is {@code false}. This method is invoked by private setter methods,
-     * which are themselves invoked by JAXB at unmarshalling time. Invoking this method from those setter methods
-     * serves three purposes:
+     * Invoked by private setter methods (themselves invoked by JAXB at unmarshalling time)
+     * when an element is already set. Invoking this method from those setter methods serves
+     * three purposes:
      *
      * <ul>
      *   <li>Make sure that a singleton property is not defined twice in the XML document.</li>
@@ -277,23 +303,17 @@ public final class ReferencingUtilities
      *       warning or error messages in future SIS versions.</li>
      * </ul>
      *
-     * @param  classe    The caller class, used only in case of warning message to log.
-     * @param  method    The caller method, used only in case of warning message to log.
-     * @param  name      The property name, used only in case of error message to format.
-     * @param  isDefined Whether the property in the caller object is current defined.
-     * @return {@code true} if the caller can set the property.
+     * @param  classe The caller class, used only in case of warning message to log.
+     * @param  method The caller method, used only in case of warning message to log.
+     * @param  name   The property name, used only in case of error message to format.
      * @throws IllegalStateException If {@code isDefined} is {@code true} and we are not unmarshalling an object.
      */
-    public static boolean canSetProperty(final Class<?> classe, final String method,
-            final String name, final boolean isDefined) throws IllegalStateException
+    public static void propertyAlreadySet(final Class<?> classe, final String method, final String name)
+            throws IllegalStateException
     {
-        if (!isDefined) {
-            return true;
-        }
         final Context context = Context.current();
         if (context != null) {
             Context.warningOccured(context, classe, method, Errors.class, Errors.Keys.ElementAlreadyPresent_1, name);
-            return false;
         } else {
             throw new IllegalStateException(Errors.format(Errors.Keys.ElementAlreadyPresent_1, name));
         }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -114,12 +114,13 @@ abstract class AbstractProvider extends
     }
 
     /**
-     * Creates a descriptor for a constant value in degrees.
+     * Creates a descriptor for a 0 constant value in degrees.
      *
      * @see MapProjection#validate(ParameterDescriptor, double)
      */
-    static ParameterDescriptor<Double> createConstant(final ParameterBuilder builder, final Double constant) {
-        return builder.createBounded(MeasurementRange.create(constant, true, constant, true, NonSI.DEGREE_ANGLE), constant);
+    static ParameterDescriptor<Double> createZeroConstant(final ParameterBuilder builder) {
+        final Double zero = +0.0;
+        return builder.createBounded(MeasurementRange.create(-0.0, true, zero, true, NonSI.DEGREE_ANGLE), zero);
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Equirectangular.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -163,7 +163,7 @@ public final class Equirectangular exten
          * still see it in use sometime. However, taking inspiration from the practice done in "Mercator (1SP)"
          * projection, we require that the parameter value must be zero.
          */
-        LATITUDE_OF_ORIGIN = createConstant(builder     // Was used by EPSG:9823 (also EPSG:9842).
+        LATITUDE_OF_ORIGIN = createZeroConstant(builder     // Was used by EPSG:9823 (also EPSG:9842).
                 .addIdentifier("8801")
                 .addName("Latitude of natural origin")
                 .addName(Citations.OGC,     "latitude_of_origin")
@@ -172,7 +172,7 @@ public final class Equirectangular exten
                 .addName(Citations.GEOTIFF, "ProjCenterLat")
                 .addName(Citations.PROJ4,   "lat_0")
                 .setRemarks(Messages.formatInternational(Messages.Keys.ConstantProjParameterValue_1, 0))
-                .setRequired(false), 0.0);
+                .setRequired(false));
 
         // Do not declare the ESRI "Equidistant_Cylindrical" projection name below,
         // for avoiding confusion with EPSG "Equidistant Cylindrical" ellipsoidal projection.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -48,7 +48,6 @@ import org.apache.sis.util.resources.Mes
 import static org.opengis.metadata.Identifier.AUTHORITY_KEY;
 
 // Branch-dependent imports
-import org.apache.sis.internal.jdk7.Objects;
 
 
 /**
@@ -134,7 +133,7 @@ public abstract class MapProjection exte
      * @param  value The parameter value in the units given by the descriptor.
      * @throws IllegalArgumentException if the given value is out of bounds.
      *
-     * @see #createConstant(ParameterBuilder, Double)
+     * @see #createZeroConstant(ParameterBuilder)
      */
     public static void validate(final ParameterDescriptor<? extends Number> descriptor, final double value)
             throws IllegalArgumentException
@@ -145,7 +144,9 @@ public abstract class MapProjection exte
         }
         final Comparable<? extends Number> min = descriptor.getMinimumValue();
         final Comparable<? extends Number> max = descriptor.getMaximumValue();
-        if (!Objects.equals(min, max)) {
+        final double minValue = (min instanceof Number) ? ((Number) min).doubleValue() : Double.NaN;
+        final double maxValue = (max instanceof Number) ? ((Number) max).doubleValue() : Double.NaN;
+        if (value < minValue || value > maxValue) {
             /*
              * RATIONAL: why we do not check the bounds if (min == max):
              * The only case when our descriptor have (min == max) is when a parameter can only be zero,
@@ -153,11 +154,9 @@ public abstract class MapProjection exte
              * But in some cases, it would be possible to deal with non-zero values, even if in principle
              * we should not. In such case we let the caller decides.
              *
-             * Above check should be revisited if createConstant(ParameterBuilder, Double) is modified.
+             * Above check should be revisited if createZeroConstant(ParameterBuilder) is modified.
              */
-            if ((min instanceof Number && !(value >= ((Number) min).doubleValue())) ||
-                (max instanceof Number && !(value <= ((Number) max).doubleValue())))
-            {
+            if (minValue != maxValue) {   // Compare as 'double' because we want (-0 == +0) to be true.
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.ValueOutOfRange_4,
                         descriptor.getName(), min, max, value));
             }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator1SP.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -66,9 +66,9 @@ public final class Mercator1SP extends A
     static final ParameterDescriptorGroup PARAMETERS;
     static {
         final ParameterBuilder builder = builder();
-        LATITUDE_OF_ORIGIN = createConstant(builder.addNamesAndIdentifiers(Equirectangular.LATITUDE_OF_ORIGIN)
+        LATITUDE_OF_ORIGIN = createZeroConstant(builder.addNamesAndIdentifiers(Equirectangular.LATITUDE_OF_ORIGIN)
                 .rename(Citations.GEOTIFF, "NatOriginLat")
-                .setRemarks(Equirectangular.LATITUDE_OF_ORIGIN.getRemarks()), 0.0);
+                .setRemarks(Equirectangular.LATITUDE_OF_ORIGIN.getRemarks()));
 
         LONGITUDE_OF_ORIGIN = createLongitude(builder.addNamesAndIdentifiers(Equirectangular.LONGITUDE_OF_ORIGIN)
                 .rename(Citations.GEOTIFF, "NatOriginLong"));

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/Mercator2SP.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -77,9 +77,9 @@ public final class Mercator2SP extends A
          */
         builder.setRequired(false); // Will apply to all remaining parameters.
         final InternationalString remarks = notFormalParameter("Mercator (variant A)");
-        final ParameterDescriptor<Double> latitudeOfOrigin = createConstant(builder
+        final ParameterDescriptor<Double> latitudeOfOrigin = createZeroConstant(builder
                 .addNamesAndIdentifiers(Mercator1SP.LATITUDE_OF_ORIGIN)
-                .setRemarks(remarks), 0.0);
+                .setRemarks(remarks));
         /*
          * Remove the EPSG name and identifier at least for the scale factor, because its meaning does not fit well
          * in this context. The EPSG name is "Scale factor at natural origin" while actually the scale factor applied

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/AbstractParameterDescriptor.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -32,6 +32,7 @@ import org.apache.sis.util.resources.Err
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.Debug;
 
+import static org.apache.sis.internal.jaxb.referencing.CC_GeneralOperationParameter.DEFAULT_OCCURRENCE;
 
 /**
  * Abstract definition of a parameter or group of parameters used by a coordinate operation or a process.
@@ -128,17 +129,6 @@ public abstract class AbstractParameterD
     private short maximumOccurs;
 
     /**
-     * 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.
-     */
-    AbstractParameterDescriptor() {
-        super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE);
-        minimumOccurs = 1;  // Default value is XML element is omitted.
-        maximumOccurs = 1;
-    }
-
-    /**
      * Constructs a parameter descriptor from a set of properties. 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:
@@ -350,7 +340,30 @@ public abstract class AbstractParameterD
         return WKTKeywords.Parameter;
     }
 
-    // ---- XML SUPPORT ----------------------------------------------------
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 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.
+     */
+    AbstractParameterDescriptor() {
+        super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE);
+        minimumOccurs = DEFAULT_OCCURRENCE;  // Default value if XML element is omitted.
+        maximumOccurs = DEFAULT_OCCURRENCE;
+    }
 
     /**
      * Invoked by JAXB for marshalling the {@link #minimumOccurs} value. Omit marshalling of this
@@ -360,7 +373,7 @@ public abstract class AbstractParameterD
     @XmlSchemaType(name = "nonNegativeInteger")
     private Integer getNonDefaultMinimumOccurs() {
         final int n = getMinimumOccurs();
-        return (n != 1) ? n : null;
+        return (n != DEFAULT_OCCURRENCE) ? n : null;
     }
 
     /**
@@ -377,20 +390,20 @@ public abstract class AbstractParameterD
     @XmlSchemaType(name = "nonNegativeInteger")
     private Integer getNonDefaultMaximumOccurs() {
         final int n = getMaximumOccurs();
-        return (n != 1) ? n : null;
+        return (n != DEFAULT_OCCURRENCE) ? n : null;
     }
 
     /**
      * Invoked by JAXB for unmarshalling the {@link #minimumOccurs} value.
      */
     private void setNonDefaultMinimumOccurs(final Integer n) {
-        minimumOccurs = (n != null) ? crop(n) : 1;
+        minimumOccurs = (n != null) ? crop(n) : DEFAULT_OCCURRENCE;
     }
 
     /**
      * Invoked by JAXB for unmarshalling the {@link #maximumOccurs} value.
      */
     private void setNonDefaultMaximumOccurs(final Integer n) {
-        maximumOccurs = (n != null) ? crop(n) : 1;
+        maximumOccurs = (n != null) ? crop(n) : DEFAULT_OCCURRENCE;
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptor.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -121,37 +121,6 @@ public class DefaultParameterDescriptor<
     private final T defaultValue;
 
     /**
-     * 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.
-     *
-     * <p>This constructor fetches the value class and the unit of measurement from the enclosing
-     * {@link DefaultParameterValue}, if presents, because those information are not presents in GML.
-     * They are GeoAPI additions.</p>
-     */
-    @SuppressWarnings("unchecked")
-    private DefaultParameterDescriptor() {
-        final PropertyType<?,?> wrapper = Context.getWrapper(Context.current());
-        if (wrapper instanceof CC_OperationParameter) {
-            final CC_OperationParameter param = (CC_OperationParameter) wrapper;
-            /*
-             * This unsafe cast would be forbidden if this constructor was public or used in any context where the
-             * user can choose the value of <T>. But this constructor should be invoked only during unmarshalling,
-             * after the creation of the ParameterValue (this is the reverse creation order than what we normally
-             * do through the public API). The 'valueClass' should be compatible with DefaultParameterValue.value,
-             * and the parameterized type visible to the user should be only <?>.
-             */
-            valueClass  = (Class) param.valueClass;
-            valueDomain = param.valueDomain;
-        } else {
-            valueClass  = null;
-            valueDomain = null;
-        }
-        validValues  = null;
-        defaultValue = null;
-    }
-
-    /**
      * Constructs a descriptor from the given properties. The properties map is given unchanged to the
      * {@linkplain AbstractParameterDescriptor#AbstractParameterDescriptor(Map, int, int) super-class constructor}.
      * The following table is a reminder of main (not all) properties:
@@ -537,4 +506,50 @@ public class DefaultParameterDescriptor<
     protected long computeHashCode() {
         return Arrays.deepHashCode(new Object[] {valueClass, valueDomain, defaultValue}) + super.computeHashCode();
     }
+
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+    /**
+     * 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.
+     *
+     * <p>This constructor fetches the value class and the unit of measurement from the enclosing
+     * {@link DefaultParameterValue}, if presents, because those information are not presents in GML.
+     * They are GeoAPI additions.</p>
+     */
+    @SuppressWarnings("unchecked")
+    private DefaultParameterDescriptor() {
+        final PropertyType<?,?> wrapper = Context.getWrapper(Context.current());
+        if (wrapper instanceof CC_OperationParameter) {
+            final CC_OperationParameter param = (CC_OperationParameter) wrapper;
+            /*
+             * This unsafe cast would be forbidden if this constructor was public or used in any context where the
+             * user can choose the value of <T>. But this constructor should be invoked only during unmarshalling,
+             * after the creation of the ParameterValue (this is the reverse creation order than what we normally
+             * do through the public API). The 'valueClass' should be compatible with DefaultParameterValue.value,
+             * and the parameterized type visible to the user should be only <?>.
+             */
+            valueClass  = (Class) param.valueClass;
+            valueDomain = param.valueDomain;
+        } else {
+            valueClass  = null;
+            valueDomain = null;
+        }
+        validValues  = null;
+        defaultValue = null;
+    }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterDescriptorGroup.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -21,7 +21,6 @@ import java.util.Set;
 import java.util.List;
 import java.util.HashSet;
 import java.util.Collections;
-import java.util.LinkedHashMap;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -30,9 +29,10 @@ import org.opengis.parameter.ParameterDe
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.parameter.InvalidParameterNameException;
+import org.apache.sis.internal.jaxb.referencing.CC_OperationParameterGroup;
+import org.apache.sis.internal.referencing.ReferencingUtilities;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
-import org.apache.sis.util.collection.Containers;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.ComparisonMode;
@@ -109,15 +109,6 @@ public class DefaultParameterDescriptorG
     private List<GeneralParameterDescriptor> descriptors;
 
     /**
-     * Constructs a new object in which every attributes are set to a null value or an empty list.
-     * <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 DefaultParameterDescriptorGroup() {
-        descriptors = Collections.emptyList();
-    }
-
-    /**
      * Constructs a parameter group from a set of properties. The properties map is given unchanged to the
      * {@linkplain AbstractParameterDescriptor#AbstractParameterDescriptor(Map, int, int) super-class constructor}.
      * The following table is a reminder of main (not all) properties:
@@ -393,7 +384,30 @@ public class DefaultParameterDescriptorG
         return super.computeHashCode() + descriptors.hashCode();
     }
 
-    // ---- XML SUPPORT ----------------------------------------------------
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Constructs a new object in which every attributes are set to a null value or an empty list.
+     * <strong>This is not a valid object.</strong> This constructor is strictly reserved to JAXB
+     * and to {@link DefaultParameterValueGroup}, which will assign values later.
+     *
+     * @see #setDescriptors(GeneralParameterDescriptor[])
+     */
+    DefaultParameterDescriptorGroup() {
+        descriptors = Collections.emptyList();
+    }
 
     /**
      * Invoked by JAXB for getting the parameters to marshal.
@@ -405,35 +419,39 @@ public class DefaultParameterDescriptorG
     }
 
     /**
-     * Invoked by JAXB or by {@link DefaultParameterValueGroup} for setting the unmarshalled parameters.
-     * If parameters already exist, them this method computes the union of the two parameter collections
-     * with the new parameters having precedence over the old ones.
+     * Invoked by JAXB for setting the unmarshalled parameter descriptors.
+     */
+    private void setDescriptors(final GeneralParameterDescriptor[] parameters) {
+        if (descriptors.isEmpty()) {
+            verifyNames(null, parameters);
+            descriptors = asList(parameters);
+        } else {
+            ReferencingUtilities.propertyAlreadySet(DefaultParameterValue.class, "setDescriptors", "parameter");
+        }
+    }
+
+    /**
+     * Merges the given parameter descriptors with the descriptors currently in this group.
+     * The descriptors are set twice during {@link DefaultParameterValueGroup} unmarshalling:
      *
-     * <div class="note"><b>Rational:</b>
-     * this method is invoked twice during {@link DefaultParameterValueGroup} unmarshalling:
      * <ol>
-     *   <li>First, this method is invoked during unmarshalling of this {@code DefaultParameterDescriptorGroup}.
+     *   <li>First, the descriptors are set during unmarshalling of this {@code DefaultParameterDescriptorGroup}.
      *       But the value class of {@code ParameterDescriptor} components are unknown because this information
      *       is not part of GML.</li>
      *   <li>Next, this method is invoked during unmarshalling of the {@code DefaultParameterValueGroup} enclosing
      *       element with the descriptors found inside the {@code ParameterValue} components. The later do have the
      *       {@code valueClass} information, so we want to use them in replacement of descriptors of step 1.</li>
      * </ol>
-     * </div>
+     *
+     * @param fromValues Descriptors declared in the {@code ParameterValue} instances of a {@code ParameterValueGroup}.
+     * @param replacements An {@code IdentityHashMap} where to store the replacements that the caller needs
+     *                     to apply in the {@code GeneralParameterValue} instances.
      */
-    final void setDescriptors(GeneralParameterDescriptor[] parameters) {
-        verifyNames(null, parameters);
-        if (!descriptors.isEmpty()) {
-            final Map<String,GeneralParameterDescriptor> union =
-                    new LinkedHashMap<String,GeneralParameterDescriptor>(Containers.hashMapCapacity(descriptors.size()));
-            for (final GeneralParameterDescriptor p : descriptors) {
-                union.put(p.getName().getCode(), p);
-            }
-            for (final GeneralParameterDescriptor p : parameters) {
-                union.put(p.getName().getCode(), p);
-            }
-            parameters = union.values().toArray(new GeneralParameterDescriptor[union.size()]);
-        }
-        descriptors = asList(parameters);
+    final void merge(GeneralParameterDescriptor[] fromValues,
+            final Map<GeneralParameterDescriptor,GeneralParameterDescriptor> replacements)
+    {
+        fromValues = CC_OperationParameterGroup.merge(descriptors, fromValues, replacements);
+        verifyNames(null, fromValues);
+        descriptors = asList(fromValues);
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValue.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -160,13 +160,6 @@ public class DefaultParameterValue<T> ex
     private Unit<?> unit;
 
     /**
-     * Default constructor for JAXB only. The descriptor is initialized to {@code null},
-     * but will be assigned a value after XML unmarshalling.
-     */
-    private DefaultParameterValue() {
-    }
-
-    /**
      * Creates a parameter value from the specified descriptor.
      * The value will be initialized to the default value, if any.
      *
@@ -998,7 +991,38 @@ public class DefaultParameterValue<T> ex
                formatter.hasContextualUnit(2);      // In WKT2
     }
 
-    // ---- XML SUPPORT ----------------------------------------------------
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Default constructor for JAXB only. The descriptor is initialized to {@code null},
+     * but will be assigned a value after XML unmarshalling.
+     */
+    private DefaultParameterValue() {
+    }
+
+    /**
+     * Invoked by JAXB at unmarshalling time.
+     * May also be invoked by {@link DefaultParameterValueGroup} if the descriptor as been completed
+     * with additional information provided in the {@code <gml:group>} element of a descriptor group.
+     *
+     * @see #getDescriptor()
+     */
+    final void setDescriptor(final ParameterDescriptor<T> descriptor) {
+        this.descriptor = descriptor;
+        assert (value == null) || descriptor.getValueClass().isInstance(value) : this;
+    }
 
     /**
      * Invoked by JAXB for obtaining the object to marshal.
@@ -1048,9 +1072,7 @@ public class DefaultParameterValue<T> ex
      */
     @SuppressWarnings("unchecked")
     private void setXmlValue(Object xmlValue) {
-        if (ReferencingUtilities.canSetProperty(DefaultParameterValue.class,
-                "setXmlValue", "value", value != null || unit != null))
-        {
+        if (value == null && unit == null) {
             if (xmlValue instanceof Measure) {
                 final Measure measure = (Measure) xmlValue;
                 xmlValue = measure.value;
@@ -1081,16 +1103,8 @@ public class DefaultParameterValue<T> ex
                  */
                 value = (T) xmlValue;
             }
+        } else {
+            ReferencingUtilities.propertyAlreadySet(DefaultParameterValue.class, "setXmlValue", "value");
         }
     }
-
-    /**
-     * Invoked by JAXB at unmarshalling time.
-     *
-     * @see #getDescriptor()
-     */
-    private void setDescriptor(final ParameterDescriptor<T> descriptor) {
-        this.descriptor = descriptor;
-        assert (value == null) || descriptor.getValueClass().isInstance(value) : this;
-    }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/DefaultParameterValueGroup.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -18,7 +18,8 @@ package org.apache.sis.parameter;
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Map;
+import java.util.IdentityHashMap;
 import java.io.Serializable;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
@@ -132,13 +133,6 @@ public class DefaultParameterValueGroup
     private ParameterValueList values;
 
     /**
-     * Default constructor for JAXB only. The values list is initialized to {@code null},
-     * but will be assigned a value after XML unmarshalling.
-     */
-    private DefaultParameterValueGroup() {
-    }
-
-    /**
      * Creates a parameter group from the specified descriptor.
      *
      * <p><b>Usage note:</b> {@code ParameterValueGroup} are usually not instantiated directly. Instead, consider
@@ -504,7 +498,42 @@ public class DefaultParameterValueGroup
         ParameterFormat.print(this);
     }
 
-    // ---- XML SUPPORT ----------------------------------------------------
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Default constructor for JAXB only. The values list is initialized to {@code null},
+     * but will be assigned a value after XML unmarshalling.
+     */
+    private DefaultParameterValueGroup() {
+    }
+
+    /**
+     * Invoked by JAXB for setting the group parameter descriptor. Those parameter are redundant with
+     * the parameters associated to the values given to {@link #setValues(GeneralParameterValue[])},
+     * except the the group identification (name, <i>etc.</i>) and for any optional parameters which
+     * were not present in the above {@code GeneralParameterValue} array.
+     *
+     * @see #getDescriptor()
+     */
+    private void setDescriptor(final ParameterDescriptorGroup descriptor) {
+        if (values == null) {
+            values = new ParameterValueList(descriptor);
+        } else {
+            ReferencingUtilities.propertyAlreadySet(DefaultParameterValue.class, "setDescriptor", "group");
+        }
+    }
 
     /**
      * Invoked by JAXB for getting the parameters to marshal.
@@ -519,38 +548,57 @@ public class DefaultParameterValueGroup
      * Invoked by JAXB for setting the unmarshalled parameters. This method should be invoked last
      * (after {@link #setDescriptor(ParameterDescriptorGroup)}) even if the {@code parameterValue}
      * elements were first in the XML document. This is the case at least with the JAXB reference
-     * implementation.
+     * implementation, because the property type is an array (it would not work with a list).
+     *
+     * <p><b>Maintenance note:</b> the {@code "setValues"} method name is also hard-coded in
+     * {@link org.apache.sis.internal.jaxb.referencing.CC_GeneralOperationParameter} for logging purpose.</p>
      */
     private void setValues(final GeneralParameterValue[] parameters) {
-        final GeneralParameterDescriptor[] descriptors = new GeneralParameterDescriptor[parameters.length];
-        for (int i=0; i<descriptors.length; i++) {
-            descriptors[i] = parameters[i].getDescriptor();
-        }
-        if (values == null) {
+        ParameterValueList addTo = values;
+        if (addTo == null) {
             // Should never happen, unless the XML document is invalid and does not have a 'group' element.
-            
-        } else {
-            // We known that the descriptor is an instance of our DefaultParameterDescriptorGroup
-            // implementation because this is what we declare to the JAXBContext and in adapters.
-            ((DefaultParameterDescriptorGroup) values.descriptor).setDescriptors(descriptors);
-            values.clear();  // Because references to parameter descriptors have changed.
+            addTo = new ParameterValueList(new DefaultParameterDescriptorGroup());
         }
-        values.addAll(Arrays.asList(parameters));
+        /*
+         * Merge the descriptors declared in the <gml:group> element with the descriptors given in each
+         * <gml:parameterValue> element. The implementation is known to be DefaultParameterDescriptorGroup
+         * because this is the type declared in the JAXBContext and in adapters.
+         */
+        final Map<GeneralParameterDescriptor,GeneralParameterDescriptor> replacements =
+                new IdentityHashMap<GeneralParameterDescriptor,GeneralParameterDescriptor>(4);
+        ((DefaultParameterDescriptorGroup) addTo.descriptor).merge(getDescriptors(parameters), replacements);
+        addTo.clear();  // Because references to parameter descriptors have changed.
+        setValues(parameters, replacements, addTo);
     }
 
     /**
-     * Invoked by JAXB for setting the group parameter descriptor. Those parameter are redundant with
-     * the parameters associated to the values given to {@link #setValues(GeneralParameterValue[])},
-     * except the the group identification (name, <i>etc.</i>) and for any optional parameters which
-     * were not present in the above {@code GeneralParameterValue} array.
+     * Appends all parameter values. In this process, we may need to update the descriptor of some values
+     * if those descriptors changed as a result of the above merge process.
      *
-     * @see #getDescriptor()
+     * @param parameters   The parameters to add, or {@code null} for {@link #values}.
+     * @param replacements The replacements to apply in the {@code GeneralParameterValue} instances.
+     * @param addTo        Where to store the new values.
      */
-    private void setDescriptor(final ParameterDescriptorGroup descriptor) {
-        if (ReferencingUtilities.canSetProperty(DefaultParameterValue.class,
-                "setDescriptor", "group", values != null))
-        {
-            values = new ParameterValueList(descriptor);
+    @SuppressWarnings({"unchecked", "AssignmentToCollectionOrArrayFieldFromParameter"})
+    private void setValues(GeneralParameterValue[] parameters,
+            final Map<GeneralParameterDescriptor,GeneralParameterDescriptor> replacements,
+            final ParameterValueList addTo)
+    {
+        if (parameters == null) {
+            parameters = values.toArray();
+        }
+        for (final GeneralParameterValue p : parameters) {
+            final GeneralParameterDescriptor replacement = replacements.get(p.getDescriptor());
+            if (replacement != null) {
+                if (p instanceof DefaultParameterValue<?>) {
+                    ((DefaultParameterValue<?>) p).setDescriptor((ParameterDescriptor) replacement);
+                } else if (p instanceof DefaultParameterValueGroup) {
+                    ((DefaultParameterValueGroup) p).setValues(null, replacements,
+                            new ParameterValueList((ParameterDescriptorGroup) replacement));
+                }
+            }
+            addTo.add(p);
         }
+        values = addTo;
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterValueList.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -34,6 +34,7 @@ import org.opengis.metadata.Identifier;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.referencing.IdentifiedObjects;
 
 // Related to JDK7
 import org.apache.sis.internal.jdk7.JDK7;
@@ -241,14 +242,15 @@ final class ParameterValueList extends A
              * parameter name was not found, or the parameter descriptor does not matches.
              */
             final Identifier name = desc.getName();
+            final String code = name.getCode();
             for (final GeneralParameterDescriptor descriptor : descriptors) {
-                if (name.equals(descriptor.getName())) {
+                if (IdentifiedObjects.isHeuristicMatchForName(descriptor, code)) {
                     throw new IllegalArgumentException(Errors.format(
                             Errors.Keys.MismatchedParameterDescriptor_1, name));
                 }
             }
             throw new InvalidParameterNameException(Errors.format(Errors.Keys.ParameterNotFound_2,
-                    Verifier.getDisplayName(descriptor), name), name.getCode());
+                    Verifier.getDisplayName(descriptor), name), code);
         }
     }
 
@@ -313,6 +315,14 @@ final class ParameterValueList extends A
     }
 
     /**
+     * Returns the parameters in an array.
+     */
+    @Override
+    public GeneralParameterValue[] toArray() {
+        return Arrays.copyOf(values, size);
+    }
+
+    /**
      * Returns a string representation of this list.
      */
     @Override

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1701520&r1=1701519&r2=1701520&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] Sun Sep  6 19:52:36 2015
@@ -220,6 +220,35 @@ public abstract class Parameters impleme
     }
 
     /**
+     * Returns the descriptors of the given parameters, in the same order.
+     * Special cases:
+     *
+     * <ul>
+     *   <li>If the given array is {@code null}, then this method returns {@code null}.
+     *   <li>If an element of the given array is {@code null}, then the corresponding
+     *       element of the returned array is also {@code null}.</li>
+     * </ul>
+     *
+     * @param  parameters The parameter values from which to get the descriptors, or {@code null}.
+     * @return The descriptors of the given parameter values, or {@code null} if the {@code parameters} argument was null.
+     *
+     * @since 0.6
+     */
+    public static GeneralParameterDescriptor[] getDescriptors(final GeneralParameterValue... parameters) {
+        if (parameters == null) {
+            return null;
+        }
+        final GeneralParameterDescriptor[] descriptors = new GeneralParameterDescriptor[parameters.length];
+        for (int i=0; i<parameters.length; i++) {
+            final GeneralParameterValue p = parameters[i];
+            if (p != null) {
+                descriptors[i] = p.getDescriptor();
+            }
+        }
+        return descriptors;
+    }
+
+    /**
      * Gets the parameter name as an instance of {@code MemberName}.
      * This method performs the following checks:
      *

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=1701520&r1=1701519&r2=1701520&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] Sun Sep  6 19:52:36 2015
@@ -29,6 +29,7 @@ import javax.xml.bind.annotation.XmlType
 import javax.xml.bind.annotation.XmlSeeAlso;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlSchemaType;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
 import org.opengis.util.GenericName;
@@ -226,16 +227,6 @@ public class AbstractIdentifiedObject ex
     private transient int hashCode;
 
     /**
-     * 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.
-     */
-    AbstractIdentifiedObject() {
-        remarks = null;
-        deprecated = false;
-    }
-
-    /**
      * Constructs an object from the given properties. Keys are strings from the table below.
      * The map given in argument shall contain an entry at least for the
      * {@value org.opengis.referencing.IdentifiedObject#NAME_KEY} or
@@ -503,6 +494,7 @@ public class AbstractIdentifiedObject ex
      * since it may depends on the marshalling context.</p>
      */
     @XmlID
+    @XmlSchemaType(name = "ID")
     @XmlAttribute(name = "id", namespace = Namespaces.GML, required = true)
     @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
     final String getID() {
@@ -535,144 +527,6 @@ public class AbstractIdentifiedObject ex
     }
 
     /**
-     * Returns a single element from the {@code Set<Identifier>} collection, or {@code null} if none.
-     * We have to define this method because ISO 19111 defines the {@code identifiers} property as a collection
-     * while GML 3.2 defines it as a singleton.
-     *
-     * <p>This method searches for the following identifiers, in preference order:</p>
-     * <ul>
-     *   <li>The first identifier having a code that begin with {@code "urn:"}.</li>
-     *   <li>The first identifier having a code that begin with {@code "http:"}.</li>
-     *   <li>The first identifier, converted to the {@code "urn:} syntax if possible.</li>
-     * </ul>
-     */
-    @XmlElement(name = "identifier")
-    final Code getIdentifier() {
-        return Code.forIdentifiedObject(getClass(), identifiers);
-    }
-
-    /**
-     * Invoked by JAXB at unmarshalling time for setting the identifier.
-     */
-    private void setIdentifier(final Code identifier) {
-        if (identifier != null) {
-            final ReferenceIdentifier id = identifier.getIdentifier();
-            if (id != null && ReferencingUtilities.canSetProperty(AbstractIdentifiedObject.class,
-                    "setIdentifier", "identifier", identifiers != null))
-            {
-                identifiers = Collections.singleton(id);
-            }
-        }
-    }
-
-    /**
-     * A writable view over the {@linkplain AbstractIdentifiedObject#getName() name} of the enclosing object followed by
-     * all {@linkplain AbstractIdentifiedObject#getAlias() aliases} which are instance of {@link ReferenceIdentifier}.
-     * Used by JAXB only at (un)marshalling time because GML merges the name and aliases in a single {@code <gml:name>}
-     * property.
-     */
-    private final class Names extends AbstractCollection<ReferenceIdentifier> {
-        /**
-         * Invoked by JAXB before to write in the collection at unmarshalling time.
-         * Do nothing since our object is already empty.
-         */
-        @Override
-        public void clear() {
-        }
-
-        /**
-         * Returns the number of name and aliases that are instance of {@link ReferenceIdentifier}.
-         */
-        @Override
-        public int size() {
-            return NameIterator.count(AbstractIdentifiedObject.this);
-        }
-
-        /**
-         * Returns an iterator over the name and aliases that are instance of {@link ReferenceIdentifier}.
-         */
-        @Override
-        public Iterator<ReferenceIdentifier> iterator() {
-            return new NameIterator(AbstractIdentifiedObject.this);
-        }
-
-        /**
-         * Invoked by JAXB at unmarshalling time for each identifier. The first identifier will be taken
-         * as the name and all other identifiers (if any) as aliases.
-         *
-         * <p>Some (but not all) JAXB implementations never invoke setter method for collections.
-         * Instead they invoke {@link AbstractIdentifiedObject#getNames()} and add directly the identifiers
-         * in the returned collection. Consequently this method must writes directly in the enclosing object.
-         * See <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a> for more information.</p>
-         */
-        @Override
-        public boolean add(final ReferenceIdentifier id) {
-            addName(id);
-            return true;
-        }
-    }
-
-    /**
-     * Implementation of {@link Names#add(ReferenceIdentifier)}, defined in the enclosing class
-     * for access to private fields without compiler-generated bridge methods.
-     */
-    final void addName(final ReferenceIdentifier id) {
-        if (name == NilReferencingObject.UNNAMED) {
-            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);
-            }
-        }
-    }
-
-    /**
-     * Returns the {@link #name} and all aliases which are also instance of {@link ReferenceIdentifier}.
-     * The later happen often in SIS implementation since many aliases are instance of {@link NamedIdentifier}.
-     *
-     * <p>The returned collection is <cite>live</cite>: adding elements in that collection will modify this
-     * {@code AbstractIdentifiedObject} instance. This is needed for unmarshalling with JAXB and should not
-     * be used in other context.</p>
-     *
-     * <div class="section">Why there is no <code>setNames(…)</code> method</div>
-     * Some JAXB implementations never invoke setter method for collections. Instead they invoke the getter and
-     * add directly the identifiers in the returned collection. Whether JAXB will perform or not a final call to
-     * {@code setNames(…)} is JAXB-implementation dependent (JDK7 does but JDK6 and JDK8 early access do not).
-     * It seems a more portable approach (at least for JAXB reference implementations) to design our class
-     * without setter method, in order to have the same behavior on all supported JDK versions.
-     *
-     * @see <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a>
-     */
-    @XmlElement(name = "name", required = true)
-    final Collection<ReferenceIdentifier> getNames() {
-        return new Names();
-    }
-
-    /**
      * Returns the primary name by which this object is identified.
      *
      * @return The primary name.
@@ -1076,4 +930,168 @@ public class AbstractIdentifiedObject ex
         WKTUtilities.appendName(this, formatter, ElementKind.forType(getClass()));
         return null;
     }
+
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 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.
+     */
+    AbstractIdentifiedObject() {
+        remarks = null;
+        deprecated = false;
+    }
+
+    /**
+     * Returns a single element from the {@code Set<Identifier>} collection, or {@code null} if none.
+     * We have to define this method because ISO 19111 defines the {@code identifiers} property as a collection
+     * while GML 3.2 defines it as a singleton.
+     *
+     * <p>This method searches for the following identifiers, in preference order:</p>
+     * <ul>
+     *   <li>The first identifier having a code that begin with {@code "urn:"}.</li>
+     *   <li>The first identifier having a code that begin with {@code "http:"}.</li>
+     *   <li>The first identifier, converted to the {@code "urn:} syntax if possible.</li>
+     * </ul>
+     */
+    @XmlElement(name = "identifier")
+    final Code getIdentifier() {
+        return Code.forIdentifiedObject(getClass(), identifiers);
+    }
+
+    /**
+     * Invoked by JAXB at unmarshalling time for setting the identifier.
+     */
+    private void setIdentifier(final Code identifier) {
+        if (identifiers == null) {
+            if (identifier != null) {
+                final ReferenceIdentifier id = identifier.getIdentifier();
+                if (id != null) {
+                    identifiers = Collections.singleton(id);
+                }
+            }
+        } else {
+            ReferencingUtilities.propertyAlreadySet(AbstractIdentifiedObject.class, "setIdentifier", "identifier");
+        }
+    }
+
+    /**
+     * Returns the {@link #name} and all aliases which are also instance of {@link Identifier}.
+     * The later happen often in SIS implementation since many aliases are instance of {@link NamedIdentifier}.
+     *
+     * <p>The returned collection is <cite>live</cite>: adding elements in that collection will modify this
+     * {@code AbstractIdentifiedObject} instance. This is needed for unmarshalling with JAXB and should not
+     * be used in other context.</p>
+     *
+     * <div class="section">Why there is no <code>setNames(…)</code> method</div>
+     * Some JAXB implementations never invoke setter method for collections. Instead they invoke the getter and
+     * add directly the identifiers in the returned collection. Whether JAXB will perform or not a final call to
+     * {@code setNames(…)} is JAXB-implementation dependent (JDK7 does but JDK6 and JDK8 early access do not).
+     * It seems a more portable approach (at least for JAXB reference implementations) to design our class
+     * without setter method, in order to have the same behavior on all supported JDK versions.
+     *
+     * @see <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a>
+     */
+    @XmlElement(name = "name", required = true)
+    final Collection<ReferenceIdentifier> getNames() {
+        return new Names();
+    }
+
+    /**
+     * A writable view over the {@linkplain AbstractIdentifiedObject#getName() name} of the enclosing object followed
+     * 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.
+     */
+    private final class Names extends AbstractCollection<ReferenceIdentifier> {
+        /**
+         * Invoked by JAXB before to write in the collection at unmarshalling time.
+         * Do nothing since our object is already empty.
+         */
+        @Override
+        public void clear() {
+        }
+
+        /**
+         * Returns the number of name and aliases that are instance of {@link Identifier}.
+         */
+        @Override
+        public int size() {
+            return NameIterator.count(AbstractIdentifiedObject.this);
+        }
+
+        /**
+         * Returns an iterator over the name and aliases that are instance of {@link Identifier}.
+         */
+        @Override
+        public Iterator<ReferenceIdentifier> iterator() {
+            return new NameIterator(AbstractIdentifiedObject.this);
+        }
+
+        /**
+         * Invoked by JAXB at unmarshalling time for each identifier. The first identifier will be taken
+         * as the name and all other identifiers (if any) as aliases.
+         *
+         * <p>Some (but not all) JAXB implementations never invoke setter method for collections.
+         * Instead they invoke {@link AbstractIdentifiedObject#getNames()} and add directly the identifiers
+         * in the returned collection. Consequently this method must writes directly in the enclosing object.
+         * See <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a> for more information.</p>
+         */
+        @Override
+        public boolean add(final ReferenceIdentifier id) {
+            addName(id);
+            return true;
+        }
+    }
+
+    /**
+     * Implementation of {@link Names#add(Identifier)}, defined in the enclosing class
+     * for access to private fields without compiler-generated bridge methods.
+     */
+    final void addName(final ReferenceIdentifier id) {
+        if (name == NilReferencingObject.UNNAMED) {
+            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);
+            }
+        }
+    }
 }

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=1701520&r1=1701519&r2=1701520&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] Sun Sep  6 19:52:36 2015
@@ -89,16 +89,6 @@ public class AbstractReferenceSystem ext
     private final InternationalString scope;
 
     /**
-     * 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.
-     */
-    AbstractReferenceSystem() {
-        domainOfValidity = null;
-        scope = null;
-    }
-
-    /**
      * Constructs a reference system from the given properties.
      * The properties given in argument follow the same rules than for the
      * {@linkplain AbstractIdentifiedObject#AbstractIdentifiedObject(Map) super-class constructor}.
@@ -252,4 +242,28 @@ public class AbstractReferenceSystem ext
     protected long computeHashCode() {
         return super.computeHashCode() + Objects.hash(domainOfValidity, scope);
     }
+
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 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.
+     */
+    AbstractReferenceSystem() {
+        domainOfValidity = null;
+        scope = null;
+    }
 }

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=1701520&r1=1701519&r2=1701520&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] Sun Sep  6 19:52:36 2015
@@ -122,15 +122,6 @@ public class AbstractCRS extends Abstrac
     private transient Map<AxesConvention,AbstractCRS> forConvention;
 
     /**
-     * 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.
-     */
-    AbstractCRS() {
-        super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE);
-    }
-
-    /**
      * Creates a coordinate reference system from the given properties and coordinate system.
      * The properties given in argument follow the same rules than for the
      * {@linkplain AbstractReferenceSystem#AbstractReferenceSystem(Map) super-class constructor}.
@@ -290,47 +281,6 @@ public class AbstractCRS extends Abstrac
     }
 
     /**
-     * Sets the coordinate system to the given value. This method is invoked only by JAXB at
-     * unmarshalling time and can be invoked only if the coordinate system has never been set.
-     *
-     * <div class="note"><b>Implementation note:</b>
-     * It was easy to put JAXB annotations directly on datum fields in subclasses because each CRS type
-     * can be associated to only one datum type. But we do not have this convenience for coordinate systems,
-     * where the same CRS may accept different kinds of CS. In GML, the different kinds of CS are marshalled
-     * as different XML elements. The usual way to handle such {@code <xs:choice>} with JAXB is to annotate
-     * a single method like below:
-     *
-     * {@preformat java
-     *   &#64;Override
-     *   &#64;XmlElements({
-     *     &#64;XmlElement(name = "cartesianCS",   type = DefaultCartesianCS.class),
-     *     &#64;XmlElement(name = "affineCS",      type = DefaultAffineCS.class),
-     *     &#64;XmlElement(name = "cylindricalCS", type = DefaultCylindricalCS.class),
-     *     &#64;XmlElement(name = "linearCS",      type = DefaultLinearCS.class),
-     *     &#64;XmlElement(name = "polarCS",       type = DefaultPolarCS.class),
-     *     &#64;XmlElement(name = "sphericalCS",   type = DefaultSphericalCS.class),
-     *     &#64;XmlElement(name = "userDefinedCS", type = DefaultUserDefinedCS.class)
-     *   })
-     *   public CoordinateSystem getCoordinateSystem() {
-     *       return super.getCoordinateSystem();
-     *   }
-     * }
-     *
-     * However our attempts to apply this approach have not been conclusive.
-     * For an unknown reason, the unmarshalled CS object was empty.</div>
-     *
-     * @param  name The property name, used only in case of error message to format.
-     * @throws IllegalStateException If the coordinate system has already been set.
-     */
-    final void setCoordinateSystem(final String name, final CoordinateSystem cs) {
-        if (cs != null && ReferencingUtilities.canSetProperty(AbstractCRS.class,
-                "setCoordinateSystem", name, coordinateSystem != null))
-        {
-            coordinateSystem = cs;
-        }
-    }
-
-    /**
      * Returns the existing CRS for the given convention, or {@code null} if none.
      */
     final AbstractCRS getCached(final AxesConvention convention) {
@@ -537,4 +487,45 @@ public class AbstractCRS extends Abstrac
         formatter.restoreContextualUnit(unit, oldUnit);
         formatter.newLine(); // For writing the ID[…] element on its own line.
     }
+
+
+
+
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+    ////////                                                                                  ////////
+    ////////                               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.                                              ////////
+    ////////                                                                                  ////////
+    //////////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 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.
+     */
+    AbstractCRS() {
+        super(org.apache.sis.internal.referencing.NilReferencingObject.INSTANCE);
+    }
+
+    /**
+     * Sets the coordinate system to the given value.
+     * This method is indirectly invoked by JAXB at unmarshalling time.
+     *
+     * @param  name The property name, used only in case of error message to format. Can be null for auto-detect.
+     * @throws IllegalStateException If the coordinate system has already been set.
+     */
+    final void setCoordinateSystem(String name, final CoordinateSystem cs) {
+        if (coordinateSystem == null) {
+            coordinateSystem = cs;
+        } else {
+            if (name == null) {
+                name = String.valueOf(ReferencingUtilities.toPropertyName(CoordinateSystem.class, cs.getClass()));
+            }
+            ReferencingUtilities.propertyAlreadySet(AbstractCRS.class, "setCoordinateSystem", name);
+        }
+    }
 }



Mime
View raw message