sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] branch geoapi-4.0 updated: Added gco:Multiplicity, MultiplicityRange and UnlimitedInteger. Those types were not present because not used by ISO 19115 (metadata), but they are used by ISO 19110 (Feature Catalog).
Date Thu, 28 Jun 2018 19:49:26 GMT
This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new 6c23235  Added gco:Multiplicity, MultiplicityRange and UnlimitedInteger. Those types
were not present because not used by ISO 19115 (metadata), but they are used by ISO 19110
(Feature Catalog).
6c23235 is described below

commit 6c232356fd59b804f5cefb3cfe38c31bf35d1950
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Thu Jun 28 21:48:09 2018 +0200

    Added gco:Multiplicity, MultiplicityRange and UnlimitedInteger. Those types were not present
because not used by ISO 19115 (metadata), but they are used by ISO 19110 (Feature Catalog).
---
 .../apache/sis/internal/jaxb/gco/GO_Decimal.java   |   2 +-
 .../apache/sis/internal/jaxb/gco/GO_Integer.java   |   7 +-
 .../apache/sis/internal/jaxb/gco/GO_Integer64.java |   4 +-
 ...GO_Integer64.java => GO_MultiplicityRange.java} |  53 ++++-----
 .../apache/sis/internal/jaxb/gco/GO_Record.java    |   2 +-
 .../sis/internal/jaxb/gco/GO_RecordType.java       |   2 +-
 ...{GO_Integer64.java => GO_UnlimitedInteger.java} |  46 ++++----
 .../apache/sis/internal/jaxb/gco/Multiplicity.java |  92 +++++++++++++++
 .../sis/internal/jaxb/gco/MultiplicityRange.java   | 107 ++++++++++++++++++
 .../sis/internal/jaxb/gco/UnlimitedInteger.java    | 120 ++++++++++++++++++++
 .../sis/internal/metadata/MetadataTypes.java       |   4 +-
 .../sis/internal/jaxb/gco/MultiplicityTest.java    | 124 +++++++++++++++++++++
 .../sis/internal/jaxb/lan/PT_LocaleTest.java       |  12 +-
 .../test/java/org/apache/sis/test/XMLTestCase.java |  25 +++--
 .../apache/sis/test/mock/FeatureAttributeMock.java |  49 ++++++++
 .../org/apache/sis/test/mock/package-info.java     |   5 +-
 .../apache/sis/test/suite/MetadataTestSuite.java   |   1 +
 .../apache/sis/metadata/xml/2007/Multiplicity.xml  |  56 ++++++++++
 .../apache/sis/metadata/xml/2016/Multiplicity.xml  |  55 +++++++++
 19 files changed, 692 insertions(+), 74 deletions(-)

diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java
index 8902346..e83bd29 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Decimal.java
@@ -78,7 +78,7 @@ public final class GO_Decimal extends PropertyType<GO_Decimal, Double>
{
      *         by {@code <gco:Decimal>} element.
      */
     @Override
-    public GO_Decimal wrap(final Double value) {
+    protected GO_Decimal wrap(final Double value) {
         return new GO_Decimal(value);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java
index 9a7e8b3..c43c26a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer.java
@@ -22,7 +22,7 @@ import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * Wraps integer values in {@code <gco:Integer>} element.
+ * Wraps an integer value in an {@code <gco:Integer>} element.
  * The ISO 19115-3 standard requires most types to be wrapped by an element representing
the value type.
  * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper
element.
  * The role of this class is to add the {@code <gco:…>} wrapper element required
by ISO 19115-3.
@@ -32,6 +32,7 @@ import javax.xml.bind.annotation.XmlType;
  * @version 1.0
  *
  * @see GO_Integer64
+ * @see GO_UnlimitedInteger
  *
  * @since 0.3
  * @module
@@ -72,7 +73,7 @@ public class GO_Integer extends PropertyType<GO_Integer, Integer>
{
      *         by {@code <gco:Integer>} element.
      */
     @Override
-    public GO_Integer wrap(final Integer value) {
+    protected GO_Integer wrap(final Integer value) {
         return new GO_Integer(value);
     }
 
@@ -110,7 +111,7 @@ public class GO_Integer extends PropertyType<GO_Integer, Integer>
{
          *
          * @return a non-null value only if marshalling ISO 19115-3 or newer.
          */
-        @Override public GO_Integer wrap(final Integer value) {
+        @Override protected GO_Integer wrap(final Integer value) {
             return accept2014() ? super.wrap(value) : null;
         }
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
index 61ad10f..bd46148 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
@@ -21,7 +21,7 @@ import javax.xml.bind.annotation.XmlSchemaType;
 
 
 /**
- * Surrounds long values by {@code <gco:Integer>}.
+ * Wraps a long value in an {@code <gco:Integer>} element.
  * The ISO 19115-3 standard requires most types to be wrapped by an element representing
the value type.
  * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper
element.
  * The role of this class is to add the {@code <gco:…>} wrapper element required
by ISO 19115-3.
@@ -66,7 +66,7 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64, Long>
{
      *         by {@code <gco:Integer>} element.
      */
     @Override
-    public GO_Integer64 wrap(final Long value) {
+    protected GO_Integer64 wrap(final Long value) {
         return new GO_Integer64(value);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_MultiplicityRange.java
similarity index 55%
copy from core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
copy to core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_MultiplicityRange.java
index 61ad10f..6ff0183 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_MultiplicityRange.java
@@ -17,25 +17,24 @@
 package org.apache.sis.internal.jaxb.gco;
 
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlSchemaType;
+import org.apache.sis.measure.NumberRange;
 
 
 /**
- * Surrounds long values by {@code <gco:Integer>}.
- * The ISO 19115-3 standard requires most types to be wrapped by an element representing
the value type.
- * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper
element.
- * The role of this class is to add the {@code <gco:…>} wrapper element required
by ISO 19115-3.
+ * Adapter for a component of a multiplicity, consisting of an non-negative lower bound,
+ * and a potentially infinite upper bound.
  *
- * @author  Cédric Briançon (Geomatys)
- * @version 0.4
- * @since   0.4
+ * @author  Guilhem Legal (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
  * @module
  */
-public final class GO_Integer64 extends PropertyType<GO_Integer64, Long> {
+final class GO_MultiplicityRange extends PropertyType<GO_MultiplicityRange, NumberRange<Integer>>
{
     /**
      * Empty constructor used only by JAXB.
      */
-    public GO_Integer64() {
+    GO_MultiplicityRange() {
     }
 
     /**
@@ -43,31 +42,32 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64,
Long> {
      *
      * @param  value  the value.
      */
-    private GO_Integer64(final Long value) {
-        super(value, value == 0L);
+    private GO_MultiplicityRange(final NumberRange<Integer> value) {
+        super(value, false);
     }
 
     /**
      * Returns the Java type which is bound by this adapter.
      *
-     * @return {@code Long.class}
+     * @return {@code MultiplicityRange.class}
      */
     @Override
-    protected Class<Long> getBoundType() {
-        return Long.class;
+    @SuppressWarnings("unchecked")
+    protected final Class<NumberRange<Integer>> getBoundType() {
+        return (Class) NumberRange.class;
     }
 
     /**
      * Allows JAXB to change the result of the marshalling process, according to the
      * ISO 19115-3 standard and its requirements about primitive types.
      *
-     * @param  value  the integer value we want to surround by an element representing its
type.
-     * @return an adaptation of the integer value, that is to say a integer value surrounded
-     *         by {@code <gco:Integer>} element.
+     * @param  value  the integer range we want to wrap in an element representing its type.
+     * @return a wrapper for the integer range, that is to say an integer value wrapped
+     *         by {@code <gco:MultiplicityRange>} element.
      */
     @Override
-    public GO_Integer64 wrap(final Long value) {
-        return new GO_Integer64(value);
+    protected GO_MultiplicityRange wrap(final NumberRange<Integer> value) {
+        return new GO_MultiplicityRange(value);
     }
 
     /**
@@ -75,10 +75,9 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64, Long>
{
      *
      * @return the value to be marshalled.
      */
-    @XmlElement(name = "Integer")
-    @XmlSchemaType(name = "integer")
-    public Long getElement() {
-        return metadata;
+    @XmlElement(name = "MultiplicityRange")
+    private MultiplicityRange getElement() {
+        return MultiplicityRange.wrap(metadata);
     }
 
     /**
@@ -86,7 +85,9 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64, Long>
{
      *
      * @param  metadata  the unmarshalled value.
      */
-    public void setElement(final Long metadata) {
-        this.metadata = metadata;
+    private void setElement(final MultiplicityRange metadata) {
+        if (metadata != null) {
+            this.metadata = metadata.value();
+        }
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Record.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Record.java
index 29c26ea..9f20985 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Record.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Record.java
@@ -105,7 +105,7 @@ public class GO_Record extends PropertyType<GO_Record, Record> {
          *
          * @return a non-null value only if marshalling ISO 19115-3 or newer.
          */
-        @Override public GO_Record wrap(final Record value) {
+        @Override protected GO_Record wrap(final Record value) {
             return accept2014() ? super.wrap(value) : null;
         }
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_RecordType.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_RecordType.java
index 968eb6c..03cf9f8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_RecordType.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_RecordType.java
@@ -105,7 +105,7 @@ public class GO_RecordType extends PropertyType<GO_RecordType, RecordType>
{
          *
          * @return a non-null value only if marshalling ISO 19115-3 or newer.
          */
-        @Override public GO_RecordType wrap(final RecordType value) {
+        @Override protected GO_RecordType wrap(final RecordType value) {
             return accept2014() ? super.wrap(value) : null;
         }
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_UnlimitedInteger.java
similarity index 63%
copy from core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
copy to core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_UnlimitedInteger.java
index 61ad10f..015a1ce 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_Integer64.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/GO_UnlimitedInteger.java
@@ -17,25 +17,30 @@
 package org.apache.sis.internal.jaxb.gco;
 
 import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
 
 
 /**
- * Surrounds long values by {@code <gco:Integer>}.
+ * Wraps an "unlimited" integer value in an {@code <gco:UnlimitedInteger>} element.
  * The ISO 19115-3 standard requires most types to be wrapped by an element representing
the value type.
  * The JAXB default behavior is to marshal primitive Java types directly, without such wrapper
element.
  * The role of this class is to add the {@code <gco:…>} wrapper element required
by ISO 19115-3.
  *
- * @author  Cédric Briançon (Geomatys)
- * @version 0.4
- * @since   0.4
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ *
+ * @see GO_Integer
+ * @see GO_Integer64
+ *
+ * @since 1.0
  * @module
  */
-public final class GO_Integer64 extends PropertyType<GO_Integer64, Long> {
+@XmlType(name = "UnlimitedInteger_PropertyType")
+final class GO_UnlimitedInteger extends PropertyType<GO_UnlimitedInteger, UnlimitedInteger>
{
     /**
      * Empty constructor used only by JAXB.
      */
-    public GO_Integer64() {
+    GO_UnlimitedInteger() {
     }
 
     /**
@@ -43,31 +48,31 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64,
Long> {
      *
      * @param  value  the value.
      */
-    private GO_Integer64(final Long value) {
-        super(value, value == 0L);
+    private GO_UnlimitedInteger(final UnlimitedInteger value) {
+        super(value, false);
     }
 
     /**
      * Returns the Java type which is bound by this adapter.
      *
-     * @return {@code Long.class}
+     * @return {@code UnlimitedInteger.class}
      */
     @Override
-    protected Class<Long> getBoundType() {
-        return Long.class;
+    protected final Class<UnlimitedInteger> getBoundType() {
+        return UnlimitedInteger.class;
     }
 
     /**
      * Allows JAXB to change the result of the marshalling process, according to the
      * ISO 19115-3 standard and its requirements about primitive types.
      *
-     * @param  value  the integer value we want to surround by an element representing its
type.
-     * @return an adaptation of the integer value, that is to say a integer value surrounded
-     *         by {@code <gco:Integer>} element.
+     * @param  value  the integer value we want to wrap in an element representing its type.
+     * @return a wrapper for the integer value, that is to say an integer value wrapped
+     *         by {@code <gco:UnlimitedInteger>} element.
      */
     @Override
-    public GO_Integer64 wrap(final Long value) {
-        return new GO_Integer64(value);
+    protected GO_UnlimitedInteger wrap(final UnlimitedInteger value) {
+        return new GO_UnlimitedInteger(value);
     }
 
     /**
@@ -75,9 +80,8 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64, Long>
{
      *
      * @return the value to be marshalled.
      */
-    @XmlElement(name = "Integer")
-    @XmlSchemaType(name = "integer")
-    public Long getElement() {
+    @XmlElement(name = "UnlimitedInteger")
+    public final UnlimitedInteger getElement() {
         return metadata;
     }
 
@@ -86,7 +90,7 @@ public final class GO_Integer64 extends PropertyType<GO_Integer64, Long>
{
      *
      * @param  metadata  the unmarshalled value.
      */
-    public void setElement(final Long metadata) {
+    public final void setElement(final UnlimitedInteger metadata) {
         this.metadata = metadata;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/Multiplicity.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/Multiplicity.java
new file mode 100644
index 0000000..df80e51
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/Multiplicity.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.jaxb.gco;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.apache.sis.measure.NumberRange;
+
+
+/**
+ * The possible cardinality of a relation. Represented by a set of simple multiplicity ranges.
+ * Example:
+ *
+ * {@preformat xml
+ *   <gco:Multiplicity>
+ *     <gco:range>
+ *       <gco:MultiplicityRange>
+ *         <gco:lower>
+ *           <gco:Integer>1</gco:Integer>
+ *         </gco:lower>
+ *         <gco:upper>
+ *           <gco:UnlimitedInteger isInfinite="false">15</gco:UnlimitedInteger>
+ *         </gco:upper>
+ *       </gco:MultiplicityRange>
+ *     </gco:range>
+ *   </gco:Multiplicity>
+ * }
+ *
+ * @author  Guilhem Legal (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+@XmlType(name = "Multiplicity_Type")
+public final class Multiplicity {
+    /**
+     * The multiplicity, defined as ranges of integers.
+     */
+    @XmlElementWrapper(name = "Multiplicity", required = true)
+    @XmlElement(name = "range", required = true)
+    @XmlJavaTypeAdapter(GO_MultiplicityRange.class)
+    private List<NumberRange<Integer>> range;
+
+    /**
+     * Creates a new multiplicity initialized with no ranges.
+     */
+    public Multiplicity() {
+    }
+
+    /**
+     * Creates a new multiplicity initialized with the given ranges.
+     *
+     * @param  ranges  the ranges.
+     */
+    @SafeVarargs
+    public Multiplicity(final NumberRange<Integer>... ranges) {
+        this.range = Arrays.asList(ranges);
+    }
+
+    /**
+     * Returns the multiplicity as a live list (change to this list are reflected to this
object).
+     *
+     * @return the multiplicity ranges as a live list.
+     */
+    @SuppressWarnings("ReturnOfCollectionOrArrayField")
+    public List<NumberRange<Integer>> range() {
+        if (range == null) {
+            range = new ArrayList<>();
+        }
+        return range;
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/MultiplicityRange.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/MultiplicityRange.java
new file mode 100644
index 0000000..fd70035
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/MultiplicityRange.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.jaxb.gco;
+
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.xml.NilReason;
+
+
+/**
+ * A component of a multiplicity, consisting of an non-negative lower bound, and a potentially
infinite upper bound.
+ *
+ * @author  Guilhem Legal (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+@XmlType(name = "MultiplicityRange_Type", propOrder = {
+    "lower",
+    "upper"
+})
+final class MultiplicityRange {
+    /**
+     * The lower bound.
+     */
+    @XmlElement(required = true)
+    @XmlJavaTypeAdapter(GO_Integer.class)
+    private Integer lower;
+
+    /**
+     * The upper bound.
+     */
+    @XmlElement(required = true)
+    @XmlJavaTypeAdapter(GO_UnlimitedInteger.class)
+    private UnlimitedInteger upper;
+
+    /**
+     * Creates an initially empty range.
+     * This is invoked by JAXB at unmarshalling time.
+     */
+    private MultiplicityRange() {
+    }
+
+    /**
+     * Creates a range initialized to the given value.
+     */
+    private MultiplicityRange(final NumberRange<Integer> range) {
+        if (range != null) {
+            lower = range.getMinValue();
+            if (lower == null) {
+                lower = NilReason.UNKNOWN.createNilObject(Integer.class);
+            } else if (!range.isMinIncluded()) {
+                lower = Math.incrementExact(lower);
+            }
+            upper = new UnlimitedInteger(range.getMaxValue(), range.isMaxIncluded());
+        } else {
+            lower = 0;
+            upper = new UnlimitedInteger();         // Initialized to missing value.
+        }
+    }
+
+    /**
+     * Wraps the given integer range in multiplicity range,
+     * or returns {@code null} if the given range is null.
+     */
+    static MultiplicityRange wrap(final NumberRange<Integer> range) {
+        return (range != null) ? new MultiplicityRange(range) : null;
+    }
+
+    /**
+     * Returns the value as a number range, or {@code null} if none.
+     */
+    NumberRange<Integer> value() {
+        if (lower != null && upper != null) {
+            final Integer h = upper.value();
+            if (h != null || upper.isInfinite()) {
+                return new NumberRange<>(Integer.class, lower, true, h, true);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns a string representation for debugging purpose.
+     */
+    @Override
+    public String toString() {
+        return String.valueOf(value());
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/UnlimitedInteger.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/UnlimitedInteger.java
new file mode 100644
index 0000000..80a9f14
--- /dev/null
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/gco/UnlimitedInteger.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.jaxb.gco;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+
+
+/**
+ * The {@code <gco:UnlimitedInteger>} value, used for {@link MultiplicityRange} implementation.
+ * Despite its name, this {@code UnlimitedInteger} implementation does not handle integers
of
+ * arbitrary size. The only difference with an ordinary integer is its capability to express
+ * infinity.
+ *
+ * @author  Guilhem Legal (Geomatys)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+@XmlType(name = "UnlimitedInteger_Type")
+@XmlRootElement(name = "UnlimitedInteger")
+final class UnlimitedInteger {
+    /**
+     * The value, limited to 32 bits integer for now. A null value is interpreted as missing
value,
+     * unless {@link #isInfinite} is {@code true}.
+     */
+    @XmlValue
+    @XmlSchemaType(name = "nonNegativeInteger")
+    private Integer value;
+
+    /**
+     * Whether the value should be considered infinite.
+     * An infinite value implies {@code xsi:nil = true}.
+     */
+    @XmlAttribute(name = "isInfinite")
+    private Boolean isInfinite;
+
+    /**
+     * Creates a new {@code gco:UnlimitedInteger} for a missing value.
+     */
+    UnlimitedInteger() {
+    }
+
+    /**
+     * Creates a new {@code gco:UnlimitedInteger} for the given value.
+     * A null value is interpreted as infinity (i.e. no bound).
+     */
+    UnlimitedInteger(Integer value, final boolean inclusive) {
+        if (value == null) {
+            isInfinite = Boolean.TRUE;
+        } else {
+            if (!inclusive) {
+                value = Math.decrementExact(value);
+            }
+            this.value = value;
+        }
+    }
+
+    /**
+     * Returns whether the value should be considered infinite.
+     */
+    final boolean isInfinite() {
+        return (isInfinite != null) && isInfinite;
+    }
+
+    /**
+     * Returns the value, or {@code null} if the value is infinite.
+     * This method does not verify if the value is valid (non-nil).
+     */
+    final Integer value() {
+        return isInfinite() ? null : value;
+    }
+
+    /**
+     * Returns whether the value should be considered unspecified. An infinite value is considered
nil.
+     * This method never returns {@code false}; if the value is not nil, then {@code null}
is returned.
+     */
+    @XmlAttribute(name = "nil", namespace = XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)
+    private Boolean getNil() {
+        return (value == null) ? Boolean.TRUE : null;
+    }
+
+    /**
+     * Sets whether the value should be considered unspecified.
+     * This method is invoked by JAXB at unmarshalling time.
+     */
+    private void setNil(final Boolean nil) {
+        if (nil != null && nil) {
+            value = null;
+            // Leave 'isInfinite' unchanged since an infinite value is also nil.
+        }
+    }
+
+    /**
+     * Returns a string representation for debugging purpose only.
+     */
+    @Override
+    public String toString() {
+        return isInfinite() ? "∞" : (value == null) ? "nil" : value.toString();
+    }
+}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
index 07665ad..baec5da 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataTypes.java
@@ -23,6 +23,7 @@ import org.opengis.metadata.content.ImageDescription;
 import org.opengis.metadata.lineage.ProcessStep;
 import org.opengis.metadata.lineage.Source;
 import org.apache.sis.internal.jaxb.TypeRegistration;
+import org.apache.sis.internal.jaxb.gco.Multiplicity;
 import org.apache.sis.internal.jaxb.gmi.LE_ProcessStep;
 import org.apache.sis.internal.jaxb.gmi.LE_Source;
 import org.apache.sis.internal.jaxb.gmi.MI_Band;
@@ -42,7 +43,7 @@ import org.opengis.metadata.spatial.Georeferenceable;
  * This class is declared in the {@code META-INF/services/org.apache.sis.internal.jaxb.TypeRegistration}
file.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  */
@@ -53,6 +54,7 @@ public final class MetadataTypes extends TypeRegistration {
     @Override
     protected void getTypes(final Collection<Class<?>> addTo) {
         addTo.add(DefaultMetadata.class);
+        addTo.add(Multiplicity.class);          // Not used directly by ISO 19115 metadata,
but used by Feature Catalog.
     }
 
     /**
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/gco/MultiplicityTest.java
b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/gco/MultiplicityTest.java
new file mode 100644
index 0000000..da28840
--- /dev/null
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/gco/MultiplicityTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.internal.jaxb.gco;
+
+import java.util.Collections;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import org.apache.sis.util.Version;
+import org.apache.sis.util.iso.Names;
+import org.apache.sis.measure.NumberRange;
+import org.apache.sis.metadata.xml.TestUsingFile;
+import org.apache.sis.test.mock.FeatureAttributeMock;
+import org.apache.sis.xml.MarshallerPool;
+import org.apache.sis.xml.XML;
+import org.junit.AfterClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Tests {@link MultiplicityRange}
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+public final strictfp class MultiplicityTest extends TestUsingFile {
+    /**
+     * An XML file containing multiplicity declarations.
+     */
+    private static final String FILENAME = "Multiplicity.xml";
+
+    /**
+     * A poll of configured {@code Marshaller} and {@code Unmarshaller}.
+     */
+    private static MarshallerPool pool;
+
+    /**
+     * Returns the XML (un)marshaller pool to be shared by all test methods.
+     * This test uses its own pool instead of {@link #getMarshallerPool()}
+     * in order to use {@link FeatureAttributeMock}.
+     *
+     * @return the marshaller pool for this test.
+     * @throws JAXBException if an error occurred while creating the pool.
+     */
+    @Override
+    protected MarshallerPool getMarshallerPool() throws JAXBException {
+        if (pool == null) {
+            pool = new MarshallerPool(JAXBContext.newInstance(FeatureAttributeMock.class),
+                        Collections.singletonMap(XML.LENIENT_UNMARSHAL, Boolean.TRUE));
+        }
+        return pool;
+    }
+
+    /**
+     * Invoked by JUnit after the execution of every tests in order to dispose
+     * the {@link MarshallerPool} instance used internally by this class.
+     */
+    @AfterClass
+    public static void disposeMarshallerPool() {
+        pool = null;
+    }
+
+    /**
+     * Creates a multiplicity instance with the same content than in {@value #FILENAME} file.
+     *
+     * @param  requireInclusive  0 if we are allowed to create range with exclusive bounds,
or
+     *                           1 if all bounds shall be inclusive.
+     */
+    private FeatureAttributeMock create(final int requireInclusive) {
+        final FeatureAttributeMock f = new FeatureAttributeMock();
+        f.memberName = Names.createLocalName(null, null, "Multiplicity test");
+        f.cardinality = new Multiplicity(
+                new NumberRange<>(Integer.class, 0, true, 233333 - requireInclusive,
requireInclusive != 0),
+                new NumberRange<>(Integer.class, requireInclusive, requireInclusive
!= 0, null, false));
+        return f;
+    }
+
+    /**
+     * Tests marshalling of a few multiplicity using the specified version of metadata schema.
+     *
+     * @param  filename  name of the file containing expected result.
+     */
+    private void marshalAndCompare(final String filename, final Version version) throws JAXBException
{
+        assertMarshalEqualsFile(filename, create(0), version, "xmlns:*", "xsi:*");
+    }
+
+    /**
+     * Tests marshalling to legacy ISO 19139:2007 schema.
+     *
+     * @throws JAXBException if an error occurred during (un)marshalling.
+     */
+    @Test
+    public void testMarshallingLegacy() throws JAXBException {
+        marshalAndCompare(XML2007+FILENAME, VERSION_2007);
+    }
+
+    /**
+     * Tests unmarshalling from legacy ISO 19139:2007 schema.
+     *
+     * @throws JAXBException if an error occurred during (un)marshalling.
+     */
+    @Test
+    public void testUnmarshallingLegacy() throws JAXBException {
+        final FeatureAttributeMock metadata = unmarshalFile(FeatureAttributeMock.class, XML2007+FILENAME);
+        assertEquals(create(1).cardinality.range(), metadata.cardinality.range());
+    }
+}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/PT_LocaleTest.java
b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/PT_LocaleTest.java
index bab81fa..f7064dd 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/PT_LocaleTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/lan/PT_LocaleTest.java
@@ -46,12 +46,12 @@ public final strictfp class PT_LocaleTest extends TestUsingFile {
      * The locales to use for the tests. For better test coverage we need at least:
      *
      * <ul>
-     *   <li>One locale which is a language without specifying the country</li>
+     *   <li>One locale which is a language without specifying the country.</li>
      *   <li>At least two different countries for the same language.</li>
      * </ul>
      */
-    private static final Locale[] LOCALES = {
-            Locale.ENGLISH, Locale.JAPANESE, Locale.CANADA, Locale.FRANCE, Locale.CANADA_FRENCH
+    private final Locale[] locales = {
+        Locale.ENGLISH, Locale.JAPANESE, Locale.CANADA, Locale.FRANCE, Locale.CANADA_FRENCH
     };
 
     /**
@@ -64,7 +64,7 @@ public final strictfp class PT_LocaleTest extends TestUsingFile {
             throws JAXBException
     {
         final DefaultMetadata metadata = new DefaultMetadata();
-        metadata.setLanguages(Arrays.asList(LOCALES));
+        metadata.setLanguages(Arrays.asList(locales));
         assertMarshalEqualsFile(filename, metadata, version, STRICT, ignoredNodes,
                 new String[] {"xmlns:*", "xsi:*"});
     }
@@ -99,7 +99,7 @@ public final strictfp class PT_LocaleTest extends TestUsingFile {
     @Test
     public void testUnmarshalling() throws JAXBException {
         final DefaultMetadata metadata = unmarshalFile(DefaultMetadata.class, XML2016+FILENAME);
-        assertArrayEquals(LOCALES, metadata.getLanguages().toArray());
+        assertArrayEquals(locales, metadata.getLanguages().toArray());
     }
 
     /**
@@ -110,6 +110,6 @@ public final strictfp class PT_LocaleTest extends TestUsingFile {
     @Test
     public void testUnmarshallingLegacy() throws JAXBException {
         final DefaultMetadata metadata = unmarshalFile(DefaultMetadata.class, XML2007+FILENAME);
-        assertArrayEquals(LOCALES, metadata.getLanguages().toArray());
+        assertArrayEquals(locales, metadata.getLanguages().toArray());
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/XMLTestCase.java b/core/sis-metadata/src/test/java/org/apache/sis/test/XMLTestCase.java
index 77fd71d..d3992b0 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/XMLTestCase.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/XMLTestCase.java
@@ -122,9 +122,10 @@ public abstract strictfp class XMLTestCase extends TestCase {
     }
 
     /**
-     * Returns the default XML (un)marshaller pool potentially shared by test methods in
all sub-classes.
-     * The (un)marshallers locale is set to {@link Locale#UK} (the language of ISO standards)
and their
-     * timezone is arbitrarily set to CET (<cite>Central European Time</cite>).
+     * Returns the XML (un)marshaller for the tests in this class. The default implementation
+     * returns a XML (un)marshaller pool potentially shared by test methods in all sub-classes.
+     * The (un)marshallers locale is set to {@link Locale#UK} (the language of ISO standards)
+     * and their timezone is arbitrarily set to CET (<cite>Central European Time</cite>).
      *
      * <div class="note"><b>Note:</b>
      * We intentionally use a timezone different than UTC in order to have an error of one
or two hours
@@ -133,15 +134,17 @@ public abstract strictfp class XMLTestCase extends TestCase {
      * @return the shared (un)marshaller pool.
      * @throws JAXBException if an error occurred while creating the JAXB marshaller.
      */
-    protected static synchronized MarshallerPool getMarshallerPool() throws JAXBException
{
-        if (defaultPool == null) {
-            final Map<String,Object> properties = new HashMap<>(4);
-            assertNull(properties.put(XML.LOCALE, Locale.UK));
-            assertNull(properties.put(XML.TIMEZONE, TIMEZONE));
-            assertNull(properties.put(XML.LENIENT_UNMARSHAL, Boolean.TRUE));
-            defaultPool = new MarshallerPool(properties);
+    protected MarshallerPool getMarshallerPool() throws JAXBException {
+        synchronized (XMLTestCase.class) {
+            if (defaultPool == null) {
+                final Map<String,Object> properties = new HashMap<>(4);
+                assertNull(properties.put(XML.LOCALE, Locale.UK));
+                assertNull(properties.put(XML.TIMEZONE, TIMEZONE));
+                assertNull(properties.put(XML.LENIENT_UNMARSHAL, Boolean.TRUE));
+                defaultPool = new MarshallerPool(properties);
+            }
+            return defaultPool;
         }
-        return defaultPool;
     }
 
     /**
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/FeatureAttributeMock.java
b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/FeatureAttributeMock.java
new file mode 100644
index 0000000..8d08452
--- /dev/null
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/FeatureAttributeMock.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.test.mock;
+
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.sis.internal.xml.LegacyNamespaces;
+import org.apache.sis.internal.jaxb.gco.Multiplicity;
+import org.opengis.util.LocalName;
+
+
+/**
+ * Partial implementation of {@code FC_FeatureAttribute} with only a few properties for testing
purposes.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ * @since   1.0
+ * @module
+ */
+@XmlType(name = "FC_FeatureAttribute_Type", namespace = LegacyNamespaces.GFC)
+@XmlRootElement(name = "FC_FeatureAttribute", namespace = LegacyNamespaces.GFC)
+public final class FeatureAttributeMock {
+    /**
+     * The name of the attribute.
+     */
+    @XmlElement(name = "memberName", required = true)
+    public LocalName memberName;
+
+    /**
+     * Number of occurrences allowed.
+     */
+    @XmlElement(name = "cardinality", required = true)
+    public Multiplicity cardinality;
+}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/package-info.java b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/package-info.java
index 49c552f..6e0c7b6 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/package-info.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/package-info.java
@@ -34,7 +34,9 @@
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = Namespaces.GML, xmlns =
{
     @XmlNs(prefix = "gml", namespaceURI = Namespaces.GML),
     @XmlNs(prefix = "mdb", namespaceURI = Namespaces.MDB),
-    @XmlNs(prefix = "gco", namespaceURI = Namespaces.GCO)
+    @XmlNs(prefix = "gco", namespaceURI = Namespaces.GCO),
+    @XmlNs(prefix = "gmd", namespaceURI = LegacyNamespaces.GMD),
+    @XmlNs(prefix = "gfc", namespaceURI = LegacyNamespaces.GFC)
 })
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
@@ -50,4 +52,5 @@ import javax.xml.bind.annotation.XmlAccessorType;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
 import org.apache.sis.internal.jaxb.gco.GO_GenericName;
+import org.apache.sis.internal.xml.LegacyNamespaces;
 import org.apache.sis.xml.Namespaces;
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
b/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
index fc59b4c..4581611 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/suite/MetadataTestSuite.java
@@ -71,6 +71,7 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.jaxb.ModifiableIdentifierMapTest.class,
     org.apache.sis.internal.jaxb.gco.StringAdapterTest.class,
     org.apache.sis.internal.jaxb.gco.PropertyTypeTest.class,
+    org.apache.sis.internal.jaxb.gco.MultiplicityTest.class,
     org.apache.sis.internal.jaxb.lan.PT_LocaleTest.class,
     org.apache.sis.internal.jaxb.lan.LanguageCodeTest.class,
     org.apache.sis.internal.jaxb.lan.FreeTextMarshallingTest.class,
diff --git a/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/Multiplicity.xml
b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/Multiplicity.xml
new file mode 100644
index 0000000..b76c021
--- /dev/null
+++ b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2007/Multiplicity.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<gfc:FC_FeatureAttribute
+    xmlns:gfc          = "http://www.isotc211.org/2005/gfc"
+    xmlns:gco          = "http://www.isotc211.org/2005/gco"
+    xmlns:xsi          = "http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation = "http://www.isotc211.org/2005/gfc http://www.isotc211.org/2005/gfc/gfc.xsd">
+
+  <gfc:memberName>
+    <gco:LocalName>
+      Multiplicity test
+    </gco:LocalName>
+  </gfc:memberName>
+  <gfc:cardinality>
+    <gco:Multiplicity>
+      <gco:range>
+        <gco:MultiplicityRange>
+          <gco:lower>
+            <gco:Integer>0</gco:Integer>
+          </gco:lower>
+          <gco:upper>
+            <gco:UnlimitedInteger>233332</gco:UnlimitedInteger>
+          </gco:upper>
+        </gco:MultiplicityRange>
+      </gco:range>
+      <gco:range>
+        <gco:MultiplicityRange>
+          <gco:lower>
+            <gco:Integer>1</gco:Integer>
+          </gco:lower>
+          <gco:upper>
+            <gco:UnlimitedInteger isInfinite="true" xsi:nil="true"/>
+          </gco:upper>
+        </gco:MultiplicityRange>
+      </gco:range>
+    </gco:Multiplicity>
+  </gfc:cardinality>
+</gfc:FC_FeatureAttribute>
diff --git a/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2016/Multiplicity.xml
b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2016/Multiplicity.xml
new file mode 100644
index 0000000..72fa62c
--- /dev/null
+++ b/core/sis-metadata/src/test/resources/org/apache/sis/metadata/xml/2016/Multiplicity.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<gco:Multiplicity
+    xmlns:gco          = "http://standards.iso.org/iso/19115/-3/gco/1.0"
+    xmlns:xsi          = "http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation = "http://standards.iso.org/iso/19115/-3/gco/1.0  http://standards.iso.org/iso/19115/-3/gco/1.0/gco.xsd">
+
+  <!--
+    We provide this file for completion and comparison purposes, but the tests do not use
it
+    yet because we do not have a valid wrapper class. The ../2007/Multiplicity.xml file uses
+    the FC_FeatureAttribute type published in 2005. A new version of FC_FeatureAttribute
has
+    been published later, but that version do not use Multiplicity anymore (cardinality is
+    represented by a character string instead). Since its content is identical to the 2007
+    version (with only a different namespace), it is sufficient to test (un)marshalling of
+    the older version.
+  -->
+  <gco:range>
+    <gco:MultiplicityRange>
+      <gco:lower>
+        <gco:Integer>0</gco:Integer>
+      </gco:lower>
+      <gco:upper>
+        <gco:UnlimitedInteger>233332</gco:UnlimitedInteger>
+      </gco:upper>
+    </gco:MultiplicityRange>
+  </gco:range>
+  <gco:range>
+    <gco:MultiplicityRange>
+      <gco:lower>
+        <gco:Integer>1</gco:Integer>
+      </gco:lower>
+      <gco:upper>
+        <gco:UnlimitedInteger isInfinite="true" xsi:nil="true"/>
+      </gco:upper>
+    </gco:MultiplicityRange>
+  </gco:range>
+</gco:Multiplicity>


Mime
View raw message