sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject [sis] 01/01: Upgrade from GeoAPI 3.1 to GeoAPI 4.0. The content of the branch is the one previously in "JDK8" branch in the Subversion repository.
Date Sat, 16 Jun 2018 14:26:15 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

commit a101a144f62e3aa22239f15934e465ff086518d2
Author: Martin Desruisseaux <martin.desruisseaux@geomatys.com>
AuthorDate: Sat Jun 16 16:17:03 2018 +0200

    Upgrade from GeoAPI 3.1 to GeoAPI 4.0. The content of the branch is the one previously in "JDK8" branch in the Subversion repository.
---
 .../java/org/apache/sis/feature/Validator.java     |   2 +-
 .../sis/internal/jaxb/cat/CodeListAdapter.java     |  28 +-
 ...acterSetLegacy.java => LegacyCharacterSet.java} |  22 +-
 .../jaxb/code/MD_PixelOrientationCode.java         |  69 +--
 .../internal/jaxb/code/MD_TopicCategoryCode.java   |  67 +-
 .../jaxb/metadata/CI_ResponsibleParty.java         | 128 ----
 .../metadata/replace/ReferenceSystemMetadata.java  |  12 +-
 .../jaxb/metadata/replace/ServiceParameter.java    |   7 +-
 .../sis/internal/metadata/NameToIdentifier.java    |   3 +-
 .../sis/internal/metadata/ServicesForUtility.java  |  13 +-
 .../sis/internal/simple/CitationConstant.java      |   6 +-
 .../apache/sis/internal/simple/SimpleCitation.java |   6 +-
 .../internal/simple/SimpleIdentifiedObject.java    |   9 +-
 .../sis/internal/simple/SimpleIdentifier.java      |   8 +-
 .../apache/sis/internal/simple/SimpleMetadata.java |  21 +-
 .../apache/sis/metadata/PropertyInformation.java   |   6 +-
 .../iso/DefaultApplicationSchemaInformation.java   |  57 +-
 .../iso/DefaultExtendedElementInformation.java     |  42 +-
 .../apache/sis/metadata/iso/DefaultMetadata.java   |  50 +-
 .../sis/metadata/iso/ImmutableIdentifier.java      |   3 +-
 .../sis/metadata/iso/OnlineResourceAdapter.java    |  66 --
 .../apache/sis/metadata/iso/URIStringAdapter.java  |  67 --
 .../metadata/iso/acquisition/DefaultPlatform.java  |  24 +-
 .../iso/acquisition/DefaultRequirement.java        |  46 +-
 .../sis/metadata/iso/acquisition/package-info.java |   2 +-
 .../sis/metadata/iso/citation/DefaultAddress.java  |  22 +-
 .../sis/metadata/iso/citation/DefaultCitation.java |  51 +-
 .../sis/metadata/iso/citation/DefaultContact.java  |  25 +-
 .../iso/citation/DefaultOnlineResource.java        |  14 +-
 .../sis/metadata/iso/citation/DefaultSeries.java   |  34 +-
 .../sis/metadata/iso/citation/package-info.java    |   2 +-
 .../iso/distribution/DefaultDistributor.java       |  22 +-
 .../metadata/iso/distribution/package-info.java    |   1 -
 .../iso/identification/AbstractIdentification.java |  44 +-
 .../identification/DefaultDataIdentification.java  |  23 +-
 .../metadata/iso/identification/DefaultUsage.java  |  28 +-
 .../metadata/iso/identification/package-info.java  |   3 +-
 .../metadata/iso/lineage/DefaultProcessStep.java   |  24 +-
 .../sis/metadata/iso/lineage/package-info.java     |   2 +-
 .../iso/maintenance/AttributeTypeAdapter.java      |  52 --
 .../maintenance/DefaultMaintenanceInformation.java |  24 +-
 .../iso/maintenance/DefaultScopeDescription.java   | 157 ++---
 .../iso/maintenance/FeatureTypeAdapter.java        |  52 --
 .../sis/metadata/iso/maintenance/LegacyType.java   |  70 ---
 .../sis/metadata/iso/maintenance/package-info.java |   4 +-
 .../org/apache/sis/metadata/iso/package-info.java  |   4 +-
 .../metadata/iso/quality/DefaultDataQuality.java   |   3 +-
 .../sis/internal/jaxb/cat/EnumMarshallingTest.java |   2 +
 .../apache/sis/metadata/PropertyAccessorTest.java  |  18 +-
 .../sis/metadata/PropertyInformationTest.java      |   2 +-
 .../apache/sis/metadata/TreeNodeChildrenTest.java  |   3 +-
 .../java/org/apache/sis/metadata/TreeNodeTest.java |  52 +-
 .../apache/sis/metadata/TreeTableFormatTest.java   |  12 +-
 .../org/apache/sis/metadata/TreeTableViewTest.java |  14 +-
 .../java/org/apache/sis/metadata/TypeMapTest.java  |   4 +-
 .../java/org/apache/sis/metadata/ValueMapTest.java |  10 +-
 .../sis/metadata/iso/CustomMetadataTest.java       |   9 +-
 .../apache/sis/metadata/iso/MarshallingTest.java   | 677 +++++++++++++++++++++
 .../metadata/iso/citation/DefaultCitationTest.java |  26 +-
 .../iso/citation/DefaultResponsibilityTest.java    |   3 +-
 .../metadata/iso/citation/HardCodedCitations.java  |   7 +-
 .../DefaultDataIdentificationTest.java             |   6 +-
 .../maintenance/DefaultScopeDescriptionTest.java   |   7 +-
 .../sis/metadata/sql/MetadataWriterTest.java       |   2 +-
 .../apache/sis/test/mock/IdentifiedObjectMock.java |   8 +-
 .../apache/sis/test/suite/MetadataTestSuite.java   |   1 +
 .../sis/test/xml/AnnotationConsistencyCheck.java   |  14 +-
 .../referencing/CC_GeneralOperationParameter.java  |   3 +-
 .../apache/sis/internal/jaxb/referencing/Code.java |   3 +-
 .../internal/referencing/NilReferencingObject.java |   8 +-
 .../referencing/provider/AbstractProvider.java     |   6 +-
 .../referencing/provider/MapProjection.java        |   8 +-
 .../provider/ObliqueMercatorCenter.java            |   5 +-
 .../org/apache/sis/parameter/ParameterFormat.java  |   3 +-
 .../sis/referencing/AbstractIdentifiedObject.java  |  49 +-
 .../java/org/apache/sis/referencing/Builder.java   |  29 +-
 .../main/java/org/apache/sis/referencing/CRS.java  |   4 +-
 .../org/apache/sis/referencing/NameIterator.java   |  24 +-
 .../apache/sis/referencing/NamedIdentifier.java    |   3 +-
 .../org/apache/sis/referencing/Properties.java     |   6 +-
 .../sis/referencing/crs/AbstractDerivedCRS.java    |   2 +-
 .../sis/referencing/crs/DefaultDerivedCRS.java     |   2 +-
 .../sis/referencing/crs/DefaultProjectedCRS.java   |   4 +-
 .../operation/CoordinateOperationFinder.java       |   4 +-
 .../operation/CoordinateOperationRegistry.java     |   6 +-
 .../operation/DefaultConcatenatedOperation.java    |  13 +-
 .../operation/DefaultPassThroughOperation.java     |  41 +-
 .../referencing/operation/SubOperationInfo.java    |   2 +-
 .../apache/sis/referencing/operation/SubTypes.java |  13 +-
 .../org/apache/sis/parameter/ParametersTest.java   |   6 +-
 .../referencing/AbstractIdentifiedObjectTest.java  |  38 +-
 .../apache/sis/test/integration/MetadataTest.java  |  14 +-
 .../org/apache/sis/internal/util/CitationMock.java |   9 +-
 ide-project/NetBeans/nbproject/build-impl.xml      |  26 +-
 ide-project/NetBeans/nbproject/genfiles.properties |   4 +-
 ide-project/NetBeans/nbproject/project.properties  |  16 +-
 ide-project/NetBeans/nbproject/project.xml         |  12 +-
 pom.xml                                            |   2 +-
 .../profile/fra/DirectReferenceSystem.java         |   4 +-
 .../profile/fra/IndirectReferenceSystem.java       |   4 +-
 .../profile/fra/DirectReferenceSystemTest.java     |   4 +-
 .../main/java/org/apache/sis/storage/gdal/PJ.java  |   4 +-
 .../apache/sis/storage/netcdf/MetadataReader.java  |  17 +-
 .../sis/internal/storage/MetadataBuilder.java      |  37 +-
 .../apache/sis/internal/storage/gpx/Copyright.java |   7 +-
 .../org/apache/sis/internal/storage/gpx/Link.java  |   8 +-
 .../apache/sis/internal/storage/gpx/Metadata.java  |   5 +-
 .../apache/sis/internal/storage/gpx/Person.java    |  66 +-
 108 files changed, 1294 insertions(+), 1529 deletions(-)

diff --git a/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java b/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
index 6b759f3..1a7fb44 100644
--- a/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
+++ b/core/sis-feature/src/main/java/org/apache/sis/feature/Validator.java
@@ -28,7 +28,7 @@ import org.apache.sis.metadata.iso.quality.AbstractElement;
 import org.apache.sis.metadata.iso.quality.DefaultDataQuality;
 import org.apache.sis.metadata.iso.quality.DefaultDomainConsistency;
 import org.apache.sis.metadata.iso.quality.DefaultConformanceResult;
-import org.apache.sis.metadata.iso.quality.DefaultScope;
+import org.apache.sis.metadata.iso.maintenance.DefaultScope;
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.util.resources.Errors;
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java
index ae81bbf..901c73b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/cat/CodeListAdapter.java
@@ -127,33 +127,7 @@ public abstract class CodeListAdapter<ValueType extends CodeListAdapter<ValueTyp
      */
     @Override
     public final ValueType marshal(final BoundType code) {
-        if (code == null) {
-            return null;
-        }
-        final CodeListUID p;
-        if (isEnum()) {
-            // To be removed after GEO-199 resolution.
-            p = new CodeListUID();
-            p.value = Types.getCodeName(code);
-        } else {
-            p = new CodeListUID(Context.current(), code);
-        }
-        return wrap(p);
-    }
-
-    /**
-     * Returns {@code true} if this code list is actually an enum. The default implementation
-     * returns {@code false} in every cases, since there is very few enums in ISO 19115.
-     *
-     * @return {@code true} if this code list is actually an enum.
-     *
-     * @todo Remove this method after we refactored enum wrappers as {@code EnumAdapter} subclasses
-     *       instead of {@code CodeListAdapter}. This requires the resolution of GEO-199 first.
-     *
-     * @see <a href="http://jira.codehaus.org/browse/GEO-199">GEO-199</a>
-     */
-    protected boolean isEnum() {
-        return false;
+        return (code != null) ? wrap(new CodeListUID(Context.current(), code)) : null;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_CharacterSetLegacy.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/LegacyCharacterSet.java
similarity index 73%
rename from core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_CharacterSetLegacy.java
rename to core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/LegacyCharacterSet.java
index 436c2d4..049a011 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_CharacterSetLegacy.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/LegacyCharacterSet.java
@@ -24,38 +24,44 @@ import org.apache.sis.internal.jaxb.LegacyNamespaces;
 
 
 /**
- * JAXB adapter for {@link CharacterSet}, in order to integrate the value in an element
- * complying with ISO 19139:2007 standard.
+ * JAXB adapter for {@link CharacterSet}
+ * in order to wrap the value in an XML element as specified by ISO 19115-3 standard.
+ * See package documentation for more information about the handling of {@code CodeList} in ISO 19115-3.
  *
  * @author  Cédric Briançon (Geomatys)
  * @version 1.0
  * @since   0.3
  * @module
  */
-public final class MD_CharacterSetLegacy extends CodeListAdapter<MD_CharacterSetLegacy, CharacterSet> {
+@SuppressWarnings("deprecation")
+public final class LegacyCharacterSet extends CodeListAdapter<LegacyCharacterSet, CharacterSet> {
     /**
      * Empty constructor for JAXB only.
      */
-    public MD_CharacterSetLegacy() {
+    public LegacyCharacterSet() {
     }
 
     /**
-     * Creates a new adapter for the given proxy.
+     * Creates a new adapter for the given value.
      */
-    private MD_CharacterSetLegacy(final CodeListUID value) {
+    private LegacyCharacterSet(final CodeListUID value) {
         super(value);
     }
 
     /**
      * {@inheritDoc}
+     *
+     * @return the wrapper for the code list value.
      */
     @Override
-    protected MD_CharacterSetLegacy wrap(final CodeListUID value) {
-        return new MD_CharacterSetLegacy(value);
+    protected LegacyCharacterSet wrap(final CodeListUID value) {
+        return new LegacyCharacterSet(value);
     }
 
     /**
      * {@inheritDoc}
+     *
+     * @return the code list class.
      */
     @Override
     protected Class<CharacterSet> getCodeListClass() {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
index 31c876e..4b88e53 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_PixelOrientationCode.java
@@ -18,8 +18,7 @@ package org.apache.sis.internal.jaxb.code;
 
 import javax.xml.bind.annotation.XmlElement;
 import org.opengis.metadata.spatial.PixelOrientation;
-import org.apache.sis.internal.jaxb.cat.CodeListAdapter;
-import org.apache.sis.internal.jaxb.cat.CodeListUID;
+import org.apache.sis.internal.jaxb.cat.EnumAdapter;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -34,67 +33,43 @@ import org.apache.sis.xml.Namespaces;
  * @since   0.3
  * @module
  */
-public final class MD_PixelOrientationCode
-        extends CodeListAdapter<MD_PixelOrientationCode, PixelOrientation>
-{
+public final class MD_PixelOrientationCode extends EnumAdapter<MD_PixelOrientationCode, PixelOrientation> {
     /**
-     * Empty constructor for JAXB only.
+     * The enumeration value.
      */
-    public MD_PixelOrientationCode() {
-    }
+    @XmlElement(name = "MD_PixelOrientationCode", namespace = Namespaces.MSR)
+    private String value;
 
     /**
-     * Creates a new adapter for the given proxy.
+     * Empty constructor for JAXB only.
      */
-    private MD_PixelOrientationCode(final CodeListUID value) {
-        super(value);
+    public MD_PixelOrientationCode() {
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the wrapped value.
      *
-     * @return the wrapper for the code list value.
+     * @param  wrapper  the wrapper.
+     * @return the wrapped value.
      */
     @Override
-    protected MD_PixelOrientationCode wrap(final CodeListUID value) {
-        return new MD_PixelOrientationCode(value);
+    public final PixelOrientation unmarshal(final MD_PixelOrientationCode wrapper) {
+        return PixelOrientation.valueOf(name(wrapper.value));
     }
 
     /**
-     * {@inheritDoc}
+     * Wraps the given value.
      *
-     * @return the code list class.
+     * @param  e  the value to wrap.
+     * @return the wrapped value.
      */
     @Override
-    protected Class<PixelOrientation> getCodeListClass() {
-        return PixelOrientation.class;
-    }
-
-    /**
-     * Returns {@code true} since this code list is actually an enum.
-     */
-    @Override
-    protected boolean isEnum() {
-        return true;
-    }
-
-    /**
-     * Invoked by JAXB on marshalling.
-     *
-     * @return The value to be marshalled.
-     */
-    @Override
-    @XmlElement(name = "MD_PixelOrientationCode", namespace = Namespaces.MSR)
-    public CodeListUID getElement() {
-        return identifier;
-    }
-
-    /**
-     * Invoked by JAXB on unmarshalling.
-     *
-     * @param value The unmarshalled value.
-     */
-    public void setElement(final CodeListUID value) {
-        identifier = value;
+    public final MD_PixelOrientationCode marshal(final PixelOrientation e) {
+        if (e == null) {
+            return null;
+        }
+        final MD_PixelOrientationCode wrapper = new MD_PixelOrientationCode();
+        wrapper.value = value(e);
+        return wrapper;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
index 7d700ca..dae9784 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/code/MD_TopicCategoryCode.java
@@ -18,8 +18,7 @@ package org.apache.sis.internal.jaxb.code;
 
 import javax.xml.bind.annotation.XmlElement;
 import org.opengis.metadata.identification.TopicCategory;
-import org.apache.sis.internal.jaxb.cat.CodeListAdapter;
-import org.apache.sis.internal.jaxb.cat.CodeListUID;
+import org.apache.sis.internal.jaxb.cat.EnumAdapter;
 import org.apache.sis.xml.Namespaces;
 
 
@@ -35,65 +34,43 @@ import org.apache.sis.xml.Namespaces;
  * @since   0.3
  * @module
  */
-public final class MD_TopicCategoryCode extends CodeListAdapter<MD_TopicCategoryCode, TopicCategory> {
+public final class MD_TopicCategoryCode extends EnumAdapter<MD_TopicCategoryCode, TopicCategory> {
     /**
-     * Empty constructor for JAXB only.
+     * The enumeration value.
      */
-    public MD_TopicCategoryCode() {
-    }
+    @XmlElement(name = "MD_TopicCategoryCode", namespace = Namespaces.MRI)
+    private String value;
 
     /**
-     * Creates a new adapter for the given proxy.
+     * Empty constructor for JAXB only.
      */
-    private MD_TopicCategoryCode(final CodeListUID value) {
-        super(value);
+    public MD_TopicCategoryCode() {
     }
 
     /**
-     * {@inheritDoc}
+     * Returns the wrapped value.
      *
-     * @return the wrapper for the code list value.
+     * @param  wrapper  the wrapper.
+     * @return the wrapped value.
      */
     @Override
-    protected MD_TopicCategoryCode wrap(final CodeListUID value) {
-        return new MD_TopicCategoryCode(value);
+    public final TopicCategory unmarshal(final MD_TopicCategoryCode wrapper) {
+        return TopicCategory.valueOf(name(wrapper.value));
     }
 
     /**
-     * {@inheritDoc}
+     * Wraps the given value.
      *
-     * @return the code list class.
+     * @param  e  the value to wrap.
+     * @return the wrapped value.
      */
     @Override
-    protected Class<TopicCategory> getCodeListClass() {
-        return TopicCategory.class;
-    }
-
-    /**
-     * Returns {@code true} since this code list is actually an enum.
-     */
-    @Override
-    protected boolean isEnum() {
-        return true;
-    }
-
-    /**
-     * Invoked by JAXB on marshalling.
-     *
-     * @return The value to be marshalled.
-     */
-    @Override
-    @XmlElement(name = "MD_TopicCategoryCode", namespace = Namespaces.MRI)
-    public CodeListUID getElement() {
-        return identifier;
-    }
-
-    /**
-     * Invoked by JAXB on unmarshalling.
-     *
-     * @param value The unmarshalled value.
-     */
-    public void setElement(final CodeListUID value) {
-        identifier = value;
+    public final MD_TopicCategoryCode marshal(final TopicCategory e) {
+        if (e == null) {
+            return null;
+        }
+        final MD_TopicCategoryCode wrapper = new MD_TopicCategoryCode();
+        wrapper.value = value(e);
+        return wrapper;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java
deleted file mode 100644
index 7a57029..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/CI_ResponsibleParty.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.metadata;
-
-import javax.xml.bind.annotation.XmlElementRef;
-import org.opengis.util.InternationalString;
-import org.opengis.metadata.citation.Contact;
-import org.opengis.metadata.citation.ResponsibleParty;
-import org.apache.sis.metadata.iso.citation.AbstractParty;
-import org.apache.sis.metadata.iso.citation.DefaultIndividual;
-import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
-import org.apache.sis.internal.jaxb.gco.PropertyType;
-import org.apache.sis.internal.jaxb.FilterByVersion;
-
-
-/**
- * JAXB adapter mapping implementing class to the GeoAPI interface. See
- * package documentation for more information about JAXB and interface.
- *
- * @author  Cédric Briançon (Geomatys)
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   0.3
- * @module
- */
-@SuppressWarnings("deprecation")
-public final class CI_ResponsibleParty extends PropertyType<CI_ResponsibleParty, ResponsibleParty> {
-    /**
-     * Empty constructor for JAXB only.
-     */
-    public CI_ResponsibleParty() {
-    }
-
-    /**
-     * Returns the GeoAPI interface which is bound by this adapter.
-     * This method is indirectly invoked by the private constructor
-     * below, so it shall not depend on the state of this object.
-     *
-     * @return {@code ResponsibleParty.class}
-     */
-    @Override
-    protected Class<ResponsibleParty> getBoundType() {
-        return ResponsibleParty.class;
-    }
-
-    /**
-     * Constructor for the {@link #wrap} method only.
-     */
-    private CI_ResponsibleParty(final ResponsibleParty metadata) {
-        super(metadata);
-    }
-
-    /**
-     * Invoked by {@link PropertyType} at marshalling time for wrapping the given metadata value
-     * in a {@code <gmd:CI_ResponsibleParty>} XML element.
-     *
-     * @param  metadata  the metadata element to marshall.
-     * @return a {@code PropertyType} wrapping the given the metadata element.
-     */
-    @Override
-    protected CI_ResponsibleParty wrap(final ResponsibleParty metadata) {
-        return new CI_ResponsibleParty(metadata);
-    }
-
-    /**
-     * Invoked by JAXB at marshalling time for getting the actual metadata to write
-     * inside the {@code <gmd:CI_ResponsibleParty>} XML element.
-     * This is the value or a copy of the value given in argument to the {@code wrap} method.
-     *
-     * @return the metadata to be marshalled.
-     */
-    @XmlElementRef
-    public DefaultResponsibility getElement() {
-        if (FilterByVersion.LEGACY_METADATA.accept()) {
-            return DefaultResponsibleParty.castOrCopy(metadata);
-        } else if (metadata != null) {
-            final DefaultIndividual individual;
-            final String name = metadata.getIndividualName();
-            Contact contact = metadata.getContactInfo();
-            AbstractParty party;
-            if (name != null) {
-                individual = new DefaultIndividual(name, metadata.getPositionName(), contact);
-                party      = individual;
-                contact    = null;
-            } else {
-                individual = null;
-                party      = null;
-            }
-            final InternationalString organisation = metadata.getOrganisationName();
-            if (organisation != null) {
-                party = new DefaultOrganisation(organisation, null, individual, contact);
-            }
-            if (party != null) {
-                return new DefaultResponsibility(metadata.getRole(), null, party);
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Invoked by JAXB at unmarshalling time for storing the result temporarily.
-     *
-     * @param  md  the unmarshalled metadata.
-     */
-    public void setElement(final DefaultResponsibility md) {
-        if (md instanceof DefaultResponsibleParty) {
-            metadata = (DefaultResponsibleParty) md;
-        } else if (md != null) {
-            metadata = new DefaultResponsibleParty(md);
-        }
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
index f2eb05a..9c656a3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ReferenceSystemMetadata.java
@@ -22,8 +22,8 @@ import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+import org.opengis.metadata.Identifier;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.metadata.MD_Identifier;
 import org.apache.sis.internal.jaxb.metadata.RS_Identifier;
 import org.apache.sis.internal.simple.SimpleIdentifiedObject;
@@ -87,7 +87,7 @@ public class ReferenceSystemMetadata extends SimpleIdentifiedObject implements R
      *
      * @param  name  the primary name by which this object is identified.
      */
-    public ReferenceSystemMetadata(final ReferenceIdentifier name) {
+    public ReferenceSystemMetadata(final Identifier name) {
         super(name);
     }
 
@@ -107,7 +107,7 @@ public class ReferenceSystemMetadata extends SimpleIdentifiedObject implements R
     @Override
     @XmlElement(name = "referenceSystemIdentifier")
     @XmlJavaTypeAdapter(MD_Identifier.class)
-    public ReferenceIdentifier getName() {
+    public final Identifier getName() {
         return isLegacyMetadata ? null : super.getName();
     }
 
@@ -116,7 +116,7 @@ public class ReferenceSystemMetadata extends SimpleIdentifiedObject implements R
      *
      * @param  name  the new primary name.
      */
-    public final void setName(final ReferenceIdentifier name) {
+    public final void setName(final Identifier name) {
         this.name = name;
     }
 
@@ -126,7 +126,7 @@ public class ReferenceSystemMetadata extends SimpleIdentifiedObject implements R
      */
     @XmlElement(name = "referenceSystemIdentifier", namespace = LegacyNamespaces.GMD)
     @XmlJavaTypeAdapter(RS_Identifier.class)
-    private ReferenceIdentifier getLegacyName() {
+    private Identifier getLegacyName() {
         return isLegacyMetadata ? super.getName() : null;
     }
 
@@ -134,7 +134,7 @@ public class ReferenceSystemMetadata extends SimpleIdentifiedObject implements R
      * Sets the name for this reference system metadata (used in ISO 19115:2003 model).
      */
     @SuppressWarnings("unused")
-    private void setLegacyName(final ReferenceIdentifier name) {
+    private void setLegacyName(final Identifier name) {
         this.name = name;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
index 0ca7508..ece5628 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/jaxb/metadata/replace/ServiceParameter.java
@@ -31,7 +31,6 @@ import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterValue;
 import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterDescriptor;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.simple.SimpleIdentifiedObject;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.jaxb.LegacyNamespaces;
@@ -267,10 +266,10 @@ public final class ServiceParameter extends SimpleIdentifiedObject implements Pa
      * @return the parameter name as an identifier (the type specified by ISO 19111).
      */
     @Override
-    public synchronized ReferenceIdentifier getName() {
+    public synchronized Identifier getName() {
         if (name == null && memberName != null) {
-            if (memberName instanceof ReferenceIdentifier) {
-                name = (ReferenceIdentifier) memberName;
+            if (memberName instanceof Identifier) {
+                name = (Identifier) memberName;
             } else {
                 name = new NameToIdentifier(memberName);
             }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java
index cfcb6cb..ce3c950 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/NameToIdentifier.java
@@ -24,7 +24,6 @@ import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.CharSequences;
@@ -46,7 +45,7 @@ import static org.apache.sis.util.Characters.Filter.LETTERS_AND_DIGITS;
  * @since   0.4
  * @module
  */
-public final class NameToIdentifier implements ReferenceIdentifier {
+public final class NameToIdentifier implements Identifier {
     /**
      * The name from which to infer the identifier attributes.
      */
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
index 766f7f7..5a6117a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ServicesForUtility.java
@@ -26,7 +26,7 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.util.ControlledVocabulary;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.MetadataServices;
@@ -37,7 +37,7 @@ import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.iso.Types;
 import org.apache.sis.util.Exceptions;
@@ -208,14 +208,13 @@ public final class ServicesForUtility extends MetadataServices {
         if (code                  != null) c.setIdentifiers(singleton(new ImmutableIdentifier(null, codeSpace, code, version, null)));
         if (presentationForm      != null) c.setPresentationForms(singleton(presentationForm));
         if (citedResponsibleParty != null) {
-            final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.PRINCIPAL_INVESTIGATOR);
-            r.setParties(singleton(new DefaultOrganisation(citedResponsibleParty, null, null, null)));
-            c.setCitedResponsibleParties(singleton(r));
+            c.setCitedResponsibleParties(singleton(new DefaultResponsibility(Role.PRINCIPAL_INVESTIGATOR, null,
+                    new DefaultOrganisation(citedResponsibleParty, null, null, null))));
         }
         if (copyFrom != null) {
             for (final Citation other : copyFrom) {
-                final Collection<? extends ResponsibleParty> parties = other.getCitedResponsibleParties();
-                final Collection<ResponsibleParty> current = c.getCitedResponsibleParties();
+                final Collection<? extends Responsibility> parties = other.getCitedResponsibleParties();
+                final Collection<Responsibility> current = c.getCitedResponsibleParties();
                 if (current != null) {
                     current.addAll(parties);
                 } else {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
index ea2f41b..f8a1dce 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/CitationConstant.java
@@ -24,7 +24,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.identification.BrowseGraphic;
 import org.opengis.util.InternationalString;
@@ -163,10 +163,10 @@ public class CitationConstant extends SimpleCitation {
     @Override public InternationalString                        getEdition()                 {return delegate().getEdition();}
     @Override public Date                                       getEditionDate()             {return delegate().getEditionDate();}
     @Override public Collection<? extends Identifier>           getIdentifiers()             {return delegate().getIdentifiers();}
-    @Override public Collection<? extends ResponsibleParty>     getCitedResponsibleParties() {return delegate().getCitedResponsibleParties();}
+    @Override public Collection<? extends Responsibility>       getCitedResponsibleParties() {return delegate().getCitedResponsibleParties();}
     @Override public Collection<PresentationForm>               getPresentationForms()       {return delegate().getPresentationForms();}
     @Override public Series                                     getSeries()                  {return delegate().getSeries();}
-    @Override public InternationalString                        getOtherCitationDetails()    {return delegate().getOtherCitationDetails();}
+    @Override public Collection<? extends InternationalString>  getOtherCitationDetails()    {return delegate().getOtherCitationDetails();}
     @Override public Collection<? extends OnlineResource>       getOnlineResources()         {return delegate().getOnlineResources();}
     @Override public Collection<? extends BrowseGraphic>        getGraphics()                {return delegate().getGraphics();}
     @Override public String                                     getISBN()                    {return delegate().getISBN();}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java
index a567b5f..266a03f 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleCitation.java
@@ -26,7 +26,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.identification.BrowseGraphic;
 import org.opengis.util.InternationalString;
@@ -89,10 +89,10 @@ public class SimpleCitation implements Citation, Serializable {
     @Override public InternationalString                        getEdition()                 {return null;}
     @Override public Date                                       getEditionDate()             {return null;}
     @Override public Collection<? extends Identifier>           getIdentifiers()             {return Collections.emptyList();}
-    @Override public Collection<? extends ResponsibleParty>     getCitedResponsibleParties() {return Collections.emptyList();}
+    @Override public Collection<? extends Responsibility>       getCitedResponsibleParties() {return Collections.emptyList();}
     @Override public Collection<PresentationForm>               getPresentationForms()       {return Collections.emptyList();}
     @Override public Series                                     getSeries()                  {return null;}
-    @Override public InternationalString                        getOtherCitationDetails()    {return null;}
+    @Override public Collection<? extends InternationalString>  getOtherCitationDetails()    {return Collections.emptyList();}
     @Override public Collection<? extends OnlineResource>       getOnlineResources()         {return Collections.emptyList();}
     @Override public Collection<? extends BrowseGraphic>        getGraphics()                {return Collections.emptyList();}
     @Override public String                                     getISBN()                    {return null;}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
index 12eeadb..eadcf33 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifiedObject.java
@@ -27,7 +27,6 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.extent.Extent;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Citations;
 import org.apache.sis.util.iso.DefaultNameSpace;
 import org.apache.sis.util.LenientComparable;
@@ -57,7 +56,7 @@ public class SimpleIdentifiedObject implements IdentifiedObject, LenientComparab
     /**
      * The primary name by which this object is identified.
      */
-    protected ReferenceIdentifier name;
+    protected Identifier name;
 
     /**
      * Creates an identified object without identifier.
@@ -80,7 +79,7 @@ public class SimpleIdentifiedObject implements IdentifiedObject, LenientComparab
      *
      * @param  name  the primary name by which this object is identified.
      */
-    public SimpleIdentifiedObject(final ReferenceIdentifier name) {
+    public SimpleIdentifiedObject(final Identifier name) {
         this.name = name;
     }
 
@@ -90,7 +89,7 @@ public class SimpleIdentifiedObject implements IdentifiedObject, LenientComparab
      * @return the identifier given at construction time.
      */
     @Override
-    public ReferenceIdentifier getName() {
+    public Identifier getName() {
         return name;
     }
 
@@ -104,7 +103,7 @@ public class SimpleIdentifiedObject implements IdentifiedObject, LenientComparab
      * @return the identifiers, or an empty set if none.
      */
     @Override
-    public final Set<ReferenceIdentifier> getIdentifiers() {
+    public final Set<Identifier> getIdentifiers() {
         return Collections.emptySet();
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
index cd60fae..881dd36 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleIdentifier.java
@@ -19,7 +19,7 @@ package org.apache.sis.internal.simple;
 import java.util.Objects;
 import java.io.Serializable;
 import org.opengis.util.InternationalString;
-import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.apache.sis.internal.util.Citations;
 import org.apache.sis.util.CharSequences;
@@ -31,14 +31,14 @@ import static org.apache.sis.util.iso.DefaultNameSpace.DEFAULT_SEPARATOR;
 
 
 /**
- * An implementation of {@link ReferenceIdentifier} as a wrapper around a {@link Citation}.
+ * An implementation of {@link Identifier} as a wrapper around a {@link Citation}.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @version 1.0
  * @since   0.3
  * @module
  */
-public class SimpleIdentifier implements ReferenceIdentifier, Deprecable, Serializable {
+public class SimpleIdentifier implements Identifier, Deprecable, Serializable {
     /**
      * For cross-version compatibility.
      */
@@ -237,7 +237,7 @@ public class SimpleIdentifier implements ReferenceIdentifier, Deprecable, Serial
 
     /**
      * Returns a pseudo Well Known Text for this identifier.
-     * While this method is not defined in the {@link ReferenceIdentifier} interface, it is often
+     * While this method is not defined in the {@link Identifier} interface, it is often
      * defined in related interfaces like {@link org.opengis.referencing.IdentifiedObject}.
      *
      * @return pseudo Well Known Text for this identifier.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java
index bada66b..99f2e33 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/simple/SimpleMetadata.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.internal.simple;
 
+import java.nio.charset.Charset;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -31,7 +32,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.content.ContentInformation;
@@ -139,7 +140,7 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * Also the character coding standard(s) used for the dataset.
      */
     @Override
-    public final Collection getCharacterSets() {
+    public Collection<Charset> getCharacterSets() {
         return Collections.emptySet();                  // We use 'Set' because we handle 'Charset' like a CodeList.
     }
 
@@ -224,7 +225,7 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * Parties responsible for the metadata information.
      */
     @Override
-    public Collection<ResponsibleParty> getContacts() {
+    public Collection<Responsibility> getContacts() {
         return Collections.emptyList();
     }
 
@@ -364,8 +365,8 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * Information about the distributor of and options for obtaining the resource(s).
      */
     @Override
-    public Distribution getDistributionInfo() {
-        return null;
+    public Collection<Distribution> getDistributionInfo() {
+        return Collections.emptyList();
     }
 
     /**
@@ -462,7 +463,7 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * This is part of the information returned by {@link #getIdentificationInfo()}.
      */
     @Override
-    public Collection<String> getCredits() {
+    public Collection<InternationalString> getCredits() {
         return Collections.emptyList();
     }
 
@@ -480,7 +481,7 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * This is part of the information returned by {@link #getIdentificationInfo()}.
      */
     @Override
-    public Collection<ResponsibleParty> getPointOfContacts() {
+    public Collection<Responsibility> getPointOfContacts() {
         return Collections.emptyList();
     }
 
@@ -708,7 +709,7 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * This is part of the information returned by {@link #getCitation()}.
      */
     @Override
-    public Collection<ResponsibleParty> getCitedResponsibleParties() {
+    public Collection<Responsibility> getCitedResponsibleParties() {
         return Collections.emptyList();
     }
 
@@ -737,8 +738,8 @@ public class SimpleMetadata implements Metadata, MetadataScope, DataIdentificati
      * This is part of the information returned by {@link #getCitation()}.
      */
     @Override
-    public InternationalString getOtherCitationDetails() {
-        return null;
+    public Collection<InternationalString> getOtherCitationDetails() {
+        return Collections.emptyList();
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java
index 7fe042e..c388d1c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/PropertyInformation.java
@@ -21,11 +21,11 @@ import java.util.Collection;
 import java.util.Collections;
 import java.lang.reflect.Method;
 import org.opengis.annotation.UML;
+import org.opengis.annotation.Obligation;
 import org.opengis.metadata.Datatype;
-import org.opengis.metadata.Obligation;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.ExtendedElementInformation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.util.CodeList;
 import org.opengis.util.InternationalString;
 import org.apache.sis.internal.simple.SimpleIdentifier;
@@ -343,7 +343,7 @@ final class PropertyInformation<E> extends SimpleIdentifier
      * Returns the name of the person or organization creating the element.
      */
     @Override
-    public Collection<? extends ResponsibleParty> getSources() {
+    public Collection<? extends Responsibility> getSources() {
         return authority.getCitedResponsibleParties();
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java
index 1beca0f..868b31e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultApplicationSchemaInformation.java
@@ -16,7 +16,6 @@
  */
 package org.apache.sis.metadata.iso;
 
-import java.net.URI;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
@@ -25,6 +24,8 @@ import org.opengis.metadata.ApplicationSchemaInformation;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.OnlineResource;
 import org.apache.sis.xml.Namespaces;
+import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
+import org.apache.sis.internal.jaxb.metadata.CI_OnlineResource;
 
 
 /**
@@ -70,7 +71,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = -884081423040392985L;
+    private static final long serialVersionUID = 5667352094985433121L;
 
     /**
      * Name of the application schema used.
@@ -90,17 +91,17 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
     /**
      * Full application schema given as an ASCII file.
      */
-    private URI schemaAscii;
+    private CharSequence schemaAscii;
 
     /**
      * Full application schema given as a graphics file.
      */
-    private URI graphicsFile;
+    private OnlineResource graphicsFile;
 
     /**
      * Full application schema given as a software development file.
      */
-    private URI softwareDevelopmentFile;
+    private OnlineResource softwareDevelopmentFile;
 
     /**
      * Software dependent format used for the application schema software dependent file.
@@ -242,29 +243,21 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
     /**
      * Full application schema given as an ASCII file.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * {@code URI} may be replaced by {@link CharSequence} in GeoAPI 4.0.
-     * </div>
-     *
      * @return application schema as an ASCII file, or {@code null}.
      */
     @Override
     @XmlElement(name = "schemaAscii")
-    @XmlJavaTypeAdapter(URIStringAdapter.class)
-    public URI getSchemaAscii()  {
+    @XmlJavaTypeAdapter(CharSequenceAdapter.Since2014.class)
+    public CharSequence getSchemaAscii()  {
         return schemaAscii;
     }
 
     /**
      * Sets the full application schema given as an ASCII file.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * {@code URI} may be replaced by {@link CharSequence} in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new ASCII file.
      */
-    public void setSchemaAscii(final URI newValue) {
+    public void setSchemaAscii(final CharSequence newValue) {
         checkWritePermission();
         schemaAscii = newValue;
     }
@@ -272,31 +265,21 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
     /**
      * Full application schema given as a graphics file.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return application schema as a graphics file, or {@code null}.
      */
     @Override
     @XmlElement(name = "graphicsFile")
-    @XmlJavaTypeAdapter(OnlineResourceAdapter.class)
-    public URI getGraphicsFile()  {
+    @XmlJavaTypeAdapter(CI_OnlineResource.Since2014.class)
+    public OnlineResource getGraphicsFile()  {
         return graphicsFile;
     }
 
     /**
      * Sets the full application schema given as a graphics file.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new graphics file.
      */
-    public void setGraphicsFile(final URI newValue) {
+    public void setGraphicsFile(final OnlineResource newValue) {
         checkWritePermission();
         graphicsFile = newValue;
     }
@@ -304,31 +287,21 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
     /**
      * Full application schema given as a software development file.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return application schema as a software development file, or {@code null}.
      */
     @Override
     @XmlElement(name = "softwareDevelopmentFile")
-    @XmlJavaTypeAdapter(OnlineResourceAdapter.class)
-    public URI getSoftwareDevelopmentFile()  {
+    @XmlJavaTypeAdapter(CI_OnlineResource.Since2014.class)
+    public OnlineResource getSoftwareDevelopmentFile()  {
         return softwareDevelopmentFile;
     }
 
     /**
      * Sets the full application schema given as a software development file.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * As of ISO 19115:2014, {@code URI} is replaced by {@link OnlineResource}.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new software development file.
      */
-    public void setSoftwareDevelopmentFile(final URI newValue) {
+    public void setSoftwareDevelopmentFile(final OnlineResource newValue) {
         checkWritePermission();
         softwareDevelopmentFile = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
index 12d7e7b..a810d70 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultExtendedElementInformation.java
@@ -22,9 +22,9 @@ import java.util.Iterator;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.annotation.Obligation;
 import org.opengis.metadata.Datatype;
-import org.opengis.metadata.Obligation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.ExtendedElementInformation;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.TitleProperty;
@@ -101,7 +101,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 5892811836634834434L;
+    private static final long serialVersionUID = 489138542195499530L;
 
     /**
      * Name of the extended metadata element.
@@ -176,12 +176,12 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
     /**
      * Reason for creating the extended element.
      */
-    private Collection<InternationalString> rationales;
+    private InternationalString rationale;
 
     /**
      * Name of the person or organization creating the extended element.
      */
-    private Collection<ResponsibleParty> sources;
+    private Collection<Responsibility> sources;
 
     /**
      * Construct an initially empty extended element information.
@@ -206,7 +206,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
                                              final Datatype     dataType,
                                              final String       parentEntity,
                                              final CharSequence rule,
-                                             final ResponsibleParty source)
+                                             final Responsibility source)
     {
         this.name         = name;
         this.definition   = Types.toInternationalString(definition);
@@ -214,7 +214,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
         this.dataType     = dataType;
         this.parentEntity = singleton(parentEntity, String.class);
         this.rule         = Types.toInternationalString(rule);
-        this.sources      = singleton(source, ResponsibleParty.class);
+        this.sources      = singleton(source, Responsibility.class);
     }
 
     /**
@@ -248,8 +248,8 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
             domainValue       = object.getDomainValue();
             parentEntity      = copyCollection(object.getParentEntity(), String.class);
             rule              = object.getRule();
-            rationales        = copyCollection(object.getRationales(), InternationalString.class);
-            sources           = copyCollection(object.getSources(), ResponsibleParty.class);
+            rationale         = object.getRationale();
+            sources           = copyCollection(object.getSources(), Responsibility.class);
         }
     }
 
@@ -546,8 +546,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
     @Override
     @XmlElement(name = "rationale")
     public InternationalString getRationale() {
-        return LegacyPropertyAdapter.getSingleton(rationales, InternationalString.class, null,
-                DefaultExtendedElementInformation.class, "getRationale");
+        return rationale;
     }
 
     /**
@@ -558,7 +557,8 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @since 0.5
      */
     public void setRationale(final InternationalString newValue) {
-        rationales = writeCollection(LegacyPropertyAdapter.asCollection(newValue), rationales, InternationalString.class);
+        checkWritePermission();
+        rationale = newValue;
     }
 
     /**
@@ -609,31 +609,21 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
     /**
      * Name of the person or organization creating the extended element.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return name of the person or organization creating the extended element.
      */
     @Override
     @XmlElement(name = "source", required = true)
-    public Collection<ResponsibleParty> getSources() {
-        return sources = nonNullCollection(sources, ResponsibleParty.class);
+    public Collection<Responsibility> getSources() {
+        return sources = nonNullCollection(sources, Responsibility.class);
     }
 
     /**
      * Sets the name of the person or organization creating the extended element.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new sources.
      */
-    public void setSources(final Collection<? extends ResponsibleParty> newValues) {
-        sources = writeCollection(newValues, sources, ResponsibleParty.class);
+    public void setSources(final Collection<? extends Responsibility> newValues) {
+        sources = writeCollection(newValues, sources, Responsibility.class);
     }
 
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java
index f1c6f0b..4f0399b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadata.java
@@ -42,7 +42,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.OnlineResource;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.content.ContentInformation;
 import org.opengis.metadata.distribution.Distribution;
@@ -188,7 +188,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 7337533776231004504L;
+    private static final long serialVersionUID = -4935599812744534502L;
 
     /**
      * Unique identifier for this metadata record, or {@code null} if none.
@@ -218,7 +218,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
     /**
      * Parties responsible for the metadata information.
      */
-    private Collection<ResponsibleParty> contacts;
+    private Collection<Responsibility> contacts;
 
     /**
      * Date(s) associated with the metadata.
@@ -274,7 +274,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
     /**
      * Provides information about the distributor of and options for obtaining the resource(s).
      */
-    private Distribution distributionInfo;
+    private Collection<Distribution> distributionInfo;
 
     /**
      * Provides overall assessment of quality of a resource(s).
@@ -324,11 +324,11 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      * @param dateStamp           date that the metadata was created.
      * @param identificationInfo  basic information about the resource to which the metadata applies.
      */
-    public DefaultMetadata(final ResponsibleParty contact,
+    public DefaultMetadata(final Responsibility contact,
                            final Date           dateStamp,
                            final Identification identificationInfo)
     {
-        this.contacts  = singleton(contact, ResponsibleParty.class);
+        this.contacts  = singleton(contact, Responsibility.class);
         this.identificationInfo = singleton(identificationInfo, Identification.class);
         if (dateStamp != null) {
             dateInfo = singleton(new DefaultCitationDate(dateStamp, DateType.CREATION), CitationDate.class);
@@ -352,7 +352,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
             languages                     = copyCollection(object.getLanguages(),                     Locale.class);
             characterSets                 = copyCollection(object.getCharacterSets(),                 Charset.class);
             metadataScopes                = copyCollection(object.getMetadataScopes(),                MetadataScope.class);
-            contacts                      = copyCollection(object.getContacts(),                      ResponsibleParty.class);
+            contacts                      = copyCollection(object.getContacts(),                      Responsibility.class);
             dateInfo                      = copyCollection(object.getDateInfo(),                      CitationDate.class);
             metadataStandards             = copyCollection(object.getMetadataStandards(),             Citation.class);
             metadataProfiles              = copyCollection(object.getMetadataProfiles(),              Citation.class);
@@ -363,7 +363,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
             metadataExtensionInfo         = copyCollection(object.getMetadataExtensionInfo(),         MetadataExtensionInformation.class);
             identificationInfo            = copyCollection(object.getIdentificationInfo(),            Identification.class);
             contentInfo                   = copyCollection(object.getContentInfo(),                   ContentInformation.class);
-            distributionInfo              = object.getDistributionInfo();
+            distributionInfo              = copyCollection(object.getDistributionInfo(),              Distribution.class);
             dataQualityInfo               = copyCollection(object.getDataQualityInfo(),               DataQuality.class);
             portrayalCatalogueInfo        = copyCollection(object.getPortrayalCatalogueInfo(),        PortrayalCatalogueReference.class);
             metadataConstraints           = copyCollection(object.getMetadataConstraints(),           Constraints.class);
@@ -865,17 +865,12 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
     /**
      * Returns the parties responsible for the metadata information.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return parties responsible for the metadata information.
      */
     @Override
     @XmlElement(name = "contact", required = true)
-    public Collection<ResponsibleParty> getContacts() {
-        return contacts = nonNullCollection(contacts, ResponsibleParty.class);
+    public Collection<Responsibility> getContacts() {
+        return contacts = nonNullCollection(contacts, Responsibility.class);
     }
 
     /**
@@ -883,9 +878,9 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      *
      * @param  newValues  the new contacts.
      */
-    public void setContacts(final Collection<? extends ResponsibleParty> newValues) {
+    public void setContacts(final Collection<? extends Responsibility> newValues) {
         checkWritePermission();
-        contacts = writeCollection(newValues, contacts, ResponsibleParty.class);
+        contacts = writeCollection(newValues, contacts, Responsibility.class);
     }
 
     /**
@@ -1368,32 +1363,21 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
     /**
      * Returns information about the distributor of and options for obtaining the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
-     * As of ISO 19115:2014, this singleton has been replaced by a collection.
-     * This change will tentatively be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return the distributor of and options for obtaining the resource(s).
      */
     @Override
     @XmlElement(name = "distributionInfo")
-    public Distribution getDistributionInfo() {
-        return distributionInfo;
+    public Collection<Distribution> getDistributionInfo() {
+        return distributionInfo = nonNullCollection(distributionInfo, Distribution.class);
     }
 
     /**
      * Sets information about the distributor of and options for obtaining the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
-     * As of ISO 19115:2014, this singleton has been replaced by a collection.
-     * This change will tentatively be applied in GeoAPI 4.0.
-     * </div>
-     *
-     * @param  newValue  the new distribution info.
+     * @param  newValues  the new distribution info.
      */
-    public void setDistributionInfo(final Distribution newValue) {
-        checkWritePermission();
-        distributionInfo = newValue;
+    public void setDistributionInfo(final Collection<? extends Distribution> newValues) {
+        distributionInfo = writeCollection(newValues, distributionInfo, Distribution.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
index 6f88327..f372aaa 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ImmutableIdentifier.java
@@ -26,7 +26,6 @@ import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.parameter.ParameterValue;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.Types;
@@ -138,7 +137,7 @@ import static org.apache.sis.util.collection.Containers.property;
     "version"
 })
 @XmlRootElement(name = "RS_Identifier", namespace = Namespaces.GMD)
-public class ImmutableIdentifier extends FormattableObject implements ReferenceIdentifier, Serializable {
+public class ImmutableIdentifier extends FormattableObject implements Identifier, Serializable {
     /**
      * For cross-version compatibility.
      */
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/OnlineResourceAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/OnlineResourceAdapter.java
deleted file mode 100644
index 9e7a202..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/OnlineResourceAdapter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.metadata.iso;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-import org.opengis.metadata.citation.OnlineResource;
-import org.apache.sis.internal.jaxb.metadata.CI_OnlineResource;
-import org.apache.sis.metadata.iso.citation.DefaultOnlineResource;
-
-
-/**
- * Converts an URI to a {@code <cit:OnlineResource>} element for ISO 19115-3:2016 compliance.
- * We need this additional adapter because some property type changed from {@code URI} to
- * {@code OnlineResource} in the upgrade from ISO 19115:2003 to ISO 19115-1:2014.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   1.0
- */
-final class OnlineResourceAdapter extends XmlAdapter<CI_OnlineResource, URI> {
-    /**
-     * The adapter performing the actual work.
-     */
-    private static final CI_OnlineResource ADAPTER = new CI_OnlineResource.Since2014();
-
-    /**
-     * Wraps the given URI in a {@code <cit:OnlineResource>} element.
-     */
-    @Override
-    public CI_OnlineResource marshal(final URI value) {
-        if (value != null) {
-            return ADAPTER.marshal(new DefaultOnlineResource(value));
-        }
-        return null;
-    }
-
-    /**
-     * Returns a URI from the given {@code <cit:OnlineResource>} element.
-     */
-    @Override
-    public URI unmarshal(final CI_OnlineResource value) throws URISyntaxException {
-        if (value != null) {
-            final OnlineResource res = ADAPTER.unmarshal(value);
-            if (res != null) {
-                return res.getLinkage();
-            }
-        }
-        return null;
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/URIStringAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/URIStringAdapter.java
deleted file mode 100644
index 07b42c5..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/URIStringAdapter.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.metadata.iso;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-import org.apache.sis.internal.jaxb.Context;
-import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
-import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
-
-
-/**
- * Converts an URI to a {@code <gco:CharacterSequence>} element for ISO 19115-3:2016 compliance.
- * We need this additional adapter because some property type changed from {@code URI}
- * to {@code CharacterSequence} in the upgrade from ISO 19115:2003 to ISO 19115-1:2014.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   1.0
- */
-final class URIStringAdapter extends XmlAdapter<GO_CharacterString, URI> {
-    /**
-     * The adapter performing the actual work.
-     */
-    private static final CharSequenceAdapter ADAPTER = new CharSequenceAdapter.Since2014();
-
-    /**
-     * Wraps the given URI in a {@code <cit:OnlineResource>} element.
-     */
-    @Override
-    public GO_CharacterString marshal(final URI value) {
-        if (value != null) {
-            return ADAPTER.marshal(value.toString());
-        }
-        return null;
-    }
-
-    /**
-     * Returns a URI from the given {@code <cit:OnlineResource>} element.
-     */
-    @Override
-    public URI unmarshal(final GO_CharacterString value) throws URISyntaxException {
-        if (value != null) {
-            final CharSequence uri = ADAPTER.unmarshal(value);
-            if (uri != null) {
-                final Context context = Context.current();
-                return Context.converter(context).toURI(context, uri.toString());
-            }
-        }
-        return null;
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java
index 5e5e70c..79bbb55 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatform.java
@@ -24,7 +24,7 @@ import org.opengis.metadata.Identifier;
 import org.opengis.metadata.acquisition.Instrument;
 import org.opengis.metadata.acquisition.Platform;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
@@ -85,7 +85,7 @@ public class DefaultPlatform extends ISOMetadata implements Platform {
     /**
      * Organization responsible for building, launch, or operation of the platform.
      */
-    private Collection<ResponsibleParty> sponsors;
+    private Collection<Responsibility> sponsors;
 
     /**
      * Instrument(s) mounted on a platform.
@@ -113,7 +113,7 @@ public class DefaultPlatform extends ISOMetadata implements Platform {
             citation    = object.getCitation();
             identifiers = singleton(object.getIdentifier(), Identifier.class);
             description = object.getDescription();
-            sponsors    = copyCollection(object.getSponsors(), ResponsibleParty.class);
+            sponsors    = copyCollection(object.getSponsors(), Responsibility.class);
             instruments = copyCollection(object.getInstruments(), Instrument.class);
         }
     }
@@ -210,31 +210,21 @@ public class DefaultPlatform extends ISOMetadata implements Platform {
     /**
      * Returns the organization responsible for building, launch, or operation of the platform.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return organization responsible for building, launch, or operation of the platform.
      */
     @Override
     @XmlElement(name = "sponsor")
-    public Collection<ResponsibleParty> getSponsors() {
-        return sponsors = nonNullCollection(sponsors, ResponsibleParty.class);
+    public Collection<Responsibility> getSponsors() {
+        return sponsors = nonNullCollection(sponsors, Responsibility.class);
     }
 
     /**
      * Sets the organization responsible for building, launch, or operation of the platform.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new sponsors values;
      */
-    public void setSponsors(final Collection<? extends ResponsibleParty> newValues) {
-        sponsors = writeCollection(newValues, sponsors, ResponsibleParty.class);
+    public void setSponsors(final Collection<? extends Responsibility> newValues) {
+        sponsors = writeCollection(newValues, sponsors, Responsibility.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java
index 8374339..34f6e5d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequirement.java
@@ -27,7 +27,7 @@ import org.opengis.metadata.acquisition.Priority;
 import org.opengis.metadata.acquisition.RequestedDate;
 import org.opengis.metadata.acquisition.Requirement;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.apache.sis.metadata.iso.ISOMetadata;
 import org.apache.sis.internal.jaxb.NonMarshalledAuthority;
 
@@ -95,12 +95,12 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
     /**
      * Origin of requirement.
      */
-    private Collection<ResponsibleParty> requestors;
+    private Collection<Responsibility> requestors;
 
     /**
      * Person(s), or body(ies), to receive results of requirement.
      */
-    private Collection<ResponsibleParty> recipients;
+    private Collection<Responsibility> recipients;
 
     /**
      * Relative ordered importance, or urgency, of the requirement.
@@ -143,8 +143,8 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
         if (object != null) {
             citation       = object.getCitation();
             identifiers    = singleton(object.getIdentifier(), Identifier.class);
-            requestors     = copyCollection(object.getRequestors(), ResponsibleParty.class);
-            recipients     = copyCollection(object.getRecipients(), ResponsibleParty.class);
+            requestors     = copyCollection(object.getRequestors(), Responsibility.class);
+            recipients     = copyCollection(object.getRecipients(), Responsibility.class);
             priority       = object.getPriority();
             requestedDate  = object.getRequestedDate();
             expiryDate     = toMilliseconds(object.getExpiryDate());
@@ -224,61 +224,41 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
     /**
      * Returns the origin of requirement.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return origin of requirement.
      */
     @Override
     @XmlElement(name = "requestor", required = true)
-    public Collection<ResponsibleParty> getRequestors() {
-        return requestors = nonNullCollection(requestors, ResponsibleParty.class);
+    public Collection<Responsibility> getRequestors() {
+        return requestors = nonNullCollection(requestors, Responsibility.class);
     }
 
     /**
      * Sets the origin of requirement.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new requestors values.
      */
-    public void setRequestors(final Collection<? extends ResponsibleParty> newValues) {
-        requestors = writeCollection(newValues, requestors, ResponsibleParty.class);
+    public void setRequestors(final Collection<? extends Responsibility> newValues) {
+        requestors = writeCollection(newValues, requestors, Responsibility.class);
     }
 
     /**
      * Returns the person(s), or body(ies), to receive results of requirement.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return person(s), or body(ies), to receive results.
      */
     @Override
     @XmlElement(name = "recipient", required = true)
-    public Collection<ResponsibleParty> getRecipients() {
-        return recipients = nonNullCollection(recipients, ResponsibleParty.class);
+    public Collection<Responsibility> getRecipients() {
+        return recipients = nonNullCollection(recipients, Responsibility.class);
     }
 
     /**
      * Sets the Person(s), or body(ies), to receive results of requirement.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new recipients values.
      */
-    public void setRecipients(final Collection<? extends ResponsibleParty> newValues) {
-        recipients = writeCollection(newValues, recipients, ResponsibleParty.class);
+    public void setRecipients(final Collection<? extends Responsibility> newValues) {
+        recipients = writeCollection(newValues, recipients, Responsibility.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java
index 6bb47b9..46b16ec 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/package-info.java
@@ -100,7 +100,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
+    @XmlJavaTypeAdapter(CI_Responsibility.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
     @XmlJavaTypeAdapter(GO_Real.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java
index 44bd85b..efddcb6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultAddress.java
@@ -83,7 +83,7 @@ public class DefaultAddress extends ISOMetadata implements Address {
     /**
      * Address line for the location (as described in ISO 11180, Annex A).
      */
-    private Collection<String> deliveryPoints;
+    private Collection<InternationalString> deliveryPoints;
 
     /**
      * Address of the electronic mailbox of the responsible organization or individual.
@@ -108,7 +108,7 @@ public class DefaultAddress extends ISOMetadata implements Address {
     public DefaultAddress(final Address object) {
         super(object);
         if (object != null) {
-            deliveryPoints          = copyCollection(object.getDeliveryPoints(), String.class);
+            deliveryPoints          = copyCollection(object.getDeliveryPoints(), InternationalString.class);
             city                    = object.getCity();
             administrativeArea      = object.getAdministrativeArea();
             postalCode              = object.getPostalCode();
@@ -208,31 +208,21 @@ public class DefaultAddress extends ISOMetadata implements Address {
     /**
      * Returns the address line for the location (as described in ISO 11180, Annex A).
      *
-     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
-     * The return type may be changed from {@code Collection<String>} to
-     * {@code Collection<? extends InternationalString>} in GeoAPI 4.0.
-     * </div>
-     *
      * @return address line for the location.
      */
     @Override
     @XmlElement(name = "deliveryPoint")
-    public Collection<String> getDeliveryPoints() {
-        return deliveryPoints = nonNullCollection(deliveryPoints, String.class);
+    public Collection<InternationalString> getDeliveryPoints() {
+        return deliveryPoints = nonNullCollection(deliveryPoints, InternationalString.class);
     }
 
     /**
      * Sets the address line for the location (as described in ISO 11180, Annex A).
      *
-     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
-     * The argument type may be changed from {@code Collection<String>} to
-     * {@code Collection<? extends InternationalString>} in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new delivery points, or {@code null} if none.
      */
-    public void setDeliveryPoints(final Collection<? extends String> newValues) {
-        deliveryPoints = writeCollection(newValues, deliveryPoints, String.class);
+    public void setDeliveryPoints(final Collection<? extends InternationalString> newValues) {
+        deliveryPoints = writeCollection(newValues, deliveryPoints, InternationalString.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
index 8f4d457..96a13d3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitation.java
@@ -26,7 +26,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.identification.BrowseGraphic;
 import org.opengis.util.InternationalString;
@@ -99,7 +99,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 3490090845236158848L;
+    private static final long serialVersionUID = -7343644724857519090L;
 
     /**
      * Name by which the cited resource is known.
@@ -132,7 +132,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * Roles, Name, contact, and position information for an individual or organization that is responsible
      * for the resource.
      */
-    private Collection<ResponsibleParty> citedResponsibleParties;
+    private Collection<Responsibility> citedResponsibleParties;
 
     /**
      * Mode in which the resource is represented, or an empty collection if none.
@@ -149,7 +149,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * Other information required to complete the citation that is not recorded elsewhere.
      * May be {@code null} if none.
      */
-    private InternationalString otherCitationDetails;
+    private Collection<InternationalString> otherCitationDetails;
 
     /**
      * Common title with holdings note. Note: title identifies elements of a series
@@ -206,10 +206,10 @@ public class DefaultCitation extends ISOMetadata implements Citation {
             edition                 = object.getEdition();
             editionDate             = toMilliseconds(object.getEditionDate());
             identifiers             = copyCollection(object.getIdentifiers(), Identifier.class);
-            citedResponsibleParties = copyCollection(object.getCitedResponsibleParties(), ResponsibleParty.class);
+            citedResponsibleParties = copyCollection(object.getCitedResponsibleParties(), Responsibility.class);
             presentationForms       = copyCollection(object.getPresentationForms(), PresentationForm.class);
             series                  = object.getSeries();
-            otherCitationDetails    = object.getOtherCitationDetails();
+            otherCitationDetails    = copyCollection(object.getOtherCitationDetails(), InternationalString.class);
             collectiveTitle         = object.getCollectiveTitle();
             onlineResources         = copyCollection(object.getOnlineResources(), OnlineResource.class);
             graphics                = copyCollection(object.getGraphics(), BrowseGraphic.class);
@@ -402,32 +402,22 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * Returns the role, name, contact and position information for an individual or organization
      * that is responsible for the resource.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return the individual or organization that is responsible, or an empty collection if none.
      */
     @Override
     @XmlElement(name = "citedResponsibleParty")
-    public Collection<ResponsibleParty> getCitedResponsibleParties() {
-        return citedResponsibleParties = nonNullCollection(citedResponsibleParties, ResponsibleParty.class);
+    public Collection<Responsibility> getCitedResponsibleParties() {
+        return citedResponsibleParties = nonNullCollection(citedResponsibleParties, Responsibility.class);
     }
 
     /**
      * Sets the role, name, contact and position information for an individual or organization
      * that is responsible for the resource.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new cited responsible parties, or {@code null} if none.
      */
-    public void setCitedResponsibleParties(final Collection<? extends ResponsibleParty> newValues) {
-        citedResponsibleParties = writeCollection(newValues, citedResponsibleParties, ResponsibleParty.class);
+    public void setCitedResponsibleParties(final Collection<? extends Responsibility> newValues) {
+        citedResponsibleParties = writeCollection(newValues, citedResponsibleParties, Responsibility.class);
     }
 
     /**
@@ -474,32 +464,21 @@ public class DefaultCitation extends ISOMetadata implements Citation {
     /**
      * Returns other information required to complete the citation that is not recorded elsewhere.
      *
-     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
-     * As of ISO 19115:2014, this singleton has been replaced by a collection.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return other details, or {@code null} if none.
      */
     @Override
     @XmlElement(name = "otherCitationDetails")
-    public InternationalString getOtherCitationDetails() {
-        return otherCitationDetails;
+    public Collection<InternationalString> getOtherCitationDetails() {
+        return otherCitationDetails = nonNullCollection(otherCitationDetails, InternationalString.class);
     }
 
     /**
      * Sets other information required to complete the citation that is not recorded elsewhere.
      *
-     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
-     * As of ISO 19115:2014, this singleton has been replaced by a collection.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
-     * @param newValue Other citations details, or {@code null} if none.
+     * @param newValues Other citations details.
      */
-    public void setOtherCitationDetails(final InternationalString newValue) {
-        checkWritePermission();
-        otherCitationDetails = newValue;
+    public void setOtherCitationDetails(final Collection<? extends InternationalString> newValues) {
+        otherCitationDetails = writeCollection(newValues, otherCitationDetails, InternationalString.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
index 0cc12d9..cfa5556 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultContact.java
@@ -97,7 +97,7 @@ public class DefaultContact extends ISOMetadata implements Contact {
     /**
      * Time period (including time zone) when individuals can contact the organization or individual.
      */
-    private InternationalString hoursOfService;
+    private Collection<InternationalString> hoursOfService;
 
     /**
      * Supplemental instructions on how or when to contact the individual or organization.
@@ -140,7 +140,7 @@ public class DefaultContact extends ISOMetadata implements Contact {
             phones              = copyCollection(object.getPhones(), Telephone.class);
             addresses           = copyCollection(object.getAddresses(), Address.class);
             onlineResources     = copyCollection(object.getOnlineResources(), OnlineResource.class);
-            hoursOfService      = object.getHoursOfService();
+            hoursOfService      = copyCollection(object.getHoursOfService(), InternationalString.class);
             contactInstructions = object.getContactInstructions();
             contactType         = object.getContactType();
         }
@@ -400,32 +400,21 @@ public class DefaultContact extends ISOMetadata implements Contact {
     /**
      * Returns the time period (including time zone) when individuals can contact the organization or individual.
      *
-     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
-     * As of ISO 19115:2014, this singleton has been replaced by a collection.
-     * This change will tentatively be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return time period when individuals can contact the organization or individual.
      */
     @Override
     @XmlElement(name = "hoursOfService")
-    public InternationalString getHoursOfService() {
-        return hoursOfService;
+    public Collection<InternationalString> getHoursOfService() {
+        return hoursOfService = nonNullCollection(hoursOfService, InternationalString.class);
     }
 
     /**
      * Sets time period (including time zone) when individuals can contact the organization or individual.
      *
-     * <div class="warning"><b>Upcoming API change — multiplicity</b><br>
-     * As of ISO 19115:2014, this singleton has been replaced by a collection.
-     * This change will tentatively be applied in GeoAPI 4.0.
-     * </div>
-     *
-     * @param  newValue  the new hours of service.
+     * @param  newValues  the new hours of service.
      */
-    public void setHoursOfService(final InternationalString newValue) {
-        checkWritePermission();
-        hoursOfService = newValue;
+    public void setHoursOfService(final Collection<? extends InternationalString> newValues) {
+        hoursOfService = writeCollection(newValues, hoursOfService, InternationalString.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java
index c4f3955..c1249ce 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultOnlineResource.java
@@ -90,7 +90,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
     /**
      * Name of the online resources.
      */
-    private String name;
+    private InternationalString name;
 
     /**
      * Detailed text description of what the online resource is/does.
@@ -196,28 +196,20 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
     /**
      * Name of the online resource. Returns {@code null} if none.
      *
-     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
-     * The return type may be changed from {@code String} to {@code InternationalString} in GeoAPI 4.0.
-     * </div>
-     *
      * @return name of the online resource, or {@code null}.
      */
     @Override
     @XmlElement(name = "name")
-    public String getName() {
+    public InternationalString getName() {
         return name;
     }
 
     /**
      * Sets the name of the online resource.
      *
-     * <div class="warning"><b>Upcoming API change — internationalization</b><br>
-     * The argument type may be changed from {@code String} to {@code InternationalString} in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new name, or {@code null} if none.
      */
-    public void setName(final String newValue) {
+    public void setName(final InternationalString newValue) {
         checkWritePermission();
         name = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java
index ceaa186..564b97a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultSeries.java
@@ -54,7 +54,7 @@ public class DefaultSeries extends ISOMetadata implements Series {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 7061644572814855051L;
+    private static final long serialVersionUID = -1584743260325409070L;
 
     /**
      * Name of the series, or aggregate dataset, of which the dataset is a part.
@@ -64,12 +64,12 @@ public class DefaultSeries extends ISOMetadata implements Series {
     /**
      * Information identifying the issue of the series.
      */
-    private String issueIdentification;
+    private InternationalString issueIdentification;
 
     /**
      * Details on which pages of the publication the article was published.
      */
-    private String page;
+    private InternationalString page;
 
     /**
      * Constructs a default series.
@@ -153,30 +153,20 @@ public class DefaultSeries extends ISOMetadata implements Series {
     /**
      * Returns information identifying the issue of the series.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return information identifying the issue of the series, or {@code null}.
      */
     @Override
     @XmlElement(name = "issueIdentification")
-    public String getIssueIdentification() {
+    public InternationalString getIssueIdentification() {
         return issueIdentification;
     }
 
     /**
      * Sets information identifying the issue of the series.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new issue identification, or {@code null} if none.
      */
-    public void setIssueIdentification(final String newValue) {
+    public void setIssueIdentification(final InternationalString newValue) {
         checkWritePermission();
         issueIdentification = newValue;
     }
@@ -184,30 +174,20 @@ public class DefaultSeries extends ISOMetadata implements Series {
     /**
      * Returns details on which pages of the publication the article was published.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return details on which pages of the publication the article was published, or {@code null}.
      */
     @Override
     @XmlElement(name = "page")
-    public String getPage() {
+    public InternationalString getPage() {
         return page;
     }
 
     /**
      * Sets details on which pages of the publication the article was published.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code String} is replaced by the {@link InternationalString} interface.
-     * This change will be tentatively applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new page, or {@code null} if none.
      */
-    public void setPage(final String newValue) {
+    public void setPage(final InternationalString newValue) {
         checkWritePermission();
         page = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
index 8a98a5b..41bd627 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/package-info.java
@@ -108,7 +108,7 @@
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
     @XmlJavaTypeAdapter(CI_Party.class),
     @XmlJavaTypeAdapter(CI_PresentationFormCode.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
+    @XmlJavaTypeAdapter(CI_Responsibility.class),
     @XmlJavaTypeAdapter(CI_RoleCode.class),
     @XmlJavaTypeAdapter(CI_Series.class),
     @XmlJavaTypeAdapter(CI_Telephone.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java
index 5ac6dca..238e7d8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistributor.java
@@ -20,7 +20,7 @@ import java.util.Collection;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.distribution.Distributor;
 import org.opengis.metadata.distribution.StandardOrderProcess;
@@ -71,12 +71,12 @@ public class DefaultDistributor extends ISOMetadata implements Distributor {
     /**
      * Serial number for inter-operability with different versions.
      */
-    private static final long serialVersionUID = 5706757156163948001L;
+    private static final long serialVersionUID = -8819538342342106743L;
 
     /**
      * Party from whom the resource may be obtained. This list need not be exhaustive.
      */
-    private ResponsibleParty distributorContact;
+    private Responsibility distributorContact;
 
     /**
      * Provides information about how the resource may be obtained, and related
@@ -105,7 +105,7 @@ public class DefaultDistributor extends ISOMetadata implements Distributor {
      *
      * @param distributorContact  party from whom the resource may be obtained, or {@code null}.
      */
-    public DefaultDistributor(final ResponsibleParty distributorContact) {
+    public DefaultDistributor(final Responsibility distributorContact) {
         this.distributorContact = distributorContact;
     }
 
@@ -156,30 +156,20 @@ public class DefaultDistributor extends ISOMetadata implements Distributor {
     /**
      * Party from whom the resource may be obtained.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return party from whom the resource may be obtained, or {@code null}.
      */
     @Override
     @XmlElement(name = "distributorContact", required = true)
-    public ResponsibleParty getDistributorContact() {
+    public Responsibility getDistributorContact() {
         return distributorContact;
     }
 
     /**
      * Sets the party from whom the resource may be obtained.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValue  the new distributor contact.
      */
-    public void setDistributorContact(final ResponsibleParty newValue) {
+    public void setDistributorContact(final Responsibility newValue) {
         checkWritePermission();
         distributorContact = newValue;
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
index 877e5af..3025f16 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/package-info.java
@@ -97,7 +97,6 @@
     @XmlJavaTypeAdapter(MD_Medium.class),
     @XmlJavaTypeAdapter(MD_MediumFormatCode.class),
     @XmlJavaTypeAdapter(MD_MediumNameCode.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
     @XmlJavaTypeAdapter(MD_StandardOrderProcess.class),
 
     // Java types, primitive types and basic OGC types handling
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java
index 5ef5201..4ff5e99 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/AbstractIdentification.java
@@ -24,7 +24,7 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.extent.Extent;
@@ -145,7 +145,7 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
     /**
      * Recognition of those who contributed to the resource(s).
      */
-    private Collection<String> credits;
+    private Collection<InternationalString> credits;
 
     /**
      * Status of the resource(s).
@@ -156,7 +156,7 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
      * Identification of, and means of communication with, person(s) and organizations(s)
      * associated with the resource(s).
      */
-    private Collection<ResponsibleParty> pointOfContacts;
+    private Collection<Responsibility> pointOfContacts;
 
     /**
      * Methods used to spatially represent geographic information.
@@ -261,9 +261,9 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
             citation                   = object.getCitation();
             abstracts                  = object.getAbstract();
             purpose                    = object.getPurpose();
-            credits                    = copyCollection(object.getCredits(), String.class);
+            credits                    = copyCollection(object.getCredits(), InternationalString.class);
             status                     = copyCollection(object.getStatus(), Progress.class);
-            pointOfContacts            = copyCollection(object.getPointOfContacts(), ResponsibleParty.class);
+            pointOfContacts            = copyCollection(object.getPointOfContacts(), Responsibility.class);
             spatialRepresentationTypes = copyCollection(object.getSpatialRepresentationTypes(), SpatialRepresentationType.class);
             spatialResolutions         = copyCollection(object.getSpatialResolutions(), Resolution.class);
             temporalResolutions        = copyCollection(object.getTemporalResolutions(), Duration.class);
@@ -384,29 +384,21 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
     /**
      * Returns the recognition of those who contributed to the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * The element type may be changed to the {@code InternationalString} interface in GeoAPI 4.0.
-     * </div>
-     *
      * @return recognition of those who contributed to the resource(s).
      */
     @Override
     @XmlElement(name = "credit")
-    public Collection<String> getCredits() {
-        return credits = nonNullCollection(credits, String.class);
+    public Collection<InternationalString> getCredits() {
+        return credits = nonNullCollection(credits, InternationalString.class);
     }
 
     /**
      * Sets the recognition of those who contributed to the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * The element type may be changed to the {@code InternationalString} interface in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new credits.
      */
-    public void setCredits(final Collection<? extends String> newValues) {
-        credits = writeCollection(newValues, credits, String.class);
+    public void setCredits(final Collection<? extends InternationalString> newValues) {
+        credits = writeCollection(newValues, credits, InternationalString.class);
     }
 
     /**
@@ -433,33 +425,23 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
      * Returns the identification of, and means of communication with, person(s) and organizations(s)
      * associated with the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return means of communication with person(s) and organizations(s) associated with the resource(s).
      *
      * @see org.apache.sis.metadata.iso.DefaultMetadata#getContacts()
      */
     @Override
     @XmlElement(name = "pointOfContact")
-    public Collection<ResponsibleParty> getPointOfContacts() {
-        return pointOfContacts = nonNullCollection(pointOfContacts, ResponsibleParty.class);
+    public Collection<Responsibility> getPointOfContacts() {
+        return pointOfContacts = nonNullCollection(pointOfContacts, Responsibility.class);
     }
 
     /**
      * Sets the means of communication with persons(s) and organizations(s) associated with the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new points of contacts.
      */
-    public void setPointOfContacts(final Collection<? extends ResponsibleParty> newValues) {
-        pointOfContacts = writeCollection(newValues, pointOfContacts, ResponsibleParty.class);
+    public void setPointOfContacts(final Collection<? extends Responsibility> newValues) {
+        pointOfContacts = writeCollection(newValues, pointOfContacts, Responsibility.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java
index 987a81f..4a12fa6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentification.java
@@ -25,7 +25,6 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.identification.CharacterSet;
 import org.opengis.metadata.identification.TopicCategory;
 import org.opengis.metadata.identification.DataIdentification;
 import org.apache.sis.internal.metadata.OtherLocales;
@@ -94,7 +93,7 @@ public class DefaultDataIdentification extends AbstractIdentification implements
     /**
      * Serial number for compatibility with different versions.
      */
-    private static final long serialVersionUID = 6104637930243499850L;
+    private static final long serialVersionUID = 6104637930243499851L;
 
     /**
      * Language(s) used within the dataset.
@@ -104,7 +103,7 @@ public class DefaultDataIdentification extends AbstractIdentification implements
     /**
      * Full name of the character coding standard used for the dataset.
      */
-    private Collection<CharacterSet> characterSets;
+    private Collection<Charset> characterSets;
 
     /**
      * Description of the dataset in the producer’s processing environment, including items
@@ -154,7 +153,7 @@ public class DefaultDataIdentification extends AbstractIdentification implements
         super(object);
         if (object != null) {
             languages                  = copyCollection(object.getLanguages(), Locale.class);
-            characterSets              = copyCollection(object.getCharacterSets(), CharacterSet.class);
+            characterSets              = copyCollection(object.getCharacterSets(), Charset.class);
             environmentDescription     = object.getEnvironmentDescription();
             supplementalInformation    = object.getSupplementalInformation();
         }
@@ -215,29 +214,21 @@ public class DefaultDataIdentification extends AbstractIdentification implements
     /**
      * Returns the character coding standard used for the dataset.
      *
-     * <div class="warning"><b>Upcoming API change — JDK integration</b><br>
-     * The element type may change to the {@link Charset} class in GeoAPI 4.0.
-     * </div>
-     *
      * @return character coding standard(s) used.
      */
     @Override
     @XmlElement(name = "characterSet", namespace = LegacyNamespaces.GMD)
-    public Collection<CharacterSet> getCharacterSets() {
-        return characterSets = nonNullCollection(characterSets, CharacterSet.class);
+    public Collection<Charset> getCharacterSets() {
+        return characterSets = nonNullCollection(characterSets, Charset.class);
     }
 
     /**
      * Sets the character coding standard used for the dataset.
      *
-     * <div class="warning"><b>Upcoming API change — JDK integration</b><br>
-     * The element type may change to the {@link Charset} class in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new character sets.
      */
-    public void setCharacterSets(final Collection<? extends CharacterSet> newValues) {
-        characterSets = writeCollection(newValues, characterSets, CharacterSet.class);
+    public void setCharacterSets(final Collection<? extends Charset> newValues) {
+        characterSets = writeCollection(newValues, characterSets, Charset.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
index 1b5f97c..782ca7b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultUsage.java
@@ -23,7 +23,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.identification.Usage;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.metadata.iso.ISOMetadata;
@@ -103,7 +103,7 @@ public class DefaultUsage extends ISOMetadata implements Usage {
     /**
      * Identification of and means of communicating with person(s) and organization(s) using the resource(s).
      */
-    private Collection<ResponsibleParty> userContactInfo;
+    private Collection<Responsibility> userContactInfo;
 
     /**
      * Responses to the user-determined limitations.
@@ -134,10 +134,10 @@ public class DefaultUsage extends ISOMetadata implements Usage {
      * @param userContactInfo  means of communicating with person(s) and organization(s), or {@code null} if none.
      */
     public DefaultUsage(final CharSequence specificUsage,
-                        final ResponsibleParty userContactInfo)
+                        final Responsibility userContactInfo)
     {
         this.specificUsage   = Types.toInternationalString(specificUsage);
-        this.userContactInfo = singleton(userContactInfo, ResponsibleParty.class);
+        this.userContactInfo = singleton(userContactInfo, Responsibility.class);
     }
 
     /**
@@ -155,7 +155,7 @@ public class DefaultUsage extends ISOMetadata implements Usage {
             specificUsage             = object.getSpecificUsage();
             usageDate                 = toMilliseconds(object.getUsageDate());
             userDeterminedLimitations = object.getUserDeterminedLimitations();
-            userContactInfo           = copyCollection(object.getUserContactInfo(), ResponsibleParty.class);
+            userContactInfo           = copyCollection(object.getUserContactInfo(), Responsibility.class);
             responses                 = copyCollection(object.getResponses(), InternationalString.class);
             additionalDocumentation   = copyCollection(object.getAdditionalDocumentation(), Citation.class);
             identifiedIssues          = copyCollection(object.getIdentifiedIssues(), Citation.class);
@@ -253,31 +253,21 @@ public class DefaultUsage extends ISOMetadata implements Usage {
     /**
      * Returns identification of and means of communicating with person(s) and organization(s) using the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return means of communicating with person(s) and organization(s) using the resource(s).
      */
     @Override
     @XmlElement(name = "userContactInfo")
-    public Collection<ResponsibleParty> getUserContactInfo() {
-        return userContactInfo = nonNullCollection(userContactInfo, ResponsibleParty.class);
+    public Collection<Responsibility> getUserContactInfo() {
+        return userContactInfo = nonNullCollection(userContactInfo, Responsibility.class);
     }
 
     /**
      * Sets identification of and means of communicating with person(s) and organization(s) using the resource(s).
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new user contact info.
      */
-    public void setUserContactInfo(final Collection<? extends ResponsibleParty> newValues) {
-        userContactInfo = writeCollection(newValues, userContactInfo, ResponsibleParty.class);
+    public void setUserContactInfo(final Collection<? extends Responsibility> newValues) {
+        userContactInfo = writeCollection(newValues, userContactInfo, Responsibility.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
index 1182479..4afb6e8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/package-info.java
@@ -115,7 +115,7 @@
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
+    @XmlJavaTypeAdapter(CI_Responsibility.class),
     @XmlJavaTypeAdapter(DCPList.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
@@ -124,7 +124,6 @@
     @XmlJavaTypeAdapter(MD_AssociatedResource.class),
     @XmlJavaTypeAdapter(MD_BrowseGraphic.class),
     @XmlJavaTypeAdapter(MD_CharacterSetCode.class),
-    @XmlJavaTypeAdapter(MD_CharacterSetLegacy.class),
     @XmlJavaTypeAdapter(MD_Constraints.class),
     @XmlJavaTypeAdapter(MD_DataIdentification.class),
     @XmlJavaTypeAdapter(MD_Format.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
index 4e7a925..b73d362 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStep.java
@@ -26,7 +26,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.InternationalString;
 import org.opengis.temporal.TemporalPrimitive;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.maintenance.Scope;
 import org.opengis.metadata.lineage.Source;
 import org.opengis.metadata.lineage.Processing;
@@ -110,7 +110,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * Identification of, and means of communication with, person(s) and
      * organization(s) associated with the process step.
      */
-    private Collection<ResponsibleParty> processors;
+    private Collection<Responsibility> processors;
 
     /**
      * Process step documentation.
@@ -174,7 +174,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
             description           = object.getDescription();
             rationale             = object.getRationale();
             stepDateTime          = TemporalUtilities.createInstant(object.getDate());
-            processors            = copyCollection(object.getProcessors(), ResponsibleParty.class);
+            processors            = copyCollection(object.getProcessors(), Responsibility.class);
             references            = copyCollection(object.getReferences(), Citation.class);
             sources               = copyCollection(object.getSources(), Source.class);
             scope                 = object.getScope();
@@ -306,32 +306,22 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * Returns the identification of, and means of communication with, person(s) and
      * organization(s) associated with the process step.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return means of communication with person(s) and organization(s) associated with the process step.
      */
     @Override
     @XmlElement(name = "processor")
-    public Collection<ResponsibleParty> getProcessors() {
-        return processors = nonNullCollection(processors, ResponsibleParty.class);
+    public Collection<Responsibility> getProcessors() {
+        return processors = nonNullCollection(processors, Responsibility.class);
     }
 
     /**
      * Identification of, and means of communication with, person(s) and
      * organization(s) associated with the process step.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new processors.
      */
-    public void setProcessors(final Collection<? extends ResponsibleParty> newValues) {
-        processors = writeCollection(newValues, processors, ResponsibleParty.class);
+    public void setProcessors(final Collection<? extends Responsibility> newValues) {
+        processors = writeCollection(newValues, processors, Responsibility.class);
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
index 960b846..904b98c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/package-info.java
@@ -80,7 +80,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Citation.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
+    @XmlJavaTypeAdapter(CI_Responsibility.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_Real.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/AttributeTypeAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/AttributeTypeAdapter.java
deleted file mode 100644
index be02d95..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/AttributeTypeAdapter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.metadata.iso.maintenance;
-
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-import org.opengis.feature.type.AttributeType;
-import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
-
-
-/**
- * For (un)marshalling deprecated {@link AttributeType} as a character string,
- * as expected by ISO 19115-3:2016. This is a temporary bridge to be removed
- * after the GeoAPI interfaces has been upgraded to ISO 19115-1:2014 model.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   1.0
- * @module
- */
-final class AttributeTypeAdapter extends XmlAdapter<GO_CharacterString, AttributeType> {
-    /**
-     * Wrap the given value from {@link DefaultScopeDescription} to the elements
-     * defined by ISO 19115-3:2016 schema.
-     */
-    @Override
-    public AttributeType unmarshal(GO_CharacterString value) {
-        return new LegacyType(LegacyType.ADAPTER.unmarshal(value));
-    }
-
-    /**
-     * Unwrap the elements defined by ISO 19115-3:2016 schema to the value used by
-     * {@link DefaultScopeDescription}.
-     */
-    @Override
-    public GO_CharacterString marshal(AttributeType value) {
-        return LegacyType.ADAPTER.marshal(LegacyType.wrap(value));
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
index ed33580..ff26354 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultMaintenanceInformation.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.CitationDate;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.maintenance.MaintenanceFrequency;
 import org.opengis.metadata.maintenance.MaintenanceInformation;
 import org.opengis.metadata.maintenance.ScopeCode;
@@ -116,7 +116,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      * Identification of, and means of communicating with, person(s) and organization(s)
      * with responsibility for maintaining the resource.
      */
-    private Collection<ResponsibleParty> contacts;
+    private Collection<Responsibility> contacts;
 
     /**
      * Creates a an initially empty maintenance information.
@@ -151,7 +151,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
             userDefinedMaintenanceFrequency = object.getUserDefinedMaintenanceFrequency();
             maintenanceScopes               = copyCollection(object.getMaintenanceScopes(), Scope.class);
             maintenanceNotes                = copyCollection(object.getMaintenanceNotes(), InternationalString.class);
-            contacts                        = copyCollection(object.getContacts(), ResponsibleParty.class);
+            contacts                        = copyCollection(object.getContacts(), Responsibility.class);
         }
     }
 
@@ -467,34 +467,24 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      * Returns identification of, and means of communicating with,
      * person(s) and organization(s) with responsibility for maintaining the resource.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @return means of communicating with person(s) and organization(s) with responsibility
      *         for maintaining the resource.
      */
     @Override
     @XmlElement(name = "contact")
-    public Collection<ResponsibleParty> getContacts() {
-        return contacts = nonNullCollection(contacts, ResponsibleParty.class);
+    public Collection<Responsibility> getContacts() {
+        return contacts = nonNullCollection(contacts, Responsibility.class);
     }
 
     /**
      * Sets identification of, and means of communicating with,
      * person(s) and organization(s) with responsibility for maintaining the resource.
      *
-     * <div class="warning"><b>Upcoming API change — generalization</b><br>
-     * As of ISO 19115:2014, {@code ResponsibleParty} is replaced by the {@code Responsibility} parent interface.
-     * This change may be applied in GeoAPI 4.0.
-     * </div>
-     *
      * @param  newValues  the new identification of person(s) and organization(s)
      *                    with responsibility for maintaining the resource.
      */
-    public void setContacts(final Collection<? extends ResponsibleParty> newValues) {
-        contacts = writeCollection(newValues, contacts, ResponsibleParty.class);
+    public void setContacts(final Collection<? extends Responsibility> newValues) {
+        contacts = writeCollection(newValues, contacts, Responsibility.class);
     }
 
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
index f90927a..9cf6a72 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescription.java
@@ -34,10 +34,6 @@ import org.apache.sis.xml.Namespaces;
 
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
 
-// Branch-dependent imports
-import org.opengis.feature.type.AttributeType;
-import org.opengis.feature.type.FeatureType;
-
 
 /**
  * Description of the class of information covered by the information.
@@ -121,12 +117,12 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * The value, as one of the following types:
      *
      * <ul>
-     *   <li>{@code Set<FeatureType>}   for the {@code features} property</li>
-     *   <li>{@code Set<AttributeType>} for the {@code attributes} property</li>
-     *   <li>{@code Set<FeatureType>}   for the {@code featureInstances} property</li>
-     *   <li>{@code Set<AttributeType>} for the {@code attributeInstances} property</li>
-     *   <li>{@code String} for the {@code dataset} property</li>
-     *   <li>{@code String} for the {@code other} property</li>
+     *   <li>{@code Set<CharSequence>}   for the {@code features} property</li>
+     *   <li>{@code Set<CharSequence>}   for the {@code attributes} property</li>
+     *   <li>{@code Set<CharSequence>}   for the {@code featureInstances} property</li>
+     *   <li>{@code Set<CharSequence>}   for the {@code attributeInstances} property</li>
+     *   <li>{@code String}              for the {@code dataset} property</li>
+     *   <li>{@code InternationalString} for the {@code other} property</li>
      * </ul>
      */
     private Object value;
@@ -155,36 +151,27 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      *
      * @see #castOrCopy(ScopeDescription)
      */
-    @SuppressWarnings("unchecked")
     public DefaultScopeDescription(final ScopeDescription object) {
         super(object);
         if (object != null) {
             for (byte i=DATASET; i<=OTHER; i++) {
-                Object candidate;
+                Collection<? extends CharSequence> props = null;
+                Object value = null;
                 switch (i) {
-                    case DATASET:             candidate = object.getDataset();            break;
-                    case FEATURES:            candidate = object.getFeatures();           break;
-                    case ATTRIBUTES:          candidate = object.getAttributes();         break;
-                    case FEATURE_INSTANCES:   candidate = object.getFeatureInstances();   break;
-                    case ATTRIBUTE_INSTANCES: candidate = object.getAttributeInstances(); break;
-                    case OTHER:               candidate = object.getOther();              break;
+                    case DATASET:             value = object.getDataset();            break;
+                    case FEATURES:            props = object.getFeatures();           break;
+                    case ATTRIBUTES:          props = object.getAttributes();         break;
+                    case FEATURE_INSTANCES:   props = object.getFeatureInstances();   break;
+                    case ATTRIBUTE_INSTANCES: props = object.getAttributeInstances(); break;
+                    case OTHER:               value = object.getOther();              break;
                     default: throw new AssertionError(i);
                 }
-                if (candidate != null) {
-                    switch (i) {
-                        case ATTRIBUTES:
-                        case ATTRIBUTE_INSTANCES: {
-                            candidate = copySet((Collection<AttributeType>) candidate, AttributeType.class);
-                            break;
-                        }
-                        case FEATURES:
-                        case FEATURE_INSTANCES: {
-                            candidate = copySet((Collection<FeatureType>) candidate, FeatureType.class);
-                            break;
-                        }
-                    }
-                    value = candidate;
-                    property = i;
+                if (props != null) {
+                    value = copySet(props, CharSequence.class);
+                }
+                if (value != null) {
+                    this.value = value;
+                    this.property = i;
                     break;
                 }
             }
@@ -217,35 +204,33 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
     }
 
     /**
-     * Returns the given value casted to a {@code Set} of elements of the given type.
-     * It is caller responsibility to ensure that the cast is valid, as element type
-     * is verified only when assertions are enabled.
+     * Returns the given value casted to a {@code Set<CharSequence>}.
      */
     @SuppressWarnings("unchecked")
-    private static <E> Set<E> cast(final Object value, final Class<E> type) {
-        assert ((CheckedContainer<?>) value).getElementType() == type;
-        return (Set<E>) value;
+    private static Set<CharSequence> cast(final Object value) {
+        assert ((CheckedContainer<?>) value).getElementType() == CharSequence.class;
+        return (Set<CharSequence>) value;
     }
 
     /**
      * Returns the set of properties identified by the {@code code} argument,
      * or an unmodifiable empty set if another value is defined.
      */
-    private <E> Set<E> getProperty(final Class<E> type, final byte code) {
+    private Set<CharSequence> getProperty(final byte code) {
         final Object value = this.value;
         if (value != null) {
             if (property == code) {
-                return cast(value, type);
+                return cast(value);
             } else if (!(value instanceof Set) || !((Set<?>) value).isEmpty()) {
                 return Semaphores.query(Semaphores.NULL_COLLECTION)
-                       ? null : new ExcludedSet<E>(NAMES[code-1], NAMES[property-1]);
+                       ? null : new ExcludedSet<>(NAMES[code-1], NAMES[property-1]);
             }
         }
         /*
          * Unconditionally create a new set, because the
          * user may hold a reference to the previous one.
          */
-        final Set<E> c = nonNullSet(null, type);
+        final Set<CharSequence> c = nonNullSet(null, CharSequence.class);
         property = code;
         this.value = c;
         return c;
@@ -258,17 +243,17 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * @param newValue  the value to set.
      * @param code      the property which is going to be set.
      */
-    private <E> void setProperty(final Set<? extends E> newValue, final Class<E> type, final byte code) {
-        Set<E> c = null;
+    private void setProperty(final Set<? extends CharSequence> newValue, final byte code) {
+        Set<CharSequence> c = null;
         if (property == code) {
-            c = cast(value, type);
+            c = cast(value);
         } else if (isNullOrEmpty(newValue)) {
             return;
         } else {
             warningOnOverwrite(code);
             property = code;
         }
-        value = writeSet(newValue, c, type);
+        value = writeSet(newValue, c, CharSequence.class);
     }
 
     /**
@@ -332,16 +317,12 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @return feature types to which the information applies.
      */
     @Override
     @XmlElement(name = "features")
-    public Set<FeatureType> getFeatures() {
-        return getProperty(FeatureType.class, FEATURES);
+    public Set<CharSequence> getFeatures() {
+        return getProperty(FEATURES);
     }
 
     /**
@@ -351,14 +332,10 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @param  newValues  the new feature types.
      */
-    public void setFeatures(final Set<? extends FeatureType> newValues) {
-        setProperty(newValues, FeatureType.class, FEATURES);
+    public void setFeatures(final Set<? extends CharSequence> newValues) {
+        setProperty(newValues, FEATURES);
     }
 
     /**
@@ -374,16 +351,12 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @return attribute types to which the information applies.
      */
     @Override
     @XmlElement(name = "attributes")
-    public Set<AttributeType> getAttributes() {
-        return getProperty(AttributeType.class, ATTRIBUTES);
+    public Set<CharSequence> getAttributes() {
+        return getProperty(ATTRIBUTES);
     }
 
     /**
@@ -393,14 +366,10 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @param  newValues  the new attribute types.
      */
-    public void setAttributes(final Set<? extends AttributeType> newValues) {
-        setProperty(newValues, AttributeType.class, ATTRIBUTES);
+    public void setAttributes(final Set<? extends CharSequence> newValues) {
+        setProperty(newValues, ATTRIBUTES);
     }
 
     /**
@@ -416,16 +385,12 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @return feature instances to which the information applies.
      */
     @Override
     @XmlElement(name = "featureInstances")
-    public Set<FeatureType> getFeatureInstances() {
-        return getProperty(FeatureType.class, FEATURE_INSTANCES);
+    public Set<CharSequence> getFeatureInstances() {
+        return getProperty(FEATURE_INSTANCES);
     }
 
     /**
@@ -435,14 +400,10 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @param  newValues  the new feature instances.
      */
-    public void setFeatureInstances(final Set<? extends FeatureType> newValues) {
-        setProperty(newValues, FeatureType.class, FEATURE_INSTANCES);
+    public void setFeatureInstances(final Set<? extends CharSequence> newValues) {
+        setProperty(newValues, FEATURE_INSTANCES);
     }
 
     /**
@@ -458,16 +419,12 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * This method returns a modifiable collection only if no other property is set.
      * Otherwise, this method returns an unmodifiable empty collection.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @return attribute instances to which the information applies.
      */
     @Override
     @XmlElement(name = "attributeInstances")
-    public Set<AttributeType> getAttributeInstances() {
-        return getProperty(AttributeType.class, ATTRIBUTE_INSTANCES);
+    public Set<CharSequence> getAttributeInstances() {
+        return getProperty(ATTRIBUTE_INSTANCES);
     }
 
     /**
@@ -477,29 +434,21 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * If and only if the {@code newValue} is non-empty, then this method automatically
      * discards all other properties.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@code Set<CharSequence>} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-238">GEO-238</a> for more information.</div>
-     *
      * @param  newValues  the new attribute instances.
      */
-    public void setAttributeInstances(final Set<? extends AttributeType> newValues) {
-        setProperty(newValues, AttributeType.class, ATTRIBUTE_INSTANCES);
+    public void setAttributeInstances(final Set<? extends CharSequence> newValues) {
+        setProperty(newValues, ATTRIBUTE_INSTANCES);
     }
 
     /**
      * Returns the class of information that does not fall into the other categories to which the information applies.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@link InternationalString} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-221">GEO-221</a> for more information.</div>
-     *
      * @return class of information that does not fall into the other categories, or {@code null}.
      */
     @Override
     @XmlElement(name = "other")
-    public String getOther() {
-        return (property == OTHER) ? (String) value : null;
+    public InternationalString getOther() {
+        return (property == OTHER) ? (InternationalString) value : null;
     }
 
     /**
@@ -510,13 +459,9 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * If and only if the {@code newValue} is non-null, then this method automatically
      * discards all other properties.
      *
-     * <div class="warning"><b>Upcoming API change:</b>
-     * The type of this property may be changed to {@link InternationalString} for ISO 19115:2014 conformance.
-     * See <a href="http://jira.codehaus.org/browse/GEO-221">GEO-221</a> for more information.</div>
-     *
      * @param newValue Other class of information.
      */
-    public void setOther(final String newValue) {
+    public void setOther(final InternationalString newValue) {
         checkWritePermission();
         if (newValue != null || property == OTHER) {
             warningOnOverwrite(OTHER);
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/FeatureTypeAdapter.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/FeatureTypeAdapter.java
deleted file mode 100644
index a9f1b47..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/FeatureTypeAdapter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.metadata.iso.maintenance;
-
-import javax.xml.bind.annotation.adapters.XmlAdapter;
-import org.opengis.feature.type.FeatureType;
-import org.apache.sis.internal.jaxb.gco.GO_CharacterString;
-
-
-/**
- * For (un)marshalling deprecated {@link FeatureType} as a character string,
- * as expected by ISO 19115-3:2016. This is a temporary bridge to be removed
- * after the GeoAPI interfaces has been upgraded to ISO 19115-1:2014 model.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   1.0
- * @module
- */
-final class FeatureTypeAdapter extends XmlAdapter<GO_CharacterString, FeatureType> {
-    /**
-     * Wrap the given value from {@link DefaultScopeDescription} to the elements
-     * defined by ISO 19115-3:2016 schema.
-     */
-    @Override
-    public FeatureType unmarshal(GO_CharacterString value) {
-        return new LegacyType(LegacyType.ADAPTER.unmarshal(value));
-    }
-
-    /**
-     * Unwrap the elements defined by ISO 19115-3:2016 schema to the value used by
-     * {@link DefaultScopeDescription}.
-     */
-    @Override
-    public GO_CharacterString marshal(FeatureType value) {
-        return LegacyType.ADAPTER.marshal(LegacyType.wrap(value));
-    }
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/LegacyType.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/LegacyType.java
deleted file mode 100644
index d6f24c3..0000000
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/LegacyType.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.metadata.iso.maintenance;
-
-import org.opengis.feature.type.FeatureType;
-import org.opengis.feature.type.AttributeType;
-import org.apache.sis.internal.jaxb.gco.CharSequenceAdapter;
-
-
-/**
- * Bridges between deprecated {@link FeatureType} / {@link AttributeType} and {@link CharSequence}.
- * {@code FeatureType} and {@code AttributeType} were used in ISO 19115:2003, but have been replaced
- * by {@link CharSequence} in ISO 19115:2014. The corresponding GeoAPI 3.0 interfaces are empty since
- * they were placeholder for future work. We use this {@code LegacyType} as a temporary bridge, to be
- * removed with GeoAPI 4.0.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
- * @since   1.0
- * @module
- */
-final class LegacyType implements FeatureType, AttributeType, CharSequence {
-    /**
-     * The adapter doing most of the actual work of converting {@code FeatureType} or {@code AttributeType}
-     * to {@code <gco:CharacterSequence>} elements.
-     */
-    static final CharSequenceAdapter ADAPTER = new CharSequenceAdapter();
-
-    /**
-     * The value to wrap as a {@code FeatureType} or {@code AttributeType}.
-     */
-    private final CharSequence value;
-
-    /**
-     * Creates a new type for the given value, which must be non-null.
-     */
-    LegacyType(final CharSequence value) {
-        this.value = value;
-    }
-
-    /**
-     * Wraps the given {@code FeatureType} or {@code AttributeType} as a {@code CharSequence}.
-     */
-    static CharSequence wrap(final Object value) {
-        return (value == null || value instanceof CharSequence)
-                ? (CharSequence) value : new LegacyType(value.toString());
-    }
-
-    /**
-     * Delegates to the value given at construction time.
-     */
-    @Override public int          length()                        {return value.length();}
-    @Override public char         charAt(int index)               {return value.charAt(index);}
-    @Override public CharSequence subSequence(int start, int end) {return value.subSequence(start, end);}
-    @Override public String       toString()                      {return value.toString();}
-}
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
index 4955e86..57e9225 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/package-info.java
@@ -77,7 +77,7 @@
 @XmlAccessorType(XmlAccessType.NONE)
 @XmlJavaTypeAdapters({
     @XmlJavaTypeAdapter(CI_Date.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
+    @XmlJavaTypeAdapter(CI_Responsibility.class),
     @XmlJavaTypeAdapter(EX_Extent.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
     @XmlJavaTypeAdapter(MD_MaintenanceFrequencyCode.class),
@@ -87,8 +87,6 @@
     @XmlJavaTypeAdapter(TM_PeriodDuration.class),
 
     // Java types, primitive types and basic OGC types handling
-    @XmlJavaTypeAdapter(FeatureTypeAdapter.class),
-    @XmlJavaTypeAdapter(AttributeTypeAdapter.class),
     @XmlJavaTypeAdapter(StringAdapter.class),
     @XmlJavaTypeAdapter(CharSequenceAdapter.class),
     @XmlJavaTypeAdapter(InternationalStringAdapter.class)
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java
index 47a1237..f919127 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/package-info.java
@@ -103,13 +103,12 @@
     @XmlJavaTypeAdapter(CI_Citation.class),
     @XmlJavaTypeAdapter(CI_Date.class),
     @XmlJavaTypeAdapter(CI_OnlineResource.class),
-    @XmlJavaTypeAdapter(CI_ResponsibleParty.class),
+    @XmlJavaTypeAdapter(CI_Responsibility.class),
     @XmlJavaTypeAdapter(DQ_DataQuality.class),
     @XmlJavaTypeAdapter(GO_DateTime.class),
     @XmlJavaTypeAdapter(GO_Integer.class),
     @XmlJavaTypeAdapter(LI_Lineage.class),
     @XmlJavaTypeAdapter(MD_ApplicationSchemaInformation.class),
-    @XmlJavaTypeAdapter(MD_CharacterSetLegacy.class),
     @XmlJavaTypeAdapter(MD_Constraints.class),
     @XmlJavaTypeAdapter(MD_ContentInformation.class),
     @XmlJavaTypeAdapter(MD_DatatypeCode.class),
@@ -126,6 +125,7 @@
     @XmlJavaTypeAdapter(MI_AcquisitionInformation.class),
     @XmlJavaTypeAdapter(PT_Locale.class),
     @XmlJavaTypeAdapter(RS_ReferenceSystem.class),
+    @XmlJavaTypeAdapter(LegacyCharacterSet.class),
 
     // Java types, primitive types and basic OGC types handling
     @XmlJavaTypeAdapter(StringAdapter.class),
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java
index 237466c..4dd2d9b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultDataQuality.java
@@ -23,9 +23,10 @@ import javax.xml.bind.annotation.XmlRootElement;
 import org.opengis.metadata.lineage.Lineage;
 import org.opengis.metadata.quality.DataQuality;
 import org.opengis.metadata.quality.Element;
-import org.opengis.metadata.quality.Scope;
+import org.opengis.metadata.maintenance.Scope;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.apache.sis.metadata.iso.ISOMetadata;
+import org.apache.sis.metadata.iso.maintenance.DefaultScope;
 import org.apache.sis.internal.jaxb.FilterByVersion;
 import org.apache.sis.internal.jaxb.LegacyNamespaces;
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java
index 03636a3..bca1af2 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/internal/jaxb/cat/EnumMarshallingTest.java
@@ -17,6 +17,7 @@
 package org.apache.sis.internal.jaxb.cat;
 
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.Collection;
 import javax.xml.bind.JAXBException;
 import org.opengis.metadata.identification.TopicCategory;
@@ -71,6 +72,7 @@ public final strictfp class EnumMarshallingTest extends XMLTestCase {
          * Unmarshall the above XML and verify that we find all the topic categories.
          */
         final Collection<TopicCategory> unmarshalled = unmarshal(DefaultDataIdentification.class, expected).getTopicCategories();
+        assertInstanceOf("topicCategory", EnumSet.class, unmarshalled);
         assertSetEquals(topics, unmarshalled);
     }
 }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
index 63a6ba3..7198c2e 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyAccessorTest.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Locale;
 import java.util.Date;
+import java.nio.charset.Charset;
 
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
@@ -31,7 +32,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.content.AttributeGroup;
@@ -42,7 +43,6 @@ import org.opengis.metadata.maintenance.MaintenanceInformation;
 import org.opengis.metadata.spatial.SpatialRepresentationType;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.datum.GeodeticDatum;
@@ -177,10 +177,10 @@ public final strictfp class PropertyAccessorTest extends TestCase {
             Citation.class, "getEdition",                 "edition",                 "edition",               "Edition",                    InternationalString.class,
             Citation.class, "getEditionDate",             "editionDate",             "editionDate",           "Edition date",               Date.class,
             Citation.class, "getIdentifiers",             "identifiers",             "identifier",            "Identifiers",                Identifier[].class,
-            Citation.class, "getCitedResponsibleParties", "citedResponsibleParties", "citedResponsibleParty", "Cited responsible parties",  ResponsibleParty[].class,
+            Citation.class, "getCitedResponsibleParties", "citedResponsibleParties", "citedResponsibleParty", "Cited responsible parties",  Responsibility[].class,
             Citation.class, "getPresentationForms",       "presentationForms",       "presentationForm",      "Presentation forms",         PresentationForm[].class,
             Citation.class, "getSeries",                  "series",                  "series",                "Series",                     Series.class,
-            Citation.class, "getOtherCitationDetails",    "otherCitationDetails",    "otherCitationDetails",  "Other citation details",     InternationalString.class,
+            Citation.class, "getOtherCitationDetails",    "otherCitationDetails",    "otherCitationDetails",  "Other citation details",     InternationalString[].class,
 //          Citation.class, "getCollectiveTitle",         "collectiveTitle",         "collectiveTitle",       "Collective title",           InternationalString.class,   -- deprecated as of ISO 19115:2014
             Citation.class, "getISBN",                    "ISBN",                    "ISBN",                  "ISBN",                       String.class,
             Citation.class, "getISSN",                    "ISSN",                    "ISSN",                  "ISSN",                       String.class,
@@ -205,9 +205,9 @@ public final strictfp class PropertyAccessorTest extends TestCase {
             Identification.class, "getCitation",                   "citation",                   "citation",                  "Citation",                     Citation.class,
             Identification.class, "getAbstract",                   "abstract",                   "abstract",                  "Abstract",                     InternationalString.class,
             Identification.class, "getPurpose",                    "purpose",                    "purpose",                   "Purpose",                      InternationalString.class,
-            Identification.class, "getCredits",                    "credits",                    "credit",                    "Credits",                      String[].class,
+            Identification.class, "getCredits",                    "credits",                    "credit",                    "Credits",                      InternationalString[].class,
             Identification.class, "getStatus",                     "status",                     "status",                    "Status",                       Progress[].class,
-            Identification.class, "getPointOfContacts",            "pointOfContacts",            "pointOfContact",            "Point of contacts",            ResponsibleParty[].class,
+            Identification.class, "getPointOfContacts",            "pointOfContacts",            "pointOfContact",            "Point of contacts",            Responsibility[].class,
             Identification.class, "getSpatialRepresentationTypes", "spatialRepresentationTypes", "spatialRepresentationType", "Spatial representation types", SpatialRepresentationType[].class,
             Identification.class, "getSpatialResolutions",         "spatialResolutions",         "spatialResolution",         "Spatial resolutions",          Resolution[].class,
             Identification.class, "getTemporalResolutions",        "temporalResolutions",        "temporalResolution",        "Temporal resolutions",         Duration[].class,
@@ -223,7 +223,7 @@ public final strictfp class PropertyAccessorTest extends TestCase {
             Identification.class, "getResourceConstraints",        "resourceConstraints",        "resourceConstraints",       "Resource constraints",         Constraints[].class,
             Identification.class, "getAssociatedResources",        "associatedResources",        "associatedResource",        "Associated resources",         AssociatedResource[].class,
         DataIdentification.class, "getLanguages",                  "languages",                  "language",                  "Languages",                    Locale[].class,
-        DataIdentification.class, "getCharacterSets",              "characterSets",              "characterSet",              "Character sets",               CharacterSet[].class,
+        DataIdentification.class, "getCharacterSets",              "characterSets",              "characterSet",              "Character sets",               Charset[].class,
         DataIdentification.class, "getEnvironmentDescription",     "environmentDescription",     "environmentDescription",    "Environment description",      InternationalString.class,
         DataIdentification.class, "getSupplementalInformation",    "supplementalInformation",    "supplementalInformation",   "Supplemental information",     InternationalString.class);
     }
@@ -242,10 +242,10 @@ public final strictfp class PropertyAccessorTest extends TestCase {
         //……Declaring type……………………………Method……………………………………………JavaBeans……………………………UML identifier………………Sentence…………………………………Type…………………………………………………………
             GeographicCRS.class,    "getCoordinateSystem", "coordinateSystem", "coordinateSystem", "Coordinate system",  EllipsoidalCS.class,       // Covariant return type
             GeodeticCRS.class,      "getDatum",            "datum",            "datum",            "Datum",              GeodeticDatum.class,       // Covariant return type
-            IdentifiedObject.class, "getName",             "name",             "name",             "Name",               ReferenceIdentifier.class,
+            IdentifiedObject.class, "getName",             "name",             "name",             "Name",               Identifier.class,
             IdentifiedObject.class, "getAlias",            "alias",            "alias",            "Alias",              GenericName[].class,
             ReferenceSystem.class,  "getDomainOfValidity", "domainOfValidity", "domainOfValidity", "Domain of validity", Extent.class,
-            IdentifiedObject.class, "getIdentifiers",      "identifiers",      "identifier",       "Identifiers",        ReferenceIdentifier[].class,
+            IdentifiedObject.class, "getIdentifiers",      "identifiers",      "identifier",       "Identifiers",        Identifier[].class,
             IdentifiedObject.class, "getRemarks",          "remarks",          "remarks",          "Remarks",            InternationalString.class,
             ReferenceSystem.class,  "getScope",            "scope",            "SC_CRS.scope",     "Scope",              InternationalString.class);
     }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java
index 5c96d80..4eaae22 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/PropertyInformationTest.java
@@ -18,8 +18,8 @@ package org.apache.sis.metadata;
 
 import java.util.Locale;
 import org.opengis.util.InternationalString;
+import org.opengis.annotation.Obligation;
 import org.opengis.metadata.Datatype;
-import org.opengis.metadata.Obligation;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.PresentationForm;
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
index a903c83..a4703d4 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeChildrenTest.java
@@ -21,6 +21,7 @@ import java.util.Random;
 import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Collections;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.PresentationForm;
@@ -69,7 +70,7 @@ public final strictfp class TreeNodeChildrenTest extends TestCase {
     static DefaultCitation metadataWithoutCollections() {
         final DefaultCitation citation = new DefaultCitation("Some title");
         citation.setEdition(new SimpleInternationalString("Some edition"));
-        citation.setOtherCitationDetails(new SimpleInternationalString("Some other details"));
+        citation.setOtherCitationDetails(Collections.singleton(new SimpleInternationalString("Some other details")));
         return citation;
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
index 79db6a9..7163237 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeNodeTest.java
@@ -22,14 +22,14 @@ import org.opengis.metadata.citation.Address;
 import org.opengis.metadata.citation.Contact;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.Party;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.PresentationForm;
 import org.opengis.metadata.citation.Role;
 import org.opengis.util.InternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultAddress;
 import org.apache.sis.metadata.iso.citation.DefaultContact;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.metadata.iso.citation.DefaultOrganisation;
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
 import org.apache.sis.metadata.iso.citation.AbstractParty;
@@ -84,8 +84,7 @@ public final strictfp class TreeNodeTest extends TestCase {
     static DefaultCitation metadataWithHierarchy() {
         final DefaultCitation citation = TreeNodeChildrenTest.metadataWithMultiOccurrences();
         AbstractParty party = new DefaultOrganisation("Some organisation", null, null, null);
-        DefaultResponsibleParty responsibility = new DefaultResponsibleParty(Role.DISTRIBUTOR);
-        responsibility.setParties(singleton(party));
+        DefaultResponsibility responsibility = new DefaultResponsibility(Role.DISTRIBUTOR, null, party);
         assertTrue(citation.getCitedResponsibleParties().add(responsibility));
 
         // Add a second responsible party with deeper hierarchy.
@@ -94,8 +93,7 @@ public final strictfp class TreeNodeTest extends TestCase {
         address.setElectronicMailAddresses(singleton("Some email"));
         contact.setAddresses(singleton(address));
         party = new DefaultIndividual("Some person of contact", null, contact);
-        responsibility = new DefaultResponsibleParty(Role.POINT_OF_CONTACT);
-        responsibility.setParties(singleton(party));
+        responsibility = new DefaultResponsibility(Role.POINT_OF_CONTACT, null, party);
         assertTrue(citation.getCitedResponsibleParties().add(responsibility));
         return citation;
     }
@@ -179,7 +177,7 @@ public final strictfp class TreeNodeTest extends TestCase {
      *
      * <p>If {@link #valuePolicy} is {@link ValueExistencePolicy#COMPACT}, then this method removes the elements at
      * indices 0, 6 and 10 (if {@code offset} = 0) or 1, 7 and 11 (if {@code offset} = 1) from the {@code expected}
-     * array before to perform the comparison (note: actual indices vary according branches).</p>
+     * array before to perform the comparison.</p>
      *
      * @param  offset    0 if compact mode excludes the parent, or 1 if compact mode exclude the first child.
      * @param  column    the column from which to get a value.
@@ -190,8 +188,8 @@ public final strictfp class TreeNodeTest extends TestCase {
     private void assertCitationContentEquals(final int offset, final TableColumn<?> column, final Object... expected) {
         if (valuePolicy == ValueExistencePolicy.COMPACT) {
             assertEquals(19, expected.length);
-            System.arraycopy(expected, 11+offset, expected, 10+offset,  8-offset);    // Compact the "Individual" element.
-            System.arraycopy(expected,  7+offset, expected,  6+offset, 11-offset);    // Compact the "Organisation" element.
+            System.arraycopy(expected, 12+offset, expected, 11+offset,  7-offset);    // Compact the "Individual" element.
+            System.arraycopy(expected,  8+offset, expected,  7+offset, 10-offset);    // Compact the "Organisation" element.
             System.arraycopy(expected,  1+offset, expected,    offset, 16-offset);    // Compact the "Title" element.
             Arrays.fill(expected, 16, 19, null);
         }
@@ -211,16 +209,16 @@ public final strictfp class TreeNodeTest extends TestCase {
               "Alternate title (2 of 2)",
               "Edition",
               "Cited responsible party (1 of 2)",
-                "Organisation",
-                  "Name",                               // In COMPACT mode, this value is associated to "Organisation" node.
                 "Role",
+                "Organisation",                         // A Party subtype
+                  "Name",                               // In COMPACT mode, this value is associated to "Organisation" node.
               "Cited responsible party (2 of 2)",
-                "Individual",
+                "Role",
+                "Individual",                           // A Party subtype
                   "Name",                               // In COMPACT mode, this value is associated to "Individual" node.
                   "Contact info",
                     "Address",
                       "Electronic mail address",
-                "Role",
               "Presentation form (1 of 2)",
               "Presentation form (2 of 2)",
               "Other citation details");
@@ -242,16 +240,16 @@ public final strictfp class TreeNodeTest extends TestCase {
               "alternateTitle",
               "edition",
               "citedResponsibleParty",
+                "role",
                 "party",
                   "name",                               // In COMPACT mode, this value is associated to "party" node.
-                "role",
               "citedResponsibleParty",
+                "role",
                 "party",
                   "name",                               // In COMPACT mode, this value is associated to "party" node.
                   "contactInfo",
                     "address",
                       "electronicMailAddress",
-                "role",
               "presentationForm",
               "presentationForm",
               "otherCitationDetails");
@@ -265,7 +263,6 @@ public final strictfp class TreeNodeTest extends TestCase {
     public void testGetIndex() {
         final Integer ZERO = 0;
         final Integer ONE  = 1;
-        skipCountCheck = true;                              // Because of the null value at the end of following array.
         assertCitationContentEquals(1, TableColumn.INDEX,
             null,           // CI_Citation
               null,         // title
@@ -273,19 +270,19 @@ public final strictfp class TreeNodeTest extends TestCase {
               ONE,          // alternateTitle
               null,         // edition
               ZERO,         // citedResponsibleParty
+                null,       // role
                 ZERO,       // party (organisation)
                   null,     // name                         — in COMPACT mode, this value is associated to "party" node.
-                null,       // role
               ONE,          // citedResponsibleParty
+                null,       // role
                 ZERO,       // party (individual)
                   null,     // name                         — in COMPACT mode, this value is associated to "party" node.
                   ZERO,     // contactInfo
                     ZERO,   // address
                       ZERO, // electronicMailAddress
-                null,       // role
               ZERO,         // presentationForm
               ONE,          // presentationForm
-              null);        // otherCitationDetails
+              ZERO);        // otherCitationDetails
     }
 
     /**
@@ -300,17 +297,17 @@ public final strictfp class TreeNodeTest extends TestCase {
               InternationalString.class,
               InternationalString.class,
               InternationalString.class,
-              ResponsibleParty.class,
+              Responsibility.class,
+                Role.class,
                 Party.class,                            // In COMPACT mode, value with be the one of "name" node instead.
                   InternationalString.class,            // Name
+              Responsibility.class,
                 Role.class,
-              ResponsibleParty.class,
                 Party.class,                            // In COMPACT mode, value with be the one of "name" node instead.
                   InternationalString.class,            // Name
                   Contact.class,
                     Address.class,
                       String.class,
-                Role.class,
               PresentationForm.class,
               PresentationForm.class,
               InternationalString.class);
@@ -329,16 +326,16 @@ public final strictfp class TreeNodeTest extends TestCase {
               "Second alternate title",
               "Some edition",
               null,                             // ResponsibleParty
+                Role.DISTRIBUTOR,
                 null,                           // Party (organisation)
                   "Some organisation",
-                Role.DISTRIBUTOR,
               null,                             // ResponsibleParty
+                Role.POINT_OF_CONTACT,
                 null,                           // Party (individual)
                   "Some person of contact",
                   null,                         // Contact
                     null,                       // Address
                       "Some email",
-                Role.POINT_OF_CONTACT,
               PresentationForm.MAP_DIGITAL,
               PresentationForm.MAP_HARDCOPY,
               "Some other details");
@@ -384,12 +381,6 @@ public final strictfp class TreeNodeTest extends TestCase {
     }
 
     /**
-     * For disabling the check of child nodes count.
-     * This hack is specific to the branch using GeoAPI 3.0 (not needed on the branch using GeoAPI 4.0).
-     */
-    private boolean skipCountCheck;
-
-    /**
      * Compares the result of the given getter method invoked on the given node, then invoked
      * on all children of that given. In the particular case of the {@link TableColumn#NAME},
      * international strings are replaced by unlocalized strings before comparisons.
@@ -407,7 +398,6 @@ public final strictfp class TreeNodeTest extends TestCase {
         if (valuePolicy == ValueExistencePolicy.COMPACT) {
             while (expected[count-1] == null) count--;
         }
-        if (skipCountCheck) return;
         assertEquals("Missing values in the tested metadata.", count,
                 assertColumnContentEquals(node, column, expected, 0));
     }
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
index 5c33496..2c77b1c 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableFormatTest.java
@@ -26,7 +26,7 @@ import org.apache.sis.metadata.iso.content.DefaultBand;
 import org.apache.sis.metadata.iso.content.DefaultImageDescription;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultCitationTest;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.metadata.iso.content.DefaultAttributeGroup;
 import org.apache.sis.metadata.iso.identification.DefaultDataIdentification;
 import org.apache.sis.metadata.iso.lineage.DefaultProcessing;
@@ -91,9 +91,10 @@ public final strictfp class TreeTableFormatTest extends TestCase {
             "  │   │   └─Alternate title…………………………… ISBN\n" +
             "  │   └─Code space…………………………………………………… ISBN\n"+
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Individual…………………………………………………… Testsuya Toyoda\n" +
-            "  │   └─Role…………………………………………………………………… Author\n" +
+            "  │   ├─Role…………………………………………………………………… Author\n" +
+            "  │   └─Individual…………………………………………………… Testsuya Toyoda\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
+            "  │   ├─Role…………………………………………………………………… Editor\n" +
             "  │   ├─Extent……………………………………………………………… World\n" +
             "  │   │   └─Geographic element\n" +
             "  │   │       ├─West bound longitude…… 180°W\n" +
@@ -101,8 +102,7 @@ public final strictfp class TreeTableFormatTest extends TestCase {
             "  │   │       ├─South bound latitude…… 90°S\n" +
             "  │   │       ├─North bound latitude…… 90°N\n" +
             "  │   │       └─Extent type code……………… true\n" +
-            "  │   ├─Organisation……………………………………………… Kōdansha\n" +
-            "  │   └─Role…………………………………………………………………… Editor\n" +
+            "  │   └─Organisation……………………………………………… Kōdansha\n" +
             "  ├─Presentation form (1 of 2)…………………… Document digital\n" +
             "  ├─Presentation form (2 of 2)…………………… Document hardcopy\n" +
             "  └─ISBN……………………………………………………………………………… 9782505004509\n", text);
@@ -118,7 +118,7 @@ public final strictfp class TreeTableFormatTest extends TestCase {
         final DefaultCitation untitled = new DefaultCitation();
         titled  .setPresentationForms(singleton(PresentationForm.DOCUMENT_HARDCOPY));
         coded   .setPresentationForms(singleton(PresentationForm.IMAGE_HARDCOPY));
-        untitled.setCitedResponsibleParties(singleton(new DefaultResponsibleParty(Role.AUTHOR)));
+        untitled.setCitedResponsibleParties(singleton(new DefaultResponsibility(Role.AUTHOR, null, null)));
         final DefaultProcessing processing = new DefaultProcessing();
         processing.setDocumentations(asList(titled, coded, untitled));
         final String text = format.format(processing.asTreeTable());
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
index d177a81..9d0c6e9 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TreeTableViewTest.java
@@ -59,14 +59,14 @@ public final strictfp class TreeTableViewTest extends TestCase {
             "  ├─Alternate title (2 of 2)…………………………………………… Second alternate title\n" +
             "  ├─Edition………………………………………………………………………………………… Some edition\n" +
             "  ├─Cited responsible party (1 of 2)\n" +
-            "  │   ├─Organisation………………………………………………………………… Some organisation\n" +
-            "  │   └─Role……………………………………………………………………………………… Distributor\n" +
+            "  │   ├─Role……………………………………………………………………………………… Distributor\n" +
+            "  │   └─Organisation………………………………………………………………… Some organisation\n" +
             "  ├─Cited responsible party (2 of 2)\n" +
-            "  │   ├─Individual……………………………………………………………………… Some person of contact\n" +
-            "  │   │   └─Contact info\n" +
-            "  │   │       └─Address\n" +
-            "  │   │           └─Electronic mail address…… Some email\n" +
-            "  │   └─Role……………………………………………………………………………………… Point of contact\n" +
+            "  │   ├─Role……………………………………………………………………………………… Point of contact\n" +
+            "  │   └─Individual……………………………………………………………………… Some person of contact\n" +
+            "  │       └─Contact info\n" +
+            "  │           └─Address\n" +
+            "  │               └─Electronic mail address…… Some email\n" +
             "  ├─Presentation form (1 of 2)……………………………………… Map digital\n" +
             "  ├─Presentation form (2 of 2)……………………………………… Map hardcopy\n" +
             "  └─Other citation details………………………………………………… Some other details\n";
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java
index ac76716..3614969 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/TypeMapTest.java
@@ -24,7 +24,7 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.extent.GeographicExtent;
 import org.opengis.metadata.extent.GeographicDescription;
@@ -70,7 +70,7 @@ public final strictfp class TypeMapTest extends TestCase {
             new SimpleEntry<>("edition",               InternationalString.class),
             new SimpleEntry<>("editionDate",           Date.class),
             new SimpleEntry<>("identifier",            Identifier.class),
-            new SimpleEntry<>("citedResponsibleParty", ResponsibleParty.class),
+            new SimpleEntry<>("citedResponsibleParty", Responsibility.class),
             new SimpleEntry<>("presentationForm",      PresentationForm.class),
             new SimpleEntry<>("series",                Series.class),
             new SimpleEntry<>("otherCitationDetails",  InternationalString.class),
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
index a7c6eb6..129c75c 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/ValueMapTest.java
@@ -24,7 +24,7 @@ import org.apache.sis.xml.NilReason;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultIndividual;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
+import org.apache.sis.metadata.iso.citation.DefaultResponsibility;
 import org.apache.sis.test.DependsOnMethod;
 import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
@@ -68,7 +68,7 @@ public final strictfp class ValueMapTest extends TestCase {
     /**
      * The author of the metadata instance created by {@link #createCitation()}.
      */
-    private DefaultResponsibleParty author;
+    private DefaultResponsibility author;
 
     /**
      * Creates the metadata instance to be used for testing purpose.
@@ -91,7 +91,7 @@ public final strictfp class ValueMapTest extends TestCase {
      */
     private Map<String,Object> createCitation() {
         title    = new SimpleInternationalString("Undercurrent");
-        author   = new DefaultResponsibleParty();
+        author   = new DefaultResponsibility();
         citation = new DefaultCitation(title);
         author.setParties(singleton(new DefaultIndividual("Testsuya Toyoda", null, null)));
         citation.setCitedResponsibleParties(singleton(author));
@@ -172,6 +172,7 @@ public final strictfp class ValueMapTest extends TestCase {
             new SimpleEntry<>("identifiers",             citation.getIdentifiers()),
             new SimpleEntry<>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<>("presentationForms",       emptySet()),
+            new SimpleEntry<>("otherCitationDetails",    emptyList()),
             new SimpleEntry<>("ISBN",                    "9782505004509"),
             new SimpleEntry<>("onlineResources",         emptyList()),
             new SimpleEntry<>("graphics",                emptyList())
@@ -202,6 +203,7 @@ public final strictfp class ValueMapTest extends TestCase {
             new SimpleEntry<>("identifiers",             citation.getIdentifiers()),
             new SimpleEntry<>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<>("presentationForms",       emptySet()),
+            new SimpleEntry<>("otherCitationDetails",    emptyList()),
             new SimpleEntry<>("ISBN",                    "9782505004509"),
             new SimpleEntry<>("onlineResources",         emptyList()),
             new SimpleEntry<>("graphics",                emptyList())
@@ -232,7 +234,7 @@ public final strictfp class ValueMapTest extends TestCase {
             new SimpleEntry<>("citedResponsibleParties", singletonList(author)),
             new SimpleEntry<>("presentationForms",       emptySet()),
             new SimpleEntry<>("series",                  null),
-            new SimpleEntry<>("otherCitationDetails",    null),
+            new SimpleEntry<>("otherCitationDetails",    emptyList()),
 //          new SimpleEntry<>("collectiveTitle",         null),  -- deprecated as of ISO 19115:2014.
             new SimpleEntry<>("ISBN",                    "9782505004509"),
             new SimpleEntry<>("ISSN",                    null),
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java
index 59eb7d1..0ffade4 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/CustomMetadataTest.java
@@ -23,12 +23,13 @@ import java.util.Locale;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Method;
 import java.lang.reflect.InvocationHandler;
+import java.nio.charset.Charset;
 import javax.xml.bind.JAXBException;
 import org.opengis.util.NameFactory;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.identification.*;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.constraint.Constraints;
 import org.opengis.metadata.distribution.Format;
 import org.opengis.metadata.extent.Extent;
@@ -122,12 +123,12 @@ public final strictfp class CustomMetadataTest extends XMLTestCase {
             @Override public Collection<Resolution>                getSpatialResolutions()         {return null;}
             @Override public Collection<Duration>                  getTemporalResolutions()        {return null;}
             @Override public Collection<Locale>                    getLanguages()                  {return null;}
-            @Override public Collection<CharacterSet>              getCharacterSets()              {return null;}
+            @Override public Collection<Charset>                   getCharacterSets()              {return null;}
             @Override public Collection<TopicCategory>             getTopicCategories()            {return null;}
             @Override public Collection<Extent>                    getExtents()                    {return null;}
-            @Override public Collection<String>                    getCredits()                    {return null;}
+            @Override public Collection<InternationalString>       getCredits()                    {return null;}
             @Override public Collection<Progress>                  getStatus()                     {return null;}
-            @Override public Collection<ResponsibleParty>          getPointOfContacts()            {return null;}
+            @Override public Collection<Responsibility>            getPointOfContacts()            {return null;}
             @Override public Collection<MaintenanceInformation>    getResourceMaintenances()       {return null;}
             @Override public Collection<BrowseGraphic>             getGraphicOverviews()           {return null;}
             @Override public Collection<Format>                    getResourceFormats()            {return null;}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/MarshallingTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/MarshallingTest.java
new file mode 100644
index 0000000..b30c809
--- /dev/null
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/MarshallingTest.java
@@ -0,0 +1,677 @@
+/*
+ * 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.metadata.iso;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.logging.LogRecord;
+import java.util.MissingResourceException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.io.StringWriter;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.JAXBException;
+import org.opengis.annotation.Obligation;
+import org.opengis.util.RecordType;
+import org.opengis.metadata.Datatype;
+import org.opengis.metadata.citation.*;
+import org.opengis.metadata.constraint.*;
+import org.opengis.metadata.content.*;
+import org.opengis.metadata.extent.*;
+import org.opengis.metadata.identification.*;
+import org.opengis.metadata.maintenance.*;
+import org.opengis.metadata.spatial.*;
+import org.opengis.geometry.primitive.Point;
+import org.apache.sis.metadata.iso.citation.*;
+import org.apache.sis.metadata.iso.constraint.*;
+import org.apache.sis.metadata.iso.content.*;
+import org.apache.sis.metadata.iso.distribution.*;
+import org.apache.sis.metadata.iso.extent.*;
+import org.apache.sis.metadata.iso.identification.*;
+import org.apache.sis.metadata.iso.maintenance.*;
+import org.apache.sis.metadata.iso.spatial.*;
+import org.apache.sis.util.iso.DefaultRecordSchema;
+import org.apache.sis.util.iso.SimpleInternationalString;
+import org.apache.sis.util.iso.DefaultInternationalString;
+import org.apache.sis.util.logging.WarningListener;
+import org.apache.sis.measure.Units;
+import org.apache.sis.xml.XML;
+import org.apache.sis.xml.NilReason;
+import org.apache.sis.xml.MarshallerPool;
+import org.apache.sis.xml.IdentifierSpace;
+import org.apache.sis.internal.jaxb.gcx.Anchor;
+import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
+import org.apache.sis.metadata.xml.TestUsingFile;
+import org.apache.sis.util.iso.Names;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+
+/**
+ * Simple test cases for marshalling a {@link DefaultMetadata} object to an XML file.
+ * This class is used to test the ISO 19115-3 metadata standard implementation.
+ *
+ * @author  Cullen Rombach (Image Matters)
+ * @author  Martin Desruisseaux (Geomatys)
+ * @version 1.0
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/SIS-400">SIS-400</a>
+ *
+ * @since 1.0
+ * @module
+ */
+public final class MarshallingTest extends TestUsingFile implements WarningListener<Object> {
+    /**
+     * The marshaller used to handle marshalling the created DefaultMetadata object.
+     */
+    private final Marshaller marshaller;
+
+    /**
+     * The pool from which the marshaller is pulled.
+     */
+    private final MarshallerPool pool;
+
+    /**
+     * The output to which the metadata object will be marshaled.
+     */
+    private final StringWriter output;
+
+    /**
+     * {@code true} if marshalling legacy XML instead than latest schema.
+     */
+    private boolean legacyXML;
+
+    /**
+     * Initializes a new test case.
+     *
+     * @throws JAXBException if an error occurred while preparing the marshaller.
+     */
+    @SuppressWarnings("ThisEscapedInObjectConstruction")
+    public MarshallingTest() throws JAXBException {
+        output     = new StringWriter();
+        pool       = getMarshallerPool();
+        marshaller = pool.acquireMarshaller();
+        marshaller.setProperty(XML.WARNING_LISTENER, this);
+    }
+
+    /**
+     * Creates a metadata object to marshal.
+     */
+    @SuppressWarnings("deprecation")
+    private static DefaultMetadata metadata() throws URISyntaxException {
+        /*
+         * Metadata
+         *   ├─Metadata identifier…… a-metadata-identifier
+         *   │   └─Code space………………… md.id.ns
+         *   ├─Parent metadata……………… A parent metadata
+         *   │   └─Identifier………………… a-parent-identifier
+         *   │       └─Code space……… pmd.id.ns
+         *   ├─Language (1 de 2)………… English
+         *   ├─Language (2 de 2)………… French (Canada)
+         *   ├─Character set…………………… ISO-8859-1
+         *   └─Metadata scope
+         *       ├─Resource scope……… Dataset
+         *       └─Name………………………………… Metadata for an imaginary data set
+         *
+         * Some code are indented for readability and more local variable scopes.
+         */
+        final DefaultMetadata md = new DefaultMetadata();
+        {
+            // Metadata identifier
+            final DefaultIdentifier id = new DefaultIdentifier("a-metadata-identifier");
+            id.setCodeSpace("md.id.ns");
+            md.setMetadataIdentifier(id);
+        }
+        // Languages — one language only, and one (country, language) tupple.
+        final Collection<Locale> languages = Arrays.asList(Locale.ENGLISH, Locale.CANADA_FRENCH);
+        md.setLanguages(languages);
+
+        // Character Sets (character encoding)
+        final Collection<Charset> charSets = Collections.singleton(StandardCharsets.ISO_8859_1);
+        md.setCharacterSets(charSets);
+        {
+            // Parent metadata
+            final DefaultCitation parent = new DefaultCitation("A parent metadata");
+            final DefaultIdentifier parentId = new DefaultIdentifier("a-parent-identifier");
+            parentId.setCodeSpace("pmd.id.ns");
+            parent.getIdentifiers().add(parentId);
+            md.setParentMetadata(parent);
+        }
+        // mdb:metadataScope (hierarchyLevel and hierarchyLevelName in legacy ISO 19115:2003 model)
+        md.getMetadataScopes().add(new DefaultMetadataScope(ScopeCode.DATASET, "Metadata for an imaginary data set"));
+        final DefaultOnlineResource onlineResource;
+        {
+            /*
+             * Contact information for the parties.
+             *
+             * Organisation………………………………………………………………… Plato Republic
+             *   ├─Contact info
+             *   │   ├─Phone (1 de 2)
+             *   │   │   ├─Number………………………………………………… 555-444-3333
+             *   │   │   └─Number type…………………………………… Voice
+             *   │   ├─Phone (2 de 2)
+             *   │   │   ├─Number………………………………………………… 555-555-5555
+             *   │   │   └─Number type…………………………………… Facsimile
+             *   │   ├─Address
+             *   │   │   ├─Delivery point…………………………… 123 Main Street
+             *   │   │   ├─City……………………………………………………… Metropolis city
+             *   │   │   ├─Administrative area……………… Utopia province
+             *   │   │   ├─Postal code…………………………………… A1A 2C2
+             *   │   │   ├─Country……………………………………………… Atlantis island
+             *   │   │   └─Electronic mail address…… test@example.com
+             *   │   ├─Online resource
+             *   │   │   ├─Linkage……………………………………………… http://example.com
+             *   │   │   ├─Protocol…………………………………………… Submarine HTTP
+             *   │   │   ├─Application profile……………… Imaginary work
+             *   │   │   ├─Name……………………………………………………… Timaeus & Critias
+             *   │   │   ├─Description…………………………………… A dialog between philosophers.
+             *   │   │   └─Function…………………………………………… Search
+             *   │   ├─Hours of service………………………………… Weekdays 9:00 AM - 5:00 PM
+             *   │   ├─Contact instructions……………………… Through thought
+             *   │   └─Contact type…………………………………………… Virtual
+             *   └─Individual…………………………………………………………… Socrates
+             *       └─Position name………………………………………… Philosopher
+             */
+            final DefaultContact contact = new DefaultContact();
+            contact.setPhones(Arrays.asList(new DefaultTelephone("555-444-3333", TelephoneType.VOICE),
+                                            new DefaultTelephone("555-555-5555", TelephoneType.FACSIMILE)));
+            {
+                {
+                    // Address information
+                    final DefaultAddress address = new DefaultAddress();
+                    address.setDeliveryPoints(Collections.singleton(new SimpleInternationalString("123 Main Street")));
+                    address.getElectronicMailAddresses().add("test@example.com");
+                    address.setCity(new SimpleInternationalString("Metropolis city"));
+                    address.setAdministrativeArea(new SimpleInternationalString("Utopia province"));
+                    address.setPostalCode("A1A 2C2");
+                    address.setCountry(new SimpleInternationalString("Atlantis island"));
+                    contact.getAddresses().add(address);
+                }
+                // Online resources
+                final DefaultInternationalString description = new DefaultInternationalString();
+                description.add(Locale.ENGLISH, "A dialog between philosophers.");
+                description.add(Locale.FRENCH,  "Un dialogue entre philosophes.");
+                onlineResource = new DefaultOnlineResource(new URI("http://example.com"));
+                onlineResource.setName(new SimpleInternationalString("Timaeus & Critias"));
+                onlineResource.setDescription(description);
+                onlineResource.setProtocol("Submarine HTTP");
+                onlineResource.setApplicationProfile("Imaginary work");
+                onlineResource.setFunction(OnLineFunction.SEARCH);
+                onlineResource.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "timaeus");    // For enabling references
+                contact.getOnlineResources().add(onlineResource);
+                contact.setHoursOfService(Collections.singleton(new SimpleInternationalString("Weekdays 9:00 AM - 5:00 PM")));
+                contact.setContactInstructions(new SimpleInternationalString("Through thought"));
+                contact.setContactType(new SimpleInternationalString("Virtual"));
+                contact.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "thought");           // For enabling references
+            }
+            // Create some individuals
+            final DefaultIndividual individual  = new DefaultIndividual("Socrates", "Philosopher", null);
+            final DefaultIndividual individual2 = new DefaultIndividual("Hermocrates", "Politician", contact);
+            final DefaultOrganisation org = new DefaultOrganisation("Plato Republic", null, individual, contact);
+            md.setContacts(Arrays.asList(new DefaultResponsibility(Role.POINT_OF_CONTACT, null, org),
+                                         new DefaultResponsibility(Role.POINT_OF_CONTACT, null, individual2)));
+        }
+        // Date info (date stamp in legacy ISO 19115:2003 model)
+        final Collection<CitationDate> dateInfo = Collections.singleton(new DefaultCitationDate(new Date(1260961229580L), DateType.CREATION));
+        md.setDateInfo(dateInfo);
+        {
+            // Metadata standard
+            final DefaultCitation standard = new DefaultCitation("ISO 19115-1");
+            standard.setEdition(new SimpleInternationalString("2014"));
+            md.getMetadataStandards().add(standard);
+        }
+        {
+            /*
+             * Spatial representation info : Georectified
+             *   ├─Number of dimensions………………………………………………… 2
+             *   ├─Axis dimension properties (1 de 2)…………… Row
+             *   │   ├─Dimension size……………………………………………………… 7 777
+             *   │   └─Resolution………………………………………………………………… 10
+             *   ├─Axis dimension properties (2 de 2)…………… Column
+             *   │   ├─Dimension size……………………………………………………… 2 233
+             *   │   └─Resolution………………………………………………………………… 5
+             *   ├─Cell geometry…………………………………………………………………… Area
+             *   ├─Transformation parameter availability…… false
+             *   ├─Check point availability……………………………………… false
+             *   └─Point in pixel………………………………………………………………… Upper right
+             */
+            final DefaultGeorectified georectified = new DefaultGeorectified();
+            georectified.setNumberOfDimensions(2);
+            final DefaultDimension rows = new DefaultDimension(DimensionNameType.ROW,    7777);
+            final DefaultDimension cols = new DefaultDimension(DimensionNameType.COLUMN, 2233);
+            rows.setResolution(10.0);
+            cols.setResolution( 5.0);
+            georectified.setAxisDimensionProperties(Arrays.asList(rows, cols));
+            georectified.setCellGeometry(CellGeometry.AREA);
+            georectified.setPointInPixel(PixelOrientation.UPPER_RIGHT);
+            georectified.getCornerPoints().add(NilReason.MISSING.createNilObject(Point.class));
+            md.getSpatialRepresentationInfo().add(georectified);
+        }
+        {
+            // Reference System Information
+            final ReferenceSystemMetadata refSystem = new ReferenceSystemMetadata();
+            final DefaultCitation cit = new DefaultCitation("Atlantis grid");
+            cit.setDates(dateInfo);
+            {
+                //  Responsibilities
+                final DefaultOrganisation org = new DefaultOrganisation();
+                org.setName(new SimpleInternationalString("Atlantis national mapping agency"));
+                cit.getCitedResponsibleParties().add(new DefaultResponsibility(Role.PUBLISHER, null, org));
+            }
+            // Identifier
+            final DefaultIdentifier id = new DefaultIdentifier("AG9000");
+            id.setAuthority(cit);
+            id.setCodeSpace("rs.id.ns");
+            id.setVersion("1.0");
+            id.setDescription(new SimpleInternationalString("An imaginary reference system."));
+            refSystem.setName(id);
+            md.getReferenceSystemInfo().add(refSystem);
+        }
+        {
+            /*
+             * Extended element information…… ExtendedElementName
+             *   ├─Parent entity………………………………… VirtualObject
+             *   ├─Definition………………………………………… An extended element not included in the standard.
+             *   ├─Obligation………………………………………… Conditional
+             *   ├─Condition…………………………………………… Presents in “Imaginary work” profile.
+             *   ├─Data type…………………………………………… Meta class
+             *   ├─Maximum occurrence…………………… 3
+             *   ├─Domain value…………………………………… Alpha, beta or gamma.
+             *   ├─Rule………………………………………………………… Element exists in cited resource.
+             *   └─Rationale…………………………………………… For testing extended elements.
+             */
+            final DefaultMetadataExtensionInformation extension = new DefaultMetadataExtensionInformation();
+            extension.setExtensionOnLineResource(onlineResource);
+            final DefaultExtendedElementInformation elementInfo = new DefaultExtendedElementInformation();
+            elementInfo.setName("ExtendedElementName");
+            elementInfo.setDefinition(new SimpleInternationalString("An extended element not included in the standard."));
+            elementInfo.setObligation(Obligation.CONDITIONAL);
+            elementInfo.setCondition(new SimpleInternationalString("Presents in “Imaginary work” profile."));
+            elementInfo.setDataType(Datatype.META_CLASS);
+            elementInfo.setMaximumOccurrence(3);
+            elementInfo.setDomainValue(new SimpleInternationalString("Alpha, beta or gamma."));
+            elementInfo.setShortName("ExtEltName");
+            elementInfo.setDomainCode(1234);
+            elementInfo.setParentEntity(Collections.singleton("VirtualObject"));
+            elementInfo.setRule(new SimpleInternationalString("Element exists in cited resource."));
+            elementInfo.setRationale(new SimpleInternationalString("For testing extended elements."));
+            elementInfo.getSources().add(NilReason.valueOf("other:test").createNilObject(Responsibility.class));
+            extension.getExtendedElementInformation().add(elementInfo);
+            md.getMetadataExtensionInfo().add(extension);
+        }
+        /*
+         * Data identification info
+         *   ├─Abstract………………… Méta-données pour une carte imaginaire.
+         *   └─Purpose…………………… For XML (un)marshalling tests.
+         */
+        final DefaultDataIdentification dataId = new DefaultDataIdentification();
+        {
+            final DefaultInternationalString description = new DefaultInternationalString();
+            description.add(Locale.ENGLISH, "Metadata for an imaginary map.");
+            description.add(Locale.FRENCH,  "Méta-données pour une carte imaginaire.");
+            dataId.setAbstract(description);
+            dataId.setPurpose(new SimpleInternationalString("For XML (un)marshalling tests."));
+        }
+        final Collection<Extent> extents;
+        {
+            /*
+             * Extent……………………………………………………………… Azores
+             *   ├─Geographic element
+             *   │   ├─West bound longitude…… 24°30′W
+             *   │   ├─East bound longitude…… 32°W
+             *   │   ├─South bound latitude…… 36°45′N
+             *   │   ├─North bound latitude…… 40°N
+             *   │   └─Extent type code……………… true
+             *   └─Temporal element
+             */
+            final DefaultExtent extent = new DefaultExtent();
+            extent.setDescription(new SimpleInternationalString("Azores"));
+            {
+                final DefaultGeographicBoundingBox bbox = new DefaultGeographicBoundingBox();
+                bbox.setInclusion(true);
+                bbox.setNorthBoundLatitude( 40.00);
+                bbox.setEastBoundLongitude(-32.00);
+                bbox.setSouthBoundLatitude( 36.75);
+                bbox.setWestBoundLongitude(-24.50);
+                extent.getGeographicElements().add(bbox);
+            }
+            final DefaultTemporalExtent temporal = new DefaultTemporalExtent();
+            extent.getTemporalElements().add(temporal);
+            extent.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "azores");     // For enabling references
+            extents = Collections.singleton(extent);
+            dataId.setExtents(extents);
+        }
+        final Collection<Constraints> resourceConstraints;
+        {
+            /*
+             * Constraints
+             *   ├─Use limitation…………………………………… Not for navigation.
+             *   ├─Constraint application scope
+             *   │   └─Level………………………………………………… Document
+             *   ├─Graphic
+             *   │   ├─File name……………………………………… ocean.png
+             *   │   ├─File description…………………… Somewhere in the Atlantic ocean
+             *   │   ├─File type……………………………………… PNG image
+             *   │   ├─Linkage
+             *   │   └─Image constraints
+             *   └─Releasability
+             *       └─Statement……………………………………… Public domain
+             */
+            final DefaultConstraints constraint = new DefaultConstraints();
+            final DefaultBrowseGraphic graphic = new DefaultBrowseGraphic(new URI("ocean.png"));
+            graphic.setFileDescription(new SimpleInternationalString("Somewhere in the Atlantic ocean"));
+            graphic.setFileType("PNG image");
+            graphic.getImageConstraints().add(new DefaultConstraints());
+            graphic.getLinkages().add(new DefaultOnlineResource());
+            constraint.getGraphics().add(graphic);
+            constraint.setUseLimitations(Collections.singleton(new SimpleInternationalString("Not for navigation.")));
+
+            // Releasability
+            final DefaultReleasability releasability = new DefaultReleasability();
+            releasability.setStatement(new SimpleInternationalString("Public domain"));
+            constraint.setReleasability(releasability);
+            constraint.setConstraintApplicationScope(new DefaultScope(ScopeCode.DOCUMENT));
+            constraint.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "public");         // For enabling references
+            resourceConstraints = Collections.singleton(constraint);
+            dataId.setResourceConstraints(resourceConstraints);
+        }
+        dataId.getSpatialRepresentationTypes().add(SpatialRepresentationType.GRID);
+        {
+            // Spatial resolution
+            final DefaultResolution resolution = new DefaultResolution();
+            resolution.setDistance(56777.0);
+            dataId.getSpatialResolutions().add(resolution);
+        }
+        dataId.setTopicCategories(Arrays.asList(TopicCategory.OCEANS, TopicCategory.SOCIETY));
+        dataId.getStatus().add(Progress.HISTORICAL_ARCHIVE);
+        /*
+         * Citation………………………………………………………… A lost island
+         *   ├─Alternate title (1 de 2)…… Island lost again
+         *   ├─Alternate title (2 de 2)…… Map example
+         *   ├─Date………………………………………………………… 2018-04-09 00:00:00
+         *   │   └─Date type………………………………… Création
+         *   ├─Edition………………………………………………… First edition
+         *   └─Edition date…………………………………… 2018-04-10 00:00:00
+         */
+        final DefaultCitation cit = new DefaultCitation();
+        cit.setTitle(new SimpleInternationalString("A lost island"));
+        cit.setEdition(new SimpleInternationalString("First edition"));
+        cit.setEditionDate(new Date(1523311200000L));
+        cit.setCollectiveTitle(new SimpleInternationalString("Popular legends"));
+        cit.setAlternateTitles(Arrays.asList(new SimpleInternationalString("Island lost again"),
+                                             new Anchor(new URI("http://map-example.com"), "Map example")));
+        cit.getDates().add(new DefaultCitationDate(new Date(1523224800000L), DateType.CREATION));
+        cit.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "lost-island");
+        dataId.setCitation(cit);
+        dataId.setTemporalResolutions(Collections.emptySet());              // TODO: depends on sis-temporal
+        final Collection<MaintenanceInformation> resourceMaintenances;
+        {
+            /*
+             * Maintenance information
+             *   ├─Maintenance and update frequency…… Not planned
+             *   ├─Maintenance date……………………………………………… 3000-01-01 00:00:00
+             *   │   └─Date type……………………………………………………… Révision
+             *   └─Maintenance scope
+             *       ├─Level………………………………………………………………… Model
+             *       └─Level description
+             *           └─Dataset………………………………………………… Imaginary map
+             */
+            DefaultMaintenanceInformation maintenanceInfo = new DefaultMaintenanceInformation();
+            maintenanceInfo.setMaintenanceAndUpdateFrequency(MaintenanceFrequency.NOT_PLANNED);
+            maintenanceInfo.getMaintenanceDates().add(new DefaultCitationDate(new Date(32503676400000L), DateType.REVISION));
+            final DefaultScope maintenanceScope = new DefaultScope();
+            maintenanceScope.setLevel(ScopeCode.MODEL);
+            {
+                // Scope level descriptions
+                final DefaultScopeDescription scopeDescription = new DefaultScopeDescription();
+                scopeDescription.setDataset("Imaginary map");
+                maintenanceScope.getLevelDescription().add(scopeDescription);
+            }
+            maintenanceInfo.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "not-planned");
+            maintenanceInfo.getMaintenanceScopes().add(maintenanceScope);
+            resourceMaintenances = Collections.singleton(maintenanceInfo);
+            dataId.setResourceMaintenances(resourceMaintenances);
+        }
+        {
+            /*
+             * Format
+             *   ├─Format specification citation…… Portable Network Graphics
+             *   │   ├─Alternate title……………………………… PNG
+             *   │   └─Edition…………………………………………………… November 2003
+             *   ├─Amendment number……………………………………… Second edition
+             *   └─File decompression technique……… L77 / Huffman coding
+             */
+            final DefaultFormat resourceFormat = new DefaultFormat();
+            resourceFormat.setName(new SimpleInternationalString("PNG"));
+            resourceFormat.setSpecification(new SimpleInternationalString("Portable Network Graphics"));
+            resourceFormat.setAmendmentNumber(new SimpleInternationalString("Second edition"));
+            resourceFormat.setVersion(new SimpleInternationalString("November 2003"));
+            resourceFormat.setFileDecompressionTechnique(new SimpleInternationalString("L77 / Huffman coding"));
+            dataId.getResourceFormats().add(resourceFormat);
+        }
+        final Collection<Keywords> descriptiveKeywords;
+        {
+            /*
+             * Keywords
+             *   ├─Thesaurus name………… Plato's dialogues
+             *   ├─Keyword class…………… Greek elements
+             *   ├─Keyword (1 de 2)…… Water
+             *   ├─Keyword (2 de 2)…… Aether
+             *   └─Type…………………………………… Theme
+             */
+            final DefaultKeywords keywords = new DefaultKeywords();
+            keywords.setType(KeywordType.THEME);
+            keywords.setThesaurusName(new DefaultCitation("Plato's dialogues"));
+            final DefaultKeywordClass keywordClass = new DefaultKeywordClass();
+            keywordClass.setClassName(new SimpleInternationalString("Greek elements"));
+            keywords.setKeywordClass(keywordClass);
+            keywords.setKeywords(Arrays.asList(new SimpleInternationalString("Water"),
+                                               new SimpleInternationalString("Aether")));
+            keywords.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "greek-elements");
+            descriptiveKeywords = Collections.singleton(keywords);
+            dataId.setDescriptiveKeywords(descriptiveKeywords);
+        }
+        {
+            /*
+             * Usage………………………………………………………………………… For testing purpose only.
+             *   ├─Usage date time…………………………………… 2018-04-10 14:00:00
+             *   ├─User determined limitations…… Not to be used outside MarshallingTest.java test file.
+             *   └─Response……………………………………………………… Random elements
+             */
+            final DefaultUsage usage = new DefaultUsage();
+            usage.setSpecificUsage(new SimpleInternationalString("For testing purpose only."));
+            usage.setUsageDate(new Date(1523361600000L));
+            usage.setResponses(Collections.singleton(new SimpleInternationalString("Random elements")));
+            usage.setUserDeterminedLimitations(new SimpleInternationalString("Not to be used outside MarshallingTest.java test file."));
+            dataId.getResourceSpecificUsages().add(usage);
+        }
+        final Collection<AssociatedResource> associatedResources;
+        {
+            // Associated resources (AggregationInfo in 19139)
+            final DefaultAssociatedResource associatedResource = new DefaultAssociatedResource();
+            associatedResource.setAssociationType(AssociationType.DEPENDENCY);
+            associatedResource.setInitiativeType(InitiativeType.EXPERIMENT);
+            associatedResource.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "dependency");
+            associatedResources = Collections.singleton(associatedResource);
+            dataId.setAssociatedResources(associatedResources);
+        }
+        dataId.setLanguages(languages);     // Locales (ISO 19115:2014) a.k.a Languages and CharacterSets (ISO 19115:2003)
+        dataId.setCharacterSets(charSets);
+        dataId.setEnvironmentDescription (new SimpleInternationalString("High humidity."));
+        dataId.setSupplementalInformation(new SimpleInternationalString("High water pressure."));
+        {
+            // Service identification info
+            final DefaultServiceIdentification serviceId = new DefaultServiceIdentification();
+            serviceId.setCitation(cit);
+            serviceId.setAbstract(new SimpleInternationalString("An inspiration for story tellers."));
+            serviceId.setExtents(extents);
+            serviceId.setResourceMaintenances(resourceMaintenances);
+            serviceId.setDescriptiveKeywords(descriptiveKeywords);
+            serviceId.setResourceConstraints(resourceConstraints);
+            serviceId.setAssociatedResources(associatedResources);
+            serviceId.setServiceTypeVersions(Collections.singleton("Version 1000+"));
+            // TODO: Coupled resources
+            final DefaultCoupledResource coupledResource = new DefaultCoupledResource();
+            serviceId.getCoupledResources().add(coupledResource);
+            serviceId.setCouplingType(CouplingType.LOOSE);
+            final DefaultOperationMetadata operationMetadata = new DefaultOperationMetadata();
+            {
+                operationMetadata.setOperationName("Authoring");
+                operationMetadata.setOperationDescription(new SimpleInternationalString("Write a book."));
+                operationMetadata.setInvocationName(new SimpleInternationalString("someMethodName"));
+                operationMetadata.getDistributedComputingPlatforms().add(DistributedComputingPlatform.JAVA);
+            }
+            serviceId.getContainsOperations().add(operationMetadata);
+            serviceId.getOperatesOn().add(dataId);
+            md.setIdentificationInfo(Arrays.asList(dataId, serviceId));
+        }
+        {
+            // Content info
+            final DefaultCoverageDescription coverageDescription;
+            {
+                coverageDescription = new DefaultCoverageDescription();
+                // Attribute description
+                final DefaultRecordSchema schema = new DefaultRecordSchema(null, null, "IslandFeatures");
+                final Map<CharSequence,Class<?>> members = new LinkedHashMap<>();
+                members.put("city",      String.class);
+                members.put("latitude",  Double.class);
+                members.put("longitude", Double.class);
+                final RecordType recordType = schema.createRecordType("SettledArea", members);
+                coverageDescription.setAttributeDescription(recordType);
+                {
+                    /*
+                     * Attribute group
+                     *   ├─Content type…………………… Auxilliary information
+                     *   ├─Attribute (1 de 2)…… 42
+                     *   │   ├─Description…………… Population density
+                     *   │   └─Name
+                     *   └─Attribute (2 de 2)
+                     *       ├─Description…………… Temperature
+                     *       ├─Max value………………… 22,22
+                     *       ├─Min value………………… 11,11
+                     *       ├─Units…………………………… °C
+                     *       └─Scale factor………… 1,5
+                     */
+                    final DefaultAttributeGroup attributeGroup = new DefaultAttributeGroup();
+                    attributeGroup.getContentTypes().add(CoverageContentType.AUXILLARY_INFORMATION);
+                    // Attributes
+                    final DefaultRangeDimension rangeDimension = new DefaultRangeDimension();
+                    rangeDimension.setDescription(new SimpleInternationalString("Population density"));
+                    rangeDimension.setSequenceIdentifier(Names.createMemberName(null, null, "42", Integer.class));
+                    rangeDimension.getNames().add(new DefaultIdentifier());
+                    final DefaultSampleDimension sampleDimension = new DefaultSampleDimension();
+                    sampleDimension.setDescription(new SimpleInternationalString("Temperature"));
+                    sampleDimension.setMinValue(11.11);
+                    sampleDimension.setMaxValue(22.22);
+                    sampleDimension.setUnits(Units.CELSIUS);
+                    sampleDimension.setScaleFactor(1.5);
+                    attributeGroup.setAttributes(Arrays.asList(rangeDimension, sampleDimension));
+                    coverageDescription.getAttributeGroups().add(attributeGroup);
+                }
+            }
+            // Feature Catalogue Description
+            final DefaultFeatureCatalogueDescription featureCatalogueDescription = new DefaultFeatureCatalogueDescription();
+            featureCatalogueDescription.setIncludedWithDataset(true);
+            featureCatalogueDescription.setCompliant(true);
+            md.setContentInfo(Arrays.asList(coverageDescription, featureCatalogueDescription));
+        }
+        return md;
+    }
+
+    /**
+     * Tests marshalling of an ISO 19139:2007 document (based on ISO 19115:2003 model).
+     * Current implementation merely tests that marshalling does not produce exception.
+     *
+     * @throws URISyntaxException if an error occurred while creating the metadata object.
+     * @throws JAXBException if an error occurred while marshalling the document.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-400">SIS-400</a>
+     */
+    @Test
+    public void testLegacySchema() throws URISyntaxException, JAXBException {
+        legacyXML = true;
+        final DefaultMetadata md = metadata();
+        marshaller.setProperty(XML.METADATA_VERSION, VERSION_2007);
+        marshaller.marshal(md, output);
+        recycle();
+    }
+
+    /**
+     * Tests marshalling of an ISO 19115-3 document (based on ISO 19115:2014 model).
+     * Current implementation merely tests that marshalling does not produce exception.
+     *
+     * @throws URISyntaxException if an error occurred while creating the metadata object.
+     * @throws JAXBException if an error occurred while marshalling the document.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/SIS-400">SIS-400</a>
+     */
+    @Test
+    public void testCurrentSchema() throws JAXBException, URISyntaxException {
+        final DefaultMetadata md = metadata();
+        marshaller.setProperty(XML.METADATA_VERSION, VERSION_2014);
+        marshaller.marshal(md, output);
+        recycle();
+    }
+
+    /**
+     * Invoked only on success, for recycling the marshaller.
+     */
+    private void recycle() {
+        pool.recycle(marshaller);
+    }
+
+    /**
+     * For internal {@code DefaultMetadata} usage.
+     *
+     * @return {@code Object.class}.
+     */
+    @Override
+    public Class<Object> getSourceClass() {
+        return Object.class;
+    }
+
+    /**
+     * Invoked when a warning occurred while marshalling a test XML fragment. Expected warnings are
+     * "Can't find resource for bundle {@code java.util.PropertyResourceBundle}, key <cite>Foo</cite>".
+     * When marshalling legacy XML only, additional warnings may occur.
+     *
+     * @param source  ignored.
+     * @param warning the warning.
+     */
+    @Override
+    public void warningOccured(final Object source, final LogRecord warning) {
+        if (warning.getThrown() instanceof MissingResourceException) {
+            assertNull("Expected a warning message without parameters.", warning.getParameters());
+            return;
+        }
+        final String message = warning.getMessage();
+        if (legacyXML) {
+            assertEquals("IgnoredPropertiesAfterFirst_1", message);
+            assertArrayEquals(new String[] {"RangeDimension"}, warning.getParameters());
+        } else {
+            fail("Unexpected logging message: " + message);
+        }
+    }
+}
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java
index 35d88d8..82149a8 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultCitationTest.java
@@ -30,7 +30,6 @@ import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.citation.Party;
 import org.opengis.metadata.citation.Role;
 import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
@@ -85,15 +84,9 @@ public final strictfp class DefaultCitationTest extends TestUsingFile {
                 PresentationForm.DOCUMENT_DIGITAL));
         citation.setAlternateTitles(Collections.singleton(
                 new SimpleInternationalString("Andākarento")));   // Actually a different script of the Japanese title.
-
-        final DefaultResponsibleParty author = new DefaultResponsibleParty(Role.AUTHOR);
-        author.setParties(Collections.singleton(new DefaultIndividual("Testsuya Toyoda", null, null)));
-
-        final DefaultResponsibleParty editor = new DefaultResponsibleParty(Role.EDITOR);
-        editor.setParties(Collections.singleton(new DefaultOrganisation("Kōdansha", null, null, null)));
-        editor.setExtents(Collections.singleton(Extents.WORLD));
-
-        citation.setCitedResponsibleParties(Arrays.asList(author, editor));
+        citation.setCitedResponsibleParties(Arrays.asList(
+                new DefaultResponsibility(Role.AUTHOR, null, new DefaultIndividual("Testsuya Toyoda", null, null)),
+                new DefaultResponsibility(Role.EDITOR, Extents.WORLD, new DefaultOrganisation("Kōdansha", null, null, null))));
         return citation;
     }
 
@@ -221,7 +214,7 @@ public final strictfp class DefaultCitationTest extends TestUsingFile {
      */
     private void testMarshalling(final String file, final Version version) throws JAXBException {
         final DefaultOnlineResource rs = new DefaultOnlineResource(URI.create("https://tools.ietf.org/html/rfc1149"));
-        rs.setName("IP over Avian Carriers");
+        rs.setName(new SimpleInternationalString("IP over Avian Carriers"));
         rs.setDescription(new SimpleInternationalString("High delay, low throughput, and low altitude service."));
         rs.setFunction(OnLineFunction.OFFLINE_ACCESS);
 
@@ -229,11 +222,10 @@ public final strictfp class DefaultCitationTest extends TestUsingFile {
         contact.setContactInstructions(new SimpleInternationalString("Send carrier pigeon."));
         contact.getIdentifierMap().putSpecialized(IdentifierSpace.ID, "ip-protocol");
         final DefaultCitation c = new DefaultCitation("Fight against poverty");
-        final DefaultResponsibleParty r1 = new DefaultResponsibleParty(Role.ORIGINATOR);
-        final DefaultResponsibleParty r2 = new DefaultResponsibleParty(Role.FUNDER);
-        r1.setParties(Collections.singleton(new DefaultIndividual("Maid Marian", null, contact)));
-        r2.setParties(Collections.singleton(new DefaultIndividual("Robin Hood",  null, contact)));
-        c.setCitedResponsibleParties(Arrays.asList(r1, r2));
+        c.setCitedResponsibleParties(Arrays.asList(
+                new DefaultResponsibility(Role.ORIGINATOR, null, new DefaultIndividual("Maid Marian", null, contact)),
+                new DefaultResponsibility(Role.FUNDER,     null, new DefaultIndividual("Robin Hood",  null, contact))
+        ));
         c.getDates().add(new DefaultCitationDate(TestUtilities.date("2015-10-17 00:00:00"), DateType.ADOPTED));
         c.getPresentationForms().add(PresentationForm.PHYSICAL_OBJECT);
         /*
@@ -284,7 +276,7 @@ public final strictfp class DefaultCitationTest extends TestUsingFile {
         assertEquals("dateType", DateType.ADOPTED, date.getDateType());
         assertEquals("presentationForm", PresentationForm.PHYSICAL_OBJECT, getSingleton(c.getPresentationForms()));
 
-        final Iterator<ResponsibleParty> it = c.getCitedResponsibleParties().iterator();
+        final Iterator<Responsibility> it = c.getCitedResponsibleParties().iterator();
         final Contact contact = assertResponsibilityEquals(Role.ORIGINATOR, "Maid Marian", it.next());
         assertEquals("Contact instruction", "Send carrier pigeon.", String.valueOf(contact.getContactInstructions()));
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java
index 6badf16..24362b9 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/DefaultResponsibilityTest.java
@@ -44,9 +44,8 @@ public final strictfp class DefaultResponsibilityTest extends XMLTestCase {
     @Test
     public void testLegacyMarshalling() throws JAXBException {
         final DefaultIndividual  party = new DefaultIndividual("An author", null, null);
-        final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.AUTHOR);
+        final DefaultResponsibility  r = new DefaultResponsibility(Role.AUTHOR, null, party);
         final DefaultCitation citation = new DefaultCitation();
-        r.setParties(singleton(party));
         citation.setCitedResponsibleParties(singleton(r));
         final String xml = marshal(citation, VERSION_2007);
         assertXmlEquals("<gmd:CI_Citation xmlns:gco=\"" + LegacyNamespaces.GCO + '"' +
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java
index 9e64a36..78feb24 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/HardCodedCitations.java
@@ -27,8 +27,6 @@ import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.util.Static;
 
-import static java.util.Collections.singleton;
-
 
 /**
  * Hard-coded citation constants used for testing purpose only.
@@ -94,9 +92,8 @@ public final strictfp class HardCodedCitations extends Static {
         final DefaultOnlineResource r = new DefaultOnlineResource(URI.create("http://www.epsg.org"));
         r.setFunction(OnLineFunction.INFORMATION);
 
-        final DefaultResponsibleParty p = new DefaultResponsibleParty(Role.PRINCIPAL_INVESTIGATOR);
-        p.setParties(singleton(new DefaultOrganisation("International Association of Oil & Gas Producers",
-                null, null, new DefaultContact(r))));
+        final DefaultResponsibility p = new DefaultResponsibility(Role.PRINCIPAL_INVESTIGATOR, null,
+                new DefaultOrganisation("International Association of Oil & Gas Producers", null, null, new DefaultContact(r)));
 
         final DefaultCitation c = new DefaultCitation("EPSG Geodetic Parameter Dataset");
         c.getPresentationForms().add(PresentationForm.TABLE_DIGITAL);
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
index 97d9a16..52f6d46 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/identification/DefaultDataIdentificationTest.java
@@ -19,6 +19,7 @@ package org.apache.sis.metadata.iso.identification;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Locale;
+import java.nio.charset.StandardCharsets;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.DateType;
 import org.opengis.metadata.identification.KeywordType;
@@ -37,9 +38,6 @@ import static java.util.Arrays.asList;
 import static java.util.Collections.singleton;
 import static org.apache.sis.test.MetadataAssert.*;
 
-// Branch-specific imports
-import org.opengis.metadata.identification.CharacterSet;
-
 
 /**
  * Tests {@link DefaultDataIdentification}.
@@ -119,7 +117,7 @@ public final strictfp class DefaultDataIdentificationTest extends TestCase {
         info.setResourceConstraints(singleton(new DefaultConstraints("Freely available")));
         info.setExtents(singleton(Extents.WORLD));
         info.setLanguages(asList(LOCALES));
-        info.setCharacterSets(singleton(CharacterSet.US_ASCII));
+        info.setCharacterSets(singleton(StandardCharsets.US_ASCII));
         return info;
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java
index 5082ab5..f1d2108 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/maintenance/DefaultScopeDescriptionTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.metadata.iso.maintenance;
 
+import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.test.LoggingWatcher;
 import org.apache.sis.test.TestCase;
@@ -61,14 +62,14 @@ public final strictfp class DefaultScopeDescriptionTest extends TestCase {
         assertEquals("dataset", "A dataset", metadata.getDataset());
         loggings.assertNoUnexpectedLog();
 
-        metadata.setOther("Other value");
-        assertEquals("other", "Other value", metadata.getOther());
+        metadata.setOther(new SimpleInternationalString("Other value"));
+        assertEquals("other", "Other value", String.valueOf(metadata.getOther()));
         assertNull("dataset", metadata.getDataset());
         loggings.assertNextLogContains("dataset", "other");
         loggings.assertNoUnexpectedLog();
 
         metadata.setDataset(null);                  // Expected to be a no-op.
-        assertEquals("other", "Other value", metadata.getOther());
+        assertEquals("other", "Other value", String.valueOf(metadata.getOther()));
         assertNull("dataset", metadata.getDataset());
 
         metadata.setOther(null);
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
index 5849532..04ba6c1 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataWriterTest.java
@@ -126,7 +126,7 @@ public final strictfp class MetadataWriterTest extends TestCase {
         assertEquals("EPSG",      source.search(HardCodedCitations.EPSG));
         assertEquals("SIS",       source.search(HardCodedCitations.SIS));
         assertNull  ("ISO 19111", source.search(HardCodedCitations.ISO_19111));
-        assertEquals("{CI_ResponsibleParty}EPS", source.search(TestUtilities.getSingleton(
+        assertEquals("EPSG",      source.search(TestUtilities.getSingleton(
                 HardCodedCitations.EPSG.getCitedResponsibleParties())));
     }
 
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
index 4d85c36..5663d47 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/mock/IdentifiedObjectMock.java
@@ -25,9 +25,9 @@ import javax.xml.bind.annotation.XmlRootElement;
 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
+import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.internal.jaxb.gco.GO_GenericName;
 
@@ -44,7 +44,7 @@ import org.apache.sis.internal.jaxb.gco.GO_GenericName;
  */
 @SuppressWarnings("serial")
 @XmlRootElement(name = "IO_IdentifiedObject")
-public strictfp class IdentifiedObjectMock implements IdentifiedObject, ReferenceIdentifier, Serializable {
+public strictfp class IdentifiedObjectMock implements IdentifiedObject, Identifier, Serializable {
     /**
      * The object name to be returned by {@link #getCode()}.
      */
@@ -102,7 +102,7 @@ public strictfp class IdentifiedObjectMock implements IdentifiedObject, Referenc
      * @return the name of this object, or {@code null} if none.
      */
     @Override
-    public final ReferenceIdentifier getName() {
+    public final Identifier getName() {
         return (code != null) ? this : null;
     }
 
@@ -162,7 +162,7 @@ public strictfp class IdentifiedObjectMock implements IdentifiedObject, Referenc
      * @return the identifiers of this object.
      */
     @Override
-    public final Set<ReferenceIdentifier> getIdentifiers() {
+    public final Set<Identifier> getIdentifiers() {
         return null;
     }
 
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 f9dd7c2..3d66fb1 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
@@ -125,6 +125,7 @@ import org.junit.BeforeClass;
     org.apache.sis.metadata.iso.DefaultMetadataTest.class,
     org.apache.sis.metadata.iso.CustomMetadataTest.class,
     org.apache.sis.metadata.iso.AllMetadataTest.class,
+    org.apache.sis.metadata.iso.MarshallingTest.class,
     org.apache.sis.metadata.iso.APIVerifier.class,
 
     org.apache.sis.io.wkt.ConventionTest.class,
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
index 68d3a09..f8e069e 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/test/xml/AnnotationConsistencyCheck.java
@@ -502,7 +502,7 @@ public abstract strictfp class AnnotationConsistencyCheck extends TestCase {
          * We check only the namespace start, since some specifications define many namespaces
          * under a common root (e.g. "http://standards.iso.org/iso/19115/-3/").
          */
-        if (uml != null && false) {     // This verification is available only on development branches.
+        if (uml != null) {
             final String expected = getExpectedNamespaceStart(impl, uml);
             if (!namespace.startsWith(expected)) {
                 fail("Expected " + expected + "… namespace for that ISO specification but got " + namespace);
@@ -565,18 +565,6 @@ public abstract strictfp class AnnotationConsistencyCheck extends TestCase {
     protected boolean isIgnored(final Method method) {
         switch (method.getName()) {
             /*
-             * Spelling changed.
-             */
-            case "getCenterPoint": {
-                return true;
-            }
-            /*
-             * Method that override an annotated method in parent class.
-             */
-            case "getUnits": {
-                return org.opengis.metadata.content.Band.class.isAssignableFrom(method.getDeclaringClass());
-            }
-            /*
              * Types for which JAXB binding has not yet implemented.
              */
             case "getGeographicCoordinates": {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
index af5ed04..5c97eef 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/CC_GeneralOperationParameter.java
@@ -27,7 +27,6 @@ import java.lang.reflect.Array;
 import javax.xml.bind.annotation.XmlElementRef;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.GeneralParameterDescriptor;
@@ -262,7 +261,7 @@ public final class CC_GeneralOperationParameter extends PropertyType<CC_GeneralO
         final Map<String,Object> merged = new HashMap<>(expected);
         merged.putAll(actual);  // May overwrite pre-defined properties.
         mergeArrays(GeneralParameterDescriptor.ALIAS_KEY,       GenericName.class, provided.getAlias(),       merged, complete.getName());
-        mergeArrays(GeneralParameterDescriptor.IDENTIFIERS_KEY, ReferenceIdentifier.class, provided.getIdentifiers(), merged, null);
+        mergeArrays(GeneralParameterDescriptor.IDENTIFIERS_KEY, Identifier.class,  provided.getIdentifiers(), merged, null);
         if (isGroup) {
             final List<GeneralParameterDescriptor> descriptors = ((ParameterDescriptorGroup) provided).descriptors();
             return merge(DefaultParameterValueGroup.class, merged, merged, minimumOccurs, maximumOccurs,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
index 536dd23..96b0cd0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/jaxb/referencing/Code.java
@@ -21,7 +21,6 @@ import javax.xml.bind.annotation.XmlValue;
 import javax.xml.bind.annotation.XmlAttribute;
 import org.opengis.metadata.Identifier;
 import org.opengis.metadata.citation.Citation;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.util.DefinitionURI;
 import org.apache.sis.internal.metadata.NameMeaning;
@@ -96,7 +95,7 @@ public final class Code {
      *
      * @return the identifier, or {@code null} if none.
      */
-    public ReferenceIdentifier getIdentifier() {
+    public Identifier getIdentifier() {
         String c = code;
         if (c == null) {
             return null;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java
index 46b6c40..455b421 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/NilReferencingObject.java
@@ -21,7 +21,7 @@ import java.util.Collection;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.metadata.Identifier;
 import org.opengis.metadata.extent.Extent;
 import org.apache.sis.xml.NilReason;
 import org.apache.sis.xml.NilObject;
@@ -54,7 +54,7 @@ public final class NilReferencingObject implements NilObject, ReferenceSystem {
      *
      * @since 0.6
      */
-    public static final ReferenceIdentifier UNNAMED = new NamedIdentifier(null, Vocabulary.format(Vocabulary.Keys.Unnamed));
+    public static final Identifier UNNAMED = new NamedIdentifier(null, Vocabulary.format(Vocabulary.Keys.Unnamed));
 
     /**
      * The unique instance.
@@ -80,9 +80,9 @@ public final class NilReferencingObject implements NilObject, ReferenceSystem {
      * Returning null for collection are okay in the particular case of SIS implementation,
      * because the constructor will replace empty collections by null references anyway.
      */
-    @Override public ReferenceIdentifier      getName()        {return UNNAMED;}
+    @Override public Identifier               getName()        {return UNNAMED;}
     @Override public Collection<GenericName>  getAlias()       {return null;}
-    @Override public Set<ReferenceIdentifier> getIdentifiers() {return null;}
+    @Override public Set<Identifier>          getIdentifiers() {return null;}
     @Override public InternationalString      getRemarks()     {return null;}
     @Override public InternationalString      getScope()       {return null;}
     @Override public Extent getDomainOfValidity()              {return null;}
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
index d3b067f..3bb38f7 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/AbstractProvider.java
@@ -21,10 +21,10 @@ import java.util.HashMap;
 import java.util.Collection;
 import javax.xml.bind.annotation.XmlTransient;
 import org.opengis.util.GenericName;
+import org.opengis.metadata.Identifier;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.measure.Units;
 import org.apache.sis.measure.Latitude;
@@ -95,10 +95,10 @@ public abstract class AbstractProvider extends DefaultOperationMethod implements
         ArgumentChecks.ensureNonNull("parameters", parameters);
         final Map<String,Object> properties = new HashMap<>(4);
         properties.put(NAME_KEY, parameters.getName());
-        final Collection<ReferenceIdentifier> identifiers = parameters.getIdentifiers();
+        final Collection<Identifier> identifiers = parameters.getIdentifiers();
         int size = identifiers.size();
         if (size != 0) {
-            properties.put(IDENTIFIERS_KEY, identifiers.toArray(new ReferenceIdentifier[size]));
+            properties.put(IDENTIFIERS_KEY, identifiers.toArray(new Identifier[size]));
         }
         final Collection<GenericName> aliases = parameters.getAlias();
         size = aliases.size();
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
index 6331263..378cb6a 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/MapProjection.java
@@ -31,7 +31,6 @@ import org.opengis.util.GenericName;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterNotFoundException;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
@@ -294,8 +293,7 @@ public abstract class MapProjection extends AbstractProvider {
             final ParameterDescriptor<Double> replacement, final ParameterBuilder builder)
     {
         return copyAliases(template, toRename, sameNameAs(toRename, replacement),
-                (ReferenceIdentifier) IdentifiedObjects.getIdentifier(replacement, toRename),
-                builder.addName(template.getName()));
+                IdentifiedObjects.getIdentifier(replacement, toRename), builder.addName(template.getName()));
     }
 
     /**
@@ -312,7 +310,7 @@ public abstract class MapProjection extends AbstractProvider {
      * @return the given {@code builder}, for method call chaining.
      */
     private static ParameterBuilder copyAliases(final ParameterDescriptor<Double> template, final Citation exclude,
-            GenericName replacement, ReferenceIdentifier newCode, final ParameterBuilder builder)
+            GenericName replacement, Identifier newCode, final ParameterBuilder builder)
     {
         for (GenericName alias : template.getAlias()) {
             if (((Identifier) alias).getAuthority() == exclude) {
@@ -322,7 +320,7 @@ public abstract class MapProjection extends AbstractProvider {
             }
             builder.addName(alias);
         }
-        for (ReferenceIdentifier id : template.getIdentifiers()) {
+        for (Identifier id : template.getIdentifiers()) {
             if (id.getAuthority() == exclude) {
                 if (newCode == null) continue;
                 id = newCode;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java
index ed517e7..cea037b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/provider/ObliqueMercatorCenter.java
@@ -24,9 +24,6 @@ import org.apache.sis.metadata.iso.citation.Citations;
 
 import static org.apache.sis.referencing.IdentifiedObjects.getIdentifier;
 
-// Branch-dependent imports
-import org.opengis.referencing.ReferenceIdentifier;
-
 
 /**
  * The provider for <cite>"Hotine Oblique Mercator (variant B)"</cite> projection (EPSG:9815).
@@ -100,7 +97,7 @@ public final class ObliqueMercatorCenter extends ObliqueMercator {
                 .addName      (Citations.S57,     "OME")
                 .addIdentifier(Citations.S57,     "9")
                 .addName      (Citations.GEOTIFF, "CT_ObliqueMercator")
-                .addIdentifier((ReferenceIdentifier) getIdentifier(PARAMETERS_A, Citations.GEOTIFF))      // Same GeoTIFF identifier.
+                .addIdentifier(getIdentifier(PARAMETERS_A, Citations.GEOTIFF))      // Same GeoTIFF identifier.
                 .addName      (Citations.PROJ4,   "omerc")
                 .createGroupForMapProjection(
                         LATITUDE_OF_CENTRE,
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
index 8f2d171..2ec921d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterFormat.java
@@ -40,7 +40,6 @@ import org.opengis.util.ScopedName;
 import org.opengis.util.GenericName;
 import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.OperationMethod;
 
 import org.apache.sis.measure.Range;
@@ -837,7 +836,7 @@ public class ParameterFormat extends TabularFormat<Object> {
              * Put the first identifier in the first column. If no identifier has a codespace in the list
              * supplied by the user, then we will use the first identifier (any codespace) as a fallback.
              */
-            final Set<ReferenceIdentifier> identifiers = object.getIdentifiers();
+            final Set<Identifier> identifiers = object.getIdentifiers();
             if (identifiers != null) {                                              // Paranoiac check.
                 Identifier identifier = null;
                 for (final Identifier candidate : identifiers) {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
index ebb8cf4..877bc4b 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/AbstractIdentifiedObject.java
@@ -68,9 +68,6 @@ import static org.apache.sis.internal.util.CollectionsExt.nonNull;
 import static org.apache.sis.internal.util.CollectionsExt.nonEmpty;
 import static org.apache.sis.internal.util.CollectionsExt.immutableSet;
 
-// Branch-dependent imports
-import org.opengis.referencing.ReferenceIdentifier;
-
 
 /**
  * Base class for objects identified by a name or a code. Those objects are typically
@@ -113,7 +110,7 @@ import org.opengis.referencing.ReferenceIdentifier;
  * </ul>
  *
  * <div class="section">Immutability and thread safety</div>
- * This base class is immutable if the {@link Citation}, {@link ReferenceIdentifier}, {@link GenericName} and
+ * This base class is immutable if the {@link Citation}, {@link Identifier}, {@link GenericName} and
  * {@link InternationalString} instances given to the constructor are also immutable. Most SIS subclasses and
  * related classes are immutable under similar conditions. This means that unless otherwise noted in the javadoc,
  * {@code IdentifiedObject} instances created using only SIS factories and static constants can be shared by many
@@ -174,12 +171,12 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * The name for this object or code. Shall never be {@code null}.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@code Names.add(Identifier)}.</p>
+     * This field is modified only at unmarshalling time by {@link Names#add(Identifier)}.</p>
      *
      * @see #getName()
      * @see #getNames()
      */
-    private ReferenceIdentifier name;
+    private Identifier name;
 
     /**
      * An alternative name by which this object is identified, or {@code null} if none.
@@ -187,7 +184,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * we may get both on unmarshalling.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@code Names.add(Identifier)}.</p>
+     * This field is modified only at unmarshalling time by {@link Names#add(Identifier)}.</p>
      */
     private Collection<GenericName> alias;
 
@@ -201,7 +198,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * @see #getIdentifiers()
      * @see #getIdentifier()
      */
-    private Set<ReferenceIdentifier> identifiers;
+    private Set<Identifier> identifiers;
 
     /**
      * Comments on or information about this object, or {@code null} if none.
@@ -236,7 +233,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * Other properties listed in the table below are optional.
      * In particular, {@code "authority"}, {@code "code"}, {@code "codespace"} and {@code "version"}
      * are convenience properties for building a name, and are ignored if the {@code "name"} property
-     * is already a {@link ReferenceIdentifier} object instead than a {@link String}.
+     * is already a {@link Identifier} object instead than a {@link String}.
      *
      * <table class="sis">
      *   <caption>Recognized properties (non exhaustive list)</caption>
@@ -247,7 +244,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#NAME_KEY}</td>
-     *     <td>{@link ReferenceIdentifier} or {@link String}</td>
+     *     <td>{@link Identifier} or {@link String}</td>
      *     <td>{@link #getName()}</td>
      *   </tr>
      *   <tr>
@@ -261,12 +258,12 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      *     <td>{@link NamedIdentifier#getCode()} on the {@linkplain #getName() name}</td>
      *   </tr>
      *   <tr>
-     *     <td>{@value org.opengis.referencing.ReferenceIdentifier#CODESPACE_KEY}</td>
+     *     <td>{@value org.opengis.metadata.Identifier#CODESPACE_KEY}</td>
      *     <td>{@link String}</td>
      *     <td>{@link NamedIdentifier#getCodeSpace()} on the {@linkplain #getName() name}</td>
      *   </tr>
      *   <tr>
-     *     <td>{@value org.opengis.referencing.ReferenceIdentifier#VERSION_KEY}</td>
+     *     <td>{@value org.opengis.metadata.Identifier#VERSION_KEY}</td>
      *     <td>{@link String}</td>
      *     <td>{@link NamedIdentifier#getVersion()} on the {@linkplain #getName() name}</td>
      *   </tr>
@@ -282,7 +279,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      *   </tr>
      *   <tr>
      *     <td>{@value org.opengis.referencing.IdentifiedObject#IDENTIFIERS_KEY}</td>
-     *     <td>{@link ReferenceIdentifier} (optionally as array)</td>
+     *     <td>{@link Identifier} (optionally as array)</td>
      *     <td>{@link #getIdentifiers()}</td>
      *   </tr>
      *   <tr>
@@ -333,8 +330,8 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
                         .getString(Errors.Keys.MissingValueForProperty_1, NAME_KEY));
             }
             name = new NamedIdentifier(PropertiesConverter.convert(properties));
-        } else if (value instanceof ReferenceIdentifier) {
-            name = (ReferenceIdentifier) value;
+        } else if (value instanceof Identifier) {
+            name = (Identifier) value;
         } else {
             throw illegalPropertyType(properties, NAME_KEY, value);
         }
@@ -363,10 +360,10 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
         value = properties.get(IDENTIFIERS_KEY);
         if (value == null) {
             identifiers = null;
-        } else if (value instanceof ReferenceIdentifier) {
-            identifiers = Collections.singleton((ReferenceIdentifier) value);
-        } else if (value instanceof ReferenceIdentifier[]) {
-            identifiers = immutableSet(true, (ReferenceIdentifier[]) value);
+        } else if (value instanceof Identifier) {
+            identifiers = Collections.singleton((Identifier) value);
+        } else if (value instanceof Identifier[]) {
+            identifiers = immutableSet(true, (Identifier[]) value);
         } else {
             throw illegalPropertyType(properties, IDENTIFIERS_KEY, value);
         }
@@ -484,7 +481,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * @see IdentifiedObjects#getName(IdentifiedObject, Citation)
      */
     @Override
-    public ReferenceIdentifier getName() {
+    public Identifier getName() {
         return name;
     }
 
@@ -509,7 +506,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * @see IdentifiedObjects#getIdentifier(IdentifiedObject, Citation)
      */
     @Override
-    public Set<ReferenceIdentifier> getIdentifiers() {
+    public Set<Identifier> getIdentifiers() {
         return nonNull(identifiers);    // Needs to be null-safe because we may have a null value on unmarshalling.
     }
 
@@ -970,7 +967,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
     private void setIdentifier(final Code identifier) {
         if (identifiers == null) {
             if (identifier != null) {
-                final ReferenceIdentifier id = identifier.getIdentifier();
+                final Identifier id = identifier.getIdentifier();
                 if (id != null) {
                     identifiers = Collections.singleton(id);
                 }
@@ -998,7 +995,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * @see <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a>
      */
     @XmlElement(name = "name", required = true)
-    final Collection<ReferenceIdentifier> getNames() {
+    final Collection<Identifier> getNames() {
         return new Names();
     }
 
@@ -1015,7 +1012,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
      * subclasses, this is too late. For example {@code DefaultOperationMethod} may need to know the operation name
      * before to parse the parameters.
      */
-    private final class Names extends AbstractCollection<ReferenceIdentifier> {
+    private final class Names extends AbstractCollection<Identifier> {
         /**
          * Invoked by JAXB before to write in the collection at unmarshalling time.
          * Do nothing since our object is already empty.
@@ -1036,7 +1033,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
          * Returns an iterator over the name and aliases that are instance of {@link Identifier}.
          */
         @Override
-        public Iterator<ReferenceIdentifier> iterator() {
+        public Iterator<Identifier> iterator() {
             return new NameIterator(AbstractIdentifiedObject.this);
         }
 
@@ -1050,7 +1047,7 @@ public class AbstractIdentifiedObject extends FormattableObject implements Ident
          * See <a href="https://java.net/jira/browse/JAXB-488">JAXB-488</a> for more information.</p>
          */
         @Override
-        public boolean add(final ReferenceIdentifier id) {
+        public boolean add(final Identifier id) {
             if (NameIterator.isUnnamed(name)) {
                 name = id;
             } else {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
index ae84d2c..3509fda 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
@@ -41,9 +41,6 @@ import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.*;
 
-// Branch-dependent imports
-import org.opengis.referencing.ReferenceIdentifier;
-
 
 /**
  * Base class of builders for various kind of {@link IdentifiedObject}. This class provides convenience methods
@@ -96,7 +93,7 @@ import org.opengis.referencing.ReferenceIdentifier;
  *       The result is a {@linkplain org.apache.sis.util.iso.DefaultScopedName scoped name} or identifier,
  *       in which the code space information is shown by the {@code toString()} method.</li>
  *
- *   <li>The {@code addIdentifier(Identifier)}, {@code addName(Identifier)} and {@link #addName(GenericName)}
+ *   <li>The {@link #addIdentifier(Identifier)}, {@link #addName(Identifier)} and {@link #addName(GenericName)}
  *       methods take the given object <cite>as-is</cite>. Any authority, code space, version or description
  *       information given to the {@code Builder} are ignored.</li>
  * </ul>
@@ -205,7 +202,7 @@ public abstract class Builder<B extends Builder<B>> {
     /**
      * A temporary list for identifiers, before to assign them to the {@link #properties}.
      */
-    private final List<ReferenceIdentifier> identifiers;
+    private final List<Identifier> identifiers;
 
     /**
      * The codespace as a {@code NameSpace} object, or {@code null} if not yet created.
@@ -274,7 +271,7 @@ public abstract class Builder<B extends Builder<B>> {
         if (object != null) {
             properties.putAll(IdentifiedObjects.getProperties(object));
             final GenericName[] valueAlias = (GenericName[]) properties.remove(IdentifiedObject.ALIAS_KEY);
-            final ReferenceIdentifier[] valueIds = (ReferenceIdentifier[])  properties.remove(IdentifiedObject.IDENTIFIERS_KEY);
+            final Identifier[]  valueIds   = (Identifier[])  properties.remove(IdentifiedObject.IDENTIFIERS_KEY);
             if (valueAlias != null) aliases.addAll(Arrays.asList(valueAlias));
             if (valueIds != null) identifiers.addAll(Arrays.asList(valueIds));
         }
@@ -323,7 +320,7 @@ public abstract class Builder<B extends Builder<B>> {
      * then the new identifier will also contain the user-supplied code space and version (if any).
      * The new identifier will be marked as deprecated if {@link #isDeprecated()} returns {@code true}.
      */
-    private ReferenceIdentifier createIdentifier(final Citation authority, final String identifier) {
+    private Identifier createIdentifier(final Citation authority, final String identifier) {
         final String codeSpace;
         final String version;
         if (authority == getAuthority()) {
@@ -341,9 +338,7 @@ public abstract class Builder<B extends Builder<B>> {
      * Creates an identifier for the given authority, code space and version.
      * The new identifier will be marked as deprecated if {@link #isDeprecated()} returns {@code true}.
      */
-    private ReferenceIdentifier createIdentifier(final Citation authority,
-            final String codeSpace, final String identifier, final String version)
-    {
+    private Identifier createIdentifier(final Citation authority, final String codeSpace, final String identifier, final String version) {
         if (isDeprecated()) {
             return new DeprecatedCode(authority, codeSpace, identifier, version, null, getRemarks());
         } else {
@@ -355,8 +350,8 @@ public abstract class Builder<B extends Builder<B>> {
      * Converts the given name into an identifier. Note that {@link NamedIdentifier}
      * implements both {@link GenericName} and {@link Identifier} interfaces.
      */
-    private static ReferenceIdentifier toIdentifier(final GenericName name) {
-        return (name instanceof ReferenceIdentifier) ? (ReferenceIdentifier) name : new NamedIdentifier(name);
+    private static Identifier toIdentifier(final GenericName name) {
+        return (name instanceof Identifier) ? (Identifier) name : new NamedIdentifier(name);
     }
 
     /**
@@ -587,7 +582,7 @@ public abstract class Builder<B extends Builder<B>> {
      * @param  name  the {@code IdentifiedObject} name as an identifier.
      * @return {@code this}, for method call chaining.
      */
-    public B addName(final ReferenceIdentifier name) {
+    public B addName(final Identifier name) {
         ensureNonNull("name", name);
         if (properties.putIfAbsent(IdentifiedObject.NAME_KEY, name) != null) {
             // A primary name is already present. Add the given name as an alias instead.
@@ -679,7 +674,7 @@ public abstract class Builder<B extends Builder<B>> {
      * @param  identifier  the {@code IdentifiedObject} identifier.
      * @return {@code this}, for method call chaining.
      */
-    public B addIdentifier(final ReferenceIdentifier identifier) {
+    public B addIdentifier(final Identifier identifier) {
         ensureNonNull("identifier", identifier);
         identifiers.add(identifier);
         return self();
@@ -709,12 +704,12 @@ public abstract class Builder<B extends Builder<B>> {
      */
     public B addNamesAndIdentifiers(final IdentifiedObject object) {
         ensureNonNull("object", object);
-        for (final ReferenceIdentifier id : object.getIdentifiers()) {
+        for (final Identifier id : object.getIdentifiers()) {
             if (!isDeprecated(id)) {
                 addIdentifier(id);
             }
         }
-        ReferenceIdentifier id = object.getName();
+        Identifier id = object.getName();
         if (!isDeprecated(id)) {
             addName(id);
         }
@@ -1025,7 +1020,7 @@ public abstract class Builder<B extends Builder<B>> {
             valueIds   = null;
         } else {
             valueAlias = aliases    .toArray(new GenericName[aliases    .size()]);
-            valueIds   = identifiers.toArray(new ReferenceIdentifier[identifiers.size()]);
+            valueIds   = identifiers.toArray(new Identifier [identifiers.size()]);
         }
         properties.put(IdentifiedObject.ALIAS_KEY,       valueAlias);
         properties.put(IdentifiedObject.IDENTIFIERS_KEY, valueIds);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
index 63883a2..cc3ef56 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
@@ -556,12 +556,12 @@ public final class CRS extends Static {
              */
             if (maxInsideArea < roiArea) {
                 if (tryDerivedCRS) break;                                               // Do not try twice.
-                final CoordinateReferenceSystem[] derivedCRS = new CoordinateReferenceSystem[sourceCRS.length];
+                final SingleCRS[] derivedCRS = new SingleCRS[sourceCRS.length];
                 for (int i=0; i < derivedCRS.length; i++) {
                     GeographicBoundingBox bbox = null;
                     final CoordinateReferenceSystem crs = sourceCRS[i];
                     if (crs instanceof GeneralDerivedCRS) {
-                        final CoordinateReferenceSystem baseCRS = ((GeneralDerivedCRS) crs).getBaseCRS();
+                        final SingleCRS baseCRS = ((GeneralDerivedCRS) crs).getBaseCRS();
                         bbox = getGeographicBoundingBox(baseCRS);
                         if (bbox == null && bestCRS == null && baseCRS instanceof GeodeticCRS) {
                             bestCRS = baseCRS;      // Fallback to be used if we don't find anything better.
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
index 497d975..0a57422 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NameIterator.java
@@ -19,8 +19,8 @@ package org.apache.sis.referencing;
 import java.util.Iterator;
 import java.util.Collection;
 import org.opengis.util.GenericName;
+import org.opengis.metadata.Identifier;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.Context;
 import org.apache.sis.internal.metadata.NameMeaning;
 import org.apache.sis.internal.referencing.NilReferencingObject;
@@ -30,7 +30,7 @@ import static org.apache.sis.internal.util.Utilities.appendUnicodeIdentifier;
 
 /**
  * An iterator over the {@linkplain IdentifiedObject#getName() name} of an identified object followed by
- * {@linkplain IdentifiedObject#getAlias() aliases} which are instance of {@link ReferenceIdentifier}.
+ * {@linkplain IdentifiedObject#getAlias() aliases} which are instance of {@link Identifier}.
  * This iterator is used for {@link AbstractIdentifiedObject} XML marshalling because GML merges the name
  * and aliases in a single {@code <gml:name>} property. However this iterator is useful only if the aliases
  * are instances of {@link NamedIdentifier}, or any other implementation which is both a name and an identifier.
@@ -42,11 +42,11 @@ import static org.apache.sis.internal.util.Utilities.appendUnicodeIdentifier;
  * @since   0.4
  * @module
  */
-final class NameIterator implements Iterator<ReferenceIdentifier> {
+final class NameIterator implements Iterator<Identifier> {
     /**
      * The next element to return, or {@code null} if we reached the end of iteration.
      */
-    private ReferenceIdentifier next;
+    private Identifier next;
 
     /**
      * An iterator over the aliases.
@@ -68,7 +68,7 @@ final class NameIterator implements Iterator<ReferenceIdentifier> {
     /**
      * Returns {@code true} if the given identifier is null or the {@link NilReferencingObject#UNNAMED} instance.
      */
-    static boolean isUnnamed(final ReferenceIdentifier name) {
+    static boolean isUnnamed(final Identifier name) {
         return (name == null) || (name == NilReferencingObject.UNNAMED);
     }
 
@@ -87,12 +87,12 @@ final class NameIterator implements Iterator<ReferenceIdentifier> {
      * will be used only by JAXB, which is presumed checking for {@link #hasNext()} correctly.
      */
     @Override
-    public ReferenceIdentifier next() {
-        final ReferenceIdentifier n = next;
+    public Identifier next() {
+        final Identifier n = next;
         while (alias.hasNext()) {
             final GenericName c = alias.next();
-            if (c instanceof ReferenceIdentifier) {
-                next = (ReferenceIdentifier) c;
+            if (c instanceof Identifier) {
+                next = (Identifier) c;
                 return n;
             }
         }
@@ -144,8 +144,8 @@ final class NameIterator implements Iterator<ReferenceIdentifier> {
      * @param  identifiers  the identifiers, or {@code null} if none.
      * @return proposed value for {@code gml:id} attribute, or {@code null} if none.
      */
-    static String getID(final Context context, final IdentifiedObject object, final ReferenceIdentifier name,
-            final Collection<? extends GenericName> alias, final Collection<? extends ReferenceIdentifier> identifiers)
+    static String getID(final Context context, final IdentifiedObject object, final Identifier name,
+            final Collection<? extends GenericName> alias, final Collection<? extends Identifier> identifiers)
     {
         String candidate = Context.getObjectID(context, object);
         if (candidate == null) {
@@ -155,7 +155,7 @@ final class NameIterator implements Iterator<ReferenceIdentifier> {
              * if we found no suitable ID, then we will use the primary name as a last resort.
              */
             if (identifiers != null) {
-                for (final ReferenceIdentifier identifier : identifiers) {
+                for (final Identifier identifier : identifiers) {
                     if (appendUnicodeIdentifier(id, '-', identifier.getCodeSpace(), "", true) |    // Really |, not ||
                         appendUnicodeIdentifier(id, '-', NameMeaning.toObjectType(object.getClass()), "", false) |
                         appendUnicodeIdentifier(id, '-', identifier.getCode(), "", true))
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
index a1cf4b3..d2d2e16 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
@@ -32,7 +32,6 @@ import org.opengis.util.InternationalString;
 import org.apache.sis.util.resources.Errors;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.Identifier;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.InvalidParameterValueException;
 import org.apache.sis.internal.metadata.NameToIdentifier;
 import org.apache.sis.internal.system.DefaultFactories;
@@ -95,7 +94,7 @@ import org.apache.sis.util.ArgumentChecks;
  * @since 0.4
  * @module
  */
-public class NamedIdentifier extends ImmutableIdentifier implements GenericName, ReferenceIdentifier {
+public class NamedIdentifier extends ImmutableIdentifier implements GenericName {
     /**
      * Serial number for inter-operability with different versions.
      */
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
index 10c7911..8a4b0af 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/Properties.java
@@ -21,10 +21,10 @@ import java.util.HashMap;
 import java.util.Collection;
 import java.io.Serializable;
 import org.opengis.util.GenericName;
+import org.opengis.metadata.Identifier;
 import org.opengis.referencing.datum.Datum;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.referencing.IdentifiedObject;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.metadata.quality.PositionalAccuracy;
@@ -125,11 +125,11 @@ final class Properties extends AbstractMap<String,Object> implements Serializabl
                     return object.getName();
                 }
                 case 1: {   // IDENTIFIERS_KEY
-                    final Collection<ReferenceIdentifier> c = object.getIdentifiers();
+                    final Collection<Identifier> c = object.getIdentifiers();
                     if (c != null) {
                         final int size = c.size();
                         if (size != 0) {
-                            return c.toArray(new ReferenceIdentifier[size]);
+                            return c.toArray(new Identifier[size]);
                         }
                     }
                     break;
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
index 1c66728..55fe5d4 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/AbstractDerivedCRS.java
@@ -145,7 +145,7 @@ abstract class AbstractDerivedCRS<C extends Conversion> extends AbstractCRS impl
      */
     AbstractDerivedCRS(final GeneralDerivedCRS crs) {
         super(crs);
-        conversionFromBase = createConversionFromBase(null, (SingleCRS) crs.getBaseCRS(), crs.getConversionFromBase());
+        conversionFromBase = createConversionFromBase(null, crs.getBaseCRS(), crs.getConversionFromBase());
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
index 613e309..a00f7ec 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultDerivedCRS.java
@@ -381,7 +381,7 @@ public class DefaultDerivedCRS extends AbstractDerivedCRS<Conversion> implements
         if (object == null || object instanceof DefaultDerivedCRS) {
             return (DefaultDerivedCRS) object;
         } else {
-            final String type = getType((SingleCRS) object.getBaseCRS(), object.getCoordinateSystem());
+            final String type = getType(object.getBaseCRS(), object.getCoordinateSystem());
             if (type != null) switch (type) {
                 case WKTKeywords.GeodeticCRS:    return new Geodetic   (object);
                 case WKTKeywords.VerticalCRS:    return new Vertical   (object);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
index 5ae000c..27e14f0 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultProjectedCRS.java
@@ -235,7 +235,7 @@ public class DefaultProjectedCRS extends AbstractDerivedCRS<Projection> implemen
     @XmlElement(name = "baseGeodeticCRS", required = true)        // Note: older GML version used "baseGeographicCRS".
     public GeographicCRS getBaseCRS() {
         final Projection projection = super.getConversionFromBase();
-        return (projection != null) ? (GeographicCRS) projection.getSourceCRS() : null;
+        return (projection != null) ? projection.getSourceCRS() : null;
     }
 
     /**
@@ -288,7 +288,7 @@ public class DefaultProjectedCRS extends AbstractDerivedCRS<Projection> implemen
     @Override
     final AbstractCRS createSameType(final Map<String,?> properties, final CoordinateSystem cs) {
         final Projection conversion = super.getConversionFromBase();
-        return new DefaultProjectedCRS(properties, (GeographicCRS) conversion.getSourceCRS(), conversion, (CartesianCS) cs);
+        return new DefaultProjectedCRS(properties, conversion.getSourceCRS(), conversion, (CartesianCS) cs);
     }
 
     /**
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
index 5dff676..d7853bc 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
@@ -972,7 +972,7 @@ public class CoordinateOperationFinder extends CoordinateOperationRegistry {
                  * it is not, try to copy it in such object.
                  */
                 final SingleOperation op;
-                if (SubTypes.isSingleOperation(subOperation)) {
+                if (subOperation instanceof SingleOperation) {
                     op = (SingleOperation) subOperation;
                 } else {
                     op = factorySIS.createSingleOperation(properties,
@@ -1073,7 +1073,7 @@ public class CoordinateOperationFinder extends CoordinateOperationRegistry {
             if (isAxisChange1 && mt1.getSourceDimensions() == mt1.getTargetDimensions()) main = step2;
             if (isAxisChange2 && mt2.getSourceDimensions() == mt2.getTargetDimensions()) main = step1;
         }
-        if (SubTypes.isSingleOperation(main)) {
+        if (main instanceof SingleOperation) {
             final SingleOperation op = (SingleOperation) main;
             final MathTransform mt = factorySIS.getMathTransformFactory().createConcatenatedTransform(mt1, mt2);
             main = createFromMathTransform(new HashMap<>(IdentifiedObjects.getProperties(main)),
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
index 6a733d3..67278e5 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
@@ -601,7 +601,7 @@ class CoordinateOperationRegistry {
     private CoordinateOperation inverse(final CoordinateOperation operation)
             throws NoninvertibleTransformException, FactoryException
     {
-        if (SubTypes.isSingleOperation(operation)) {
+        if (operation instanceof SingleOperation) {
             return inverse((SingleOperation) operation);
         }
         if (operation instanceof ConcatenatedOperation) {
@@ -788,7 +788,7 @@ class CoordinateOperationRegistry {
          * be prepared to see the 'redimension' call fails. In such case, we will try to get
          * the SIS implementation of the operation method and try again.
          */
-        if (SubTypes.isSingleOperation(operation)) {
+        if (operation instanceof SingleOperation) {
             final SingleOperation single = (SingleOperation) operation;
             properties.put(ReferencingServices.PARAMETERS_KEY, single.getParameterValues());
             if (method == null) {
@@ -947,7 +947,7 @@ class CoordinateOperationRegistry {
              */
             Matrix matrix = MathTransforms.getMatrix(op.getMathTransform());
             if (matrix == null) {
-                if (SubTypes.isSingleOperation(op)) {
+                if (op instanceof SingleOperation) {
                     final MathTransformFactory mtFactory = factorySIS.getMathTransformFactory();
                     if (mtFactory instanceof DefaultMathTransformFactory) {
                         if (forward) sourceCRS = toGeodetic3D(sourceCRS, source3D);
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
index 44d6c7c..99a6f50 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultConcatenatedOperation.java
@@ -43,7 +43,6 @@ import org.apache.sis.io.wkt.Formatter;
 
 import static org.apache.sis.util.Utilities.deepEquals;
 
-import org.opengis.referencing.operation.SingleOperation;
 
 /**
  * An ordered sequence of two or more single coordinate operations. The sequence of operations is constrained
@@ -71,7 +70,7 @@ final class DefaultConcatenatedOperation extends AbstractCoordinateOperation imp
      * <p><b>Consider this field as final!</b>
      * This field is modified only at unmarshalling time by {@link #setSteps(CoordinateOperation[])}</p>
      */
-    private List<SingleOperation> operations;
+    private List<? extends CoordinateOperation> operations;
 
     /**
      * Constructs a concatenated operation from a set of properties and a
@@ -143,7 +142,7 @@ final class DefaultConcatenatedOperation extends AbstractCoordinateOperation imp
          * At this point we should have flattened.size() >= 2, except if some operations
          * were omitted because their associated math transform were identity operation.
          */
-        this.operations = UnmodifiableArrayList.wrap(flattened.toArray(new SingleOperation[flattened.size()]));
+        this.operations = UnmodifiableArrayList.wrap(flattened.toArray(new CoordinateOperation[flattened.size()]));
     }
 
     /**
@@ -327,17 +326,11 @@ final class DefaultConcatenatedOperation extends AbstractCoordinateOperation imp
     /**
      * Returns the sequence of operations.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * This method is conformant to ISO 19111:2003. But the ISO 19111:2007 revision changed the element type
-     * from {@code SingleOperation} to {@link CoordinateOperation}. This change may be applied in GeoAPI 4.0.
-     * This is necessary for supporting usage of {@code PassThroughOperation} with {@link ConcatenatedOperation}.
-     * </div>
-     *
      * @return the sequence of operations.
      */
     @Override
     @SuppressWarnings("ReturnOfCollectionOrArrayField")
-    public List<SingleOperation> getOperations() {
+    public List<? extends CoordinateOperation> getOperations() {
         return operations;
     }
 
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
index 8196889..cca675d 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/DefaultPassThroughOperation.java
@@ -22,7 +22,6 @@ import java.util.Objects;
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.CoordinateOperation;
 import org.opengis.referencing.operation.PassThroughOperation;
@@ -40,8 +39,6 @@ import org.apache.sis.io.wkt.Formatter;
 
 import static org.apache.sis.util.Utilities.deepEquals;
 
-import org.opengis.referencing.operation.OperationMethod;
-import org.opengis.referencing.operation.SingleOperation;
 
 /**
  * Specifies that a subset of a coordinate tuple is subject to a specific coordinate operation.
@@ -66,11 +63,11 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
      * The operation to apply on the subset of a coordinate tuple.
      *
      * <p><b>Consider this field as final!</b>
-     * This field is modified only at unmarshalling time by {@code setOperation(CoordinateOperation)}</p>
+     * This field is modified only at unmarshalling time by {@link #setOperation(CoordinateOperation)}</p>
      *
      * @see #getOperation()
      */
-    private SingleOperation operation;
+    private CoordinateOperation operation;
 
     /**
      * Constructs a single operation from a set of properties.
@@ -108,7 +105,7 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
     public DefaultPassThroughOperation(final Map<String,?>            properties,
                                        final CoordinateReferenceSystem sourceCRS,
                                        final CoordinateReferenceSystem targetCRS,
-                                       final SingleOperation           operation,
+                                       final CoordinateOperation       operation,
                                        final int firstAffectedOrdinate,
                                        final int numTrailingOrdinates)
     {
@@ -168,43 +165,15 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
     }
 
     /**
-     * @deprecated May be removed in GeoAPI 4.0 since it does not apply to pass-through operations.
-     *
-     * @return {@code null}.
-     */
-    @Override
-    @Deprecated
-    public OperationMethod getMethod() {
-        return null;
-    }
-
-    /**
-     * @deprecated May be removed in GeoAPI 4.0 since it does not apply to pass-through operations.
-     *
-     * @return {@code null}.
-     */
-    @Override
-    @Deprecated
-    public ParameterValueGroup getParameterValues() {
-        return null;
-    }
-
-    /**
      * Returns the operation to apply on the subset of a coordinate tuple.
      *
-     * <div class="warning"><b>Upcoming API change</b><br>
-     * This method is conformant to ISO 19111:2003. But the ISO 19111:2007 revision changed the type from
-     * {@code SingleOperation} to {@link CoordinateOperation}. This change may be applied in GeoAPI 4.0.
-     * This is necessary for supporting usage of {@code PassThroughOperation} with {@code ConcatenatedOperation}.
-     * </div>
-     *
      * @return the operation to apply on the subset of a coordinate tuple.
      *
      * @see PassThroughTransform#getSubTransform()
      */
     @Override
     @XmlElement(name = "coordOperation", required = true)
-    public SingleOperation getOperation() {
+    public CoordinateOperation getOperation() {
         return operation;
     }
 
@@ -340,7 +309,7 @@ public class DefaultPassThroughOperation extends AbstractCoordinateOperation imp
      *
      * @see #getOperation()
      */
-    private void setOperation(final SingleOperation op) {
+    private void setOperation(final CoordinateOperation op) {
         if (operation == null) {
             operation = op;
         } else {
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
index 2576836..f797bae 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubOperationInfo.java
@@ -65,7 +65,7 @@ final class SubOperationInfo {
      */
     private static Class<?> type(SingleCRS crs) {
         while (crs instanceof GeneralDerivedCRS) {
-            crs = (SingleCRS) ((GeneralDerivedCRS) crs).getBaseCRS();
+            crs = ((GeneralDerivedCRS) crs).getBaseCRS();
         }
         return crs.getClass();
     }
diff --git a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
index f525f8d..51e1e64 100644
--- a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
+++ b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/SubTypes.java
@@ -47,17 +47,6 @@ final class SubTypes {
     }
 
     /**
-     * Returns {@code true} if the given operation is a single operation but not a pass-through operation.
-     * In an older ISO 19111 model, {@link PassThroughOperation} extended {@link SingleOperation}, which
-     * was a problem for providing a value to the inherited {@link SingleOperation#getMethod()} method.
-     * This has been fixed in newer ISO 19111 model, but for safety with objects following the older model
-     * (e.g. GeoAPI 3.0) we are better to perform an explicit exclusion of {@link PassThroughOperation}.
-     */
-    static boolean isSingleOperation(final CoordinateOperation operation) {
-        return (operation instanceof SingleOperation) && !(operation instanceof PassThroughOperation);
-    }
-
-    /**
      * Returns a SIS implementation for the given coordinate operation.
      *
      * @see AbstractCoordinateOperation#castOrCopy(CoordinateOperation)
@@ -75,7 +64,7 @@ final class SubTypes {
         if (object instanceof ConcatenatedOperation) {
             return DefaultConcatenatedOperation.castOrCopy((ConcatenatedOperation) object);
         }
-        if (isSingleOperation(object)) {
+        if (object instanceof SingleOperation) {
             return (object instanceof AbstractSingleOperation) ? (AbstractSingleOperation) object
                    : new AbstractSingleOperation((SingleOperation) object);
         }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java b/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
index 31aacc3..ed1c8e9 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/parameter/ParametersTest.java
@@ -23,8 +23,8 @@ import javax.measure.Unit;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDirection;
 import org.opengis.parameter.ParameterValue;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.parameter.ParameterValueGroup;
+import org.opengis.metadata.Identifier;
 import org.opengis.util.GenericName;
 import org.opengis.util.InternationalString;
 import org.apache.sis.measure.Range;
@@ -115,9 +115,9 @@ public final strictfp class ParametersTest extends TestCase {
     {
         assertEquals(valueDomain, Parameters.getValueDomain(descriptor));
         assertEquals(valueDomain, Parameters.getValueDomain(new ParameterDescriptor<T>() {
-            @Override public ReferenceIdentifier      getName()          {return descriptor.getName();}
+            @Override public Identifier               getName()          {return descriptor.getName();}
             @Override public Collection<GenericName>  getAlias()         {return descriptor.getAlias();}
-            @Override public Set<ReferenceIdentifier> getIdentifiers()   {return descriptor.getIdentifiers();}
+            @Override public Set<Identifier>          getIdentifiers()   {return descriptor.getIdentifiers();}
             @Override public InternationalString      getRemarks()       {return descriptor.getRemarks();}
             @Override public InternationalString      getDescription()   {return descriptor.getDescription();}
             @Override public ParameterDirection       getDirection()     {return descriptor.getDirection();}
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java b/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
index 094df04..04b92b8 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/referencing/AbstractIdentifiedObjectTest.java
@@ -23,7 +23,7 @@ import java.util.LinkedHashSet;
 import java.util.Locale;
 import java.util.Collections;
 import org.opengis.test.Validators;
-import org.opengis.referencing.ReferenceIdentifier;
+import org.opengis.metadata.Identifier;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.referencing.datum.AbstractDatum;
 import org.apache.sis.internal.jaxb.referencing.Code;
@@ -57,10 +57,10 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
      *
      * @param  identifiers  the value for the {@code "identifiers"} property.
      */
-    private static Map<String,Object> properties(final Set<ReferenceIdentifier> identifiers) {
+    private static Map<String,Object> properties(final Set<Identifier> identifiers) {
         final Map<String,Object> properties = new HashMap<>(8);
         assertNull(properties.put("name",       "GRS 1980"));
-        assertNull(properties.put("identifiers", identifiers.toArray(new ReferenceIdentifier[identifiers.size()])));
+        assertNull(properties.put("identifiers", identifiers.toArray(new Identifier[identifiers.size()])));
         assertNull(properties.put("codespace",  "EPSG"));
         assertNull(properties.put("version",    "8.3"));
         assertNull(properties.put("alias",      "International 1979"));
@@ -77,11 +77,11 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
      * @param  gmlID        the expected value of {@link AbstractIdentifiedObject#getID()}.
      * @return the value of {@link AbstractIdentifiedObject#getIdentifier()}.
      */
-    private static ReferenceIdentifier validate(final AbstractIdentifiedObject object,
-            final Set<ReferenceIdentifier> identifiers, final String gmlID)
+    private static Identifier validate(final AbstractIdentifiedObject object,
+            final Set<Identifier> identifiers, final String gmlID)
     {
         Validators.validate(object);
-        final ReferenceIdentifier name = object.getName();
+        final Identifier name = object.getName();
         assertEquals("name",        "GRS 1980",                      name.getCode());
         assertEquals("codespace",   "EPSG",                          name.getCodeSpace());
         assertEquals("version",     "8.3",                           name.getVersion());
@@ -134,9 +134,9 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
      */
     @Test
     public void testWithoutIdentifier() {
-        final Set<ReferenceIdentifier> identifiers = Collections.emptySet();
+        final Set<Identifier>          identifiers = Collections.emptySet();
         final AbstractIdentifiedObject object      = new AbstractIdentifiedObject(properties(identifiers));
-        final ReferenceIdentifier      gmlId       = validate(object, identifiers, "GRS1980");
+        final Identifier               gmlId       = validate(object, identifiers, "GRS1980");
         assertNull("gmlId", gmlId);
     }
 
@@ -153,10 +153,10 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
     @Test
     @DependsOnMethod("testWithoutIdentifier")
     public void testWithSingleIdentifier() {
-        final ReferenceIdentifier      identifier  = new ImmutableIdentifier(null, "EPSG", "7019");
-        final Set<ReferenceIdentifier> identifiers = Collections.singleton(identifier);
+        final Identifier               identifier  = new ImmutableIdentifier(null, "EPSG", "7019");
+        final Set<Identifier>          identifiers = Collections.singleton(identifier);
         final AbstractIdentifiedObject object      = new AbstractIdentifiedObject(properties(identifiers));
-        final ReferenceIdentifier      gmlId       = validate(object, identifiers, "epsg-7019");
+        final Identifier               gmlId       = validate(object, identifiers, "epsg-7019");
         assertNotNull("gmlId",                   gmlId);
         assertEquals ("gmlId.codespace", "EPSG", gmlId.getCodeSpace());
         assertEquals ("gmlId.code",      "7019", gmlId.getCode());
@@ -170,11 +170,11 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
     @Test
     @DependsOnMethod("testWithSingleIdentifier")
     public void testWithManyIdentifiers() {
-        final Set<ReferenceIdentifier> identifiers = new LinkedHashSet<>(4);
+        final Set<Identifier> identifiers = new LinkedHashSet<>(4);
         assertTrue(identifiers.add(new NamedIdentifier(EPSG, "7019")));
         assertTrue(identifiers.add(new NamedIdentifier(EPSG, "IgnoreMe")));
         final AbstractIdentifiedObject object = new AbstractIdentifiedObject(properties(identifiers));
-        final ReferenceIdentifier      gmlId  = validate(object, identifiers, "epsg-7019");
+        final Identifier gmlId  = validate(object, identifiers, "epsg-7019");
         assertNotNull("gmlId",                   gmlId);
         assertEquals ("gmlId.codespace", "EPSG", gmlId.getCodeSpace());
         assertEquals ("gmlId.code",      "7019", gmlId.getCode());
@@ -188,10 +188,10 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
     @Test
     @DependsOnMethod("testWithManyIdentifiers")
     public void testAsSubtype() {
-        final ReferenceIdentifier      identifier  = new NamedIdentifier(EPSG, "7019");
-        final Set<ReferenceIdentifier> identifiers = Collections.singleton(identifier);
+        final Identifier               identifier  = new NamedIdentifier(EPSG, "7019");
+        final Set<Identifier>          identifiers = Collections.singleton(identifier);
         final AbstractIdentifiedObject object      = new AbstractDatum(properties(identifiers));
-        final ReferenceIdentifier      gmlId       = validate(object, identifiers, "epsg-datum-7019");
+        final Identifier               gmlId       = validate(object, identifiers, "epsg-datum-7019");
         assertNotNull("gmlId",                   gmlId);
         assertEquals ("gmlId.codespace", "EPSG", gmlId.getCodeSpace());
         assertEquals ("gmlId.code",      "7019", gmlId.getCode());
@@ -235,9 +235,9 @@ public final strictfp class AbstractIdentifiedObjectTest extends TestCase {
     @Test
     @DependsOnMethod("testWithoutIdentifier")
     public void testSerialization() {
-        final Set<ReferenceIdentifier> identifiers = Collections.emptySet();
-        final AbstractIdentifiedObject object      = new AbstractIdentifiedObject(properties(identifiers));
-        final AbstractIdentifiedObject actual      = assertSerializedEquals(object);
+        final Set<Identifier>     identifiers = Collections.emptySet();
+        final AbstractIdentifiedObject object = new AbstractIdentifiedObject(properties(identifiers));
+        final AbstractIdentifiedObject actual = assertSerializedEquals(object);
         assertNotSame(object, actual);
         assertNull("gmlId", validate(actual, identifiers, "GRS1980"));
     }
diff --git a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java
index 64ca99f..4680a8e 100644
--- a/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java
+++ b/core/sis-referencing/src/test/java/org/apache/sis/test/integration/MetadataTest.java
@@ -162,7 +162,7 @@ public strictfp class MetadataTest extends XMLTestCase {
          * because this is what will be unmarshalled from the XML document.
          */
         @SuppressWarnings("deprecation")
-        final DefaultResponsibleParty author = new DefaultResponsibleParty(Role.AUTHOR);
+        final DefaultResponsibility author = new DefaultResponsibleParty(Role.AUTHOR);
         final Anchor country = new Anchor(URI.create("SDN:C320:2:FR"), "France"); // Non-public SIS class.
         {
             final DefaultOnlineResource online = new DefaultOnlineResource(URI.create("http://www.ifremer.fr/sismer/"));
@@ -174,7 +174,7 @@ public strictfp class MetadataTest extends XMLTestCase {
                     new DefaultTelephone("+33 (0)2 xx.xx.xx.x4", TelephoneType.FACSIMILE)
             ));
             final DefaultAddress address = new DefaultAddress();
-            address.setDeliveryPoints(singleton("Brest institute"));
+            address.setDeliveryPoints(singleton(new SimpleInternationalString("Brest institute")));
             address.setCity(new SimpleInternationalString("Plouzane"));
             address.setPostalCode("29280");
             address.setCountry(country);
@@ -194,7 +194,7 @@ public strictfp class MetadataTest extends XMLTestCase {
                     new DefaultCitationDate(TestUtilities.date("1979-08-02 22:00:00"), DateType.CREATION)));
             {
                 @SuppressWarnings("deprecation")
-                final DefaultResponsibleParty originator = new DefaultResponsibleParty(Role.ORIGINATOR);
+                final DefaultResponsibility originator = new DefaultResponsibleParty(Role.ORIGINATOR);
                 final DefaultOnlineResource online = new DefaultOnlineResource(URI.create("http://www.com.univ-mrs.fr/LOB/"));
                 online.setProtocol("http");
                 final DefaultContact contact = new DefaultContact(online);
@@ -203,7 +203,7 @@ public strictfp class MetadataTest extends XMLTestCase {
                         new DefaultTelephone("+33 (0)4 xx.xx.xx.x8", TelephoneType.FACSIMILE)
                 ));
                 final DefaultAddress address = new DefaultAddress();
-                address.setDeliveryPoints(singleton("Oceanology institute"));
+                address.setDeliveryPoints(singleton(new SimpleInternationalString("Oceanology institute")));
                 address.setCity(new SimpleInternationalString("Marseille"));
                 address.setPostalCode("13288");
                 address.setCountry(country);
@@ -218,7 +218,7 @@ public strictfp class MetadataTest extends XMLTestCase {
                     TopicCategory.OCEANS);      // Topic category
             {
                 @SuppressWarnings("deprecation")
-                final DefaultResponsibleParty custodian = new DefaultResponsibleParty((DefaultResponsibility) author);
+                final DefaultResponsibility custodian = new DefaultResponsibleParty(author);
                 custodian.setRole(Role.CUSTODIAN);
                 identification.setPointOfContacts(singleton(custodian));
             }
@@ -352,7 +352,7 @@ public strictfp class MetadataTest extends XMLTestCase {
          */
         {
             @SuppressWarnings("deprecation")
-            final DefaultResponsibleParty distributor = new DefaultResponsibleParty((DefaultResponsibility) author);
+            final DefaultResponsibility distributor = new DefaultResponsibleParty(author);
             final DefaultDistribution distributionInfo = new DefaultDistribution();
             distributor.setRole(Role.DISTRIBUTOR);
             distributionInfo.setDistributors(singleton(new DefaultDistributor(distributor)));
@@ -372,7 +372,7 @@ public strictfp class MetadataTest extends XMLTestCase {
             onlines.setProtocol("http");
             transfer.setOnLines(singleton(onlines));
             distributionInfo.setTransferOptions(singleton(transfer));
-            metadata.setDistributionInfo(distributionInfo);
+            metadata.setDistributionInfo(singleton(distributionInfo));
         }
         return metadata;
     }
diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationMock.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationMock.java
index c8513b9..e91116a 100644
--- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationMock.java
+++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/CitationMock.java
@@ -25,10 +25,9 @@ import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.citation.CitationDate;
 import org.opengis.metadata.citation.OnlineResource;
 import org.opengis.metadata.citation.PresentationForm;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.opengis.metadata.citation.Series;
 import org.opengis.metadata.identification.BrowseGraphic;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.util.InternationalString;
 import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.util.Debug;
@@ -44,7 +43,7 @@ import org.apache.sis.util.Debug;
  * @module
  */
 @SuppressWarnings("ReturnOfCollectionOrArrayField")
-final strictfp class CitationMock implements Citation, ReferenceIdentifier {
+final strictfp class CitationMock implements Citation, Identifier {
     /**
      * The title to be returned by {@link #getTitle()}.
      */
@@ -86,10 +85,10 @@ final strictfp class CitationMock implements Citation, ReferenceIdentifier {
     @Override public String                           getCodeSpace()               {return codeSpace;}
     @Override public String                           getVersion()                 {return null;}
     @Override public InternationalString              getDescription()             {return null;}
-    @Override public Collection<ResponsibleParty>     getCitedResponsibleParties() {return Collections.emptyList();}
+    @Override public Collection<Responsibility>       getCitedResponsibleParties() {return Collections.emptyList();}
     @Override public Collection<PresentationForm>     getPresentationForms()       {return Collections.emptyList();}
     @Override public Series                           getSeries()                  {return null;}
-    @Override public InternationalString              getOtherCitationDetails()    {return null;}
+    @Override public Collection<InternationalString>  getOtherCitationDetails()    {return Collections.emptyList();}
     @Override public Collection<OnlineResource>       getOnlineResources()         {return Collections.emptyList();}
     @Override public Collection<BrowseGraphic>        getGraphics()                {return Collections.emptyList();}
     @Override public String                           getISBN()                    {return null;}
diff --git a/ide-project/NetBeans/nbproject/build-impl.xml b/ide-project/NetBeans/nbproject/build-impl.xml
index d8cd687..1f0a2f8 100644
--- a/ide-project/NetBeans/nbproject/build-impl.xml
+++ b/ide-project/NetBeans/nbproject/build-impl.xml
@@ -19,7 +19,7 @@ is divided into following sections:
   - cleanup
 
         -->
-<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Apache_SIS_on_GeoAPI_3.1-impl">
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="Apache_SIS_on_GeoAPI_4.0-impl">
     <fail message="Please build using Ant 1.8.0 or higher.">
         <condition>
             <not>
@@ -634,7 +634,7 @@ is divided into following sections:
                     </fileset>
                 </union>
                 <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
-                <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="Apache_SIS_on_GeoAPI_3.1" testname="TestNG tests" workingDir="${work.dir}">
+                <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="Apache_SIS_on_GeoAPI_4.0" testname="TestNG tests" workingDir="${work.dir}">
                     <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
                     <propertyset>
                         <propertyref prefix="test-sys-prop."/>
@@ -839,7 +839,7 @@ is divided into following sections:
                 <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
                     <isset property="test.method"/>
                 </condition>
-                <condition else="-suitename Apache_SIS_on_GeoAPI_3.1 -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                <condition else="-suitename Apache_SIS_on_GeoAPI_4.0 -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
                     <matches pattern=".*\.xml" string="@{testClass}"/>
                 </condition>
                 <delete dir="${build.test.results.dir}" quiet="true"/>
@@ -1131,7 +1131,7 @@ is divided into following sections:
         <delete file="${built-jar.properties}" quiet="true"/>
     </target>
     <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
-        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 3.1 was already built"/>
+        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 4.0 was already built"/>
     </target>
     <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
         <mkdir dir="${build.dir}"/>
@@ -1141,6 +1141,14 @@ is divided into following sections:
         <propertyfile file="${built-jar.properties}">
             <entry key="${basedir}" value=""/>
         </propertyfile>
+        <antcall target="-maybe-call-dep">
+            <param name="call.built.properties" value="${built-jar.properties}"/>
+            <param location="${project.GeoAPI}" name="call.subproject"/>
+            <param location="${project.GeoAPI}/build.xml" name="call.script"/>
+            <param name="call.target" value="jar"/>
+            <param name="transfer.built-jar.properties" value="${built-jar.properties}"/>
+            <param name="transfer.not.archive.disabled" value="true"/>
+        </antcall>
     </target>
     <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
     <target depends="init" name="-check-automatic-build">
@@ -1792,7 +1800,7 @@ is divided into following sections:
         <delete file="${built-clean.properties}" quiet="true"/>
     </target>
     <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
-        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 3.1 was already built"/>
+        <echo level="warn" message="Cycle detected: Apache SIS on GeoAPI 4.0 was already built"/>
     </target>
     <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
         <mkdir dir="${build.dir}"/>
@@ -1802,6 +1810,14 @@ is divided into following sections:
         <propertyfile file="${built-clean.properties}">
             <entry key="${basedir}" value=""/>
         </propertyfile>
+        <antcall target="-maybe-call-dep">
+            <param name="call.built.properties" value="${built-clean.properties}"/>
+            <param location="${project.GeoAPI}" name="call.subproject"/>
+            <param location="${project.GeoAPI}/build.xml" name="call.script"/>
+            <param name="call.target" value="clean"/>
+            <param name="transfer.built-clean.properties" value="${built-clean.properties}"/>
+            <param name="transfer.not.archive.disabled" value="true"/>
+        </antcall>
     </target>
     <target depends="init" name="-do-clean">
         <delete dir="${build.dir}"/>
diff --git a/ide-project/NetBeans/nbproject/genfiles.properties b/ide-project/NetBeans/nbproject/genfiles.properties
index 3289eca..1f696fd 100644
--- a/ide-project/NetBeans/nbproject/genfiles.properties
+++ b/ide-project/NetBeans/nbproject/genfiles.properties
@@ -3,6 +3,6 @@
 build.xml.data.CRC32=58e6b21c
 build.xml.script.CRC32=462eaba0
 build.xml.stylesheet.CRC32=28e38971@1.53.1.46
-nbproject/build-impl.xml.data.CRC32=3c99954d
-nbproject/build-impl.xml.script.CRC32=fb8d24ed
+nbproject/build-impl.xml.data.CRC32=06dcebcb
+nbproject/build-impl.xml.script.CRC32=b7ab89c5
 nbproject/build-impl.xml.stylesheet.CRC32=830a3534@1.80.1.48
diff --git a/ide-project/NetBeans/nbproject/project.properties b/ide-project/NetBeans/nbproject/project.properties
index 8759a1e..4976a71 100644
--- a/ide-project/NetBeans/nbproject/project.properties
+++ b/ide-project/NetBeans/nbproject/project.properties
@@ -31,7 +31,7 @@ includes             = **
 excludes             =
 javadoc.html5        = false
 jlink.launcher       = false
-jlink.launcher.name  = Apache_SIS_on_GeoAPI_3.1
+jlink.launcher.name  = Apache_SIS_on_GeoAPI_4.0
 main.class           =
 manifest.file        = manifest.mf
 project.license      = apache20
@@ -91,11 +91,17 @@ src.fra-profile.dir  = ${project.root}/profiles/sis-french-profile/src/main/java
 test.fra-profile.dir = ${project.root}/profiles/sis-french-profile/src/test/java
 
 #
+# Dependencies on other NetBeans projects. The path is relative to the "NetBeans" parent directory.
+# If a different path is desired, copy that line in the "private/private.properties" file and edit
+# its value there.
+#
+project.GeoAPI       = ../../../../GeoAPI/master/ide-project/NetBeans
+
+#
 # Version numbers for all dependencies.
 # Those dependencies must exist in the local Maven repository.
 # Those numbers should match the ones declared in the pom.xml files.
 #
-geoapi.version       = 3.1-SNAPSHOT
 jsr363.version       = 1.0
 jama.version         = 1.0.3
 esri.api.version     = 2.1.0
@@ -127,7 +133,7 @@ icons.version        = 3.0.1
 maven.repository   = ${user.home}/.m2/repository
 endorsed.classpath=
 javac.classpath=\
-    ${maven.repository}/org/opengis/geoapi-pending/${geoapi.version}/geoapi-pending-${geoapi.version}.jar:\
+    ${project.GeoAPI}/dist/geoapi.jar:\
     ${maven.repository}/javax/measure/unit-api/${jsr363.version}/unit-api-${jsr363.version}.jar:\
     ${maven.repository}/com/esri/geometry/esri-geometry-api/${esri.api.version}/esri-geometry-api-${esri.api.version}.jar:\
     ${maven.repository}/org/locationtech/jts/jts-core/${jts.version}/jts-core-${jts.version}.jar:\
@@ -144,13 +150,11 @@ javac.test.classpath=\
     ${javac.classpath}:\
     ${maven.repository}/junit/junit/${junit.version}/junit-${junit.version}.jar:\
     ${maven.repository}/org/hamcrest/hamcrest-core/${hamcrest.version}/hamcrest-core-${hamcrest.version}.jar:\
-    ${maven.repository}/org/opengis/geoapi-conformance/${geoapi.version}/geoapi-conformance-${geoapi.version}.jar:\
     ${maven.repository}/org/apache/derby/derby/${derby.version}/derby-${derby.version}.jar:\
     ${maven.repository}/org/postgresql/postgresql/${postgresql.version}/postgresql-${postgresql.version}.jar:\
     ${maven.repository}/org/hsqldb/hsqldb/${hsqldb.version}/hsqldb-${hsqldb.version}.jar:\
     ${maven.repository}/gov/nist/math/jama/${jama.version}/jama-${jama.version}.jar:\
-    ${maven.repository}/org/opengis/wrapper/geoapi-netcdf/${geoapi.version}/geoapi-netcdf-${geoapi.version}.jar:\
-    ${maven.repository}/org/opengis/wrapper/geoapi-netcdf/${geoapi.version}/geoapi-netcdf-${geoapi.version}-tests.jar:\
+    ${project.GeoAPI}/dist/geoapi-tests.jar:\
     ${build.classes.dir}
 javac.test.processorpath=\
     ${javac.test.classpath}
diff --git a/ide-project/NetBeans/nbproject/project.xml b/ide-project/NetBeans/nbproject/project.xml
index 6177a7f..592860d 100644
--- a/ide-project/NetBeans/nbproject/project.xml
+++ b/ide-project/NetBeans/nbproject/project.xml
@@ -21,7 +21,7 @@
     <type>org.netbeans.modules.java.j2seproject</type>
     <configuration>
         <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
-            <name>Apache SIS on GeoAPI 3.1</name>
+            <name>Apache SIS on GeoAPI 4.0</name>
             <source-roots>
                 <root id="src.local-src.dir" name="Local sources (unversioned)"/>
                 <root id="src.webapp.dir" name="Web application"/>
@@ -67,6 +67,16 @@
                 <root id="test.gdal.dir" name="Test GDAL/Proj4"/>
             </test-roots>
         </data>
+        <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
+            <reference>
+                <foreign-project>GeoAPI</foreign-project>
+                <artifact-type>jar</artifact-type>
+                <script>build.xml</script>
+                <target>jar</target>
+                <clean-target>clean</clean-target>
+                <id>jar</id>
+            </reference>
+        </references>
         <spellchecker-wordlist xmlns="http://www.netbeans.org/ns/spellchecker-wordlist/1">
             <word>accessor</word>
             <word>bilevel</word>
diff --git a/pom.xml b/pom.xml
index e8fd749..63e8687 100644
--- a/pom.xml
+++ b/pom.xml
@@ -514,7 +514,7 @@
     <maven.compile.target>1.8</maven.compile.target>
     <sis.plugin.version>${project.version}</sis.plugin.version>
     <sis.non-free.version>0.8</sis.non-free.version>
-    <geoapi.version>3.1-SNAPSHOT</geoapi.version>
+    <geoapi.version>4.0-SNAPSHOT</geoapi.version>
   </properties>
 
   <profiles>
diff --git a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java
index 56f6759..b65a2f4 100644
--- a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java
+++ b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/DirectReferenceSystem.java
@@ -18,8 +18,8 @@ package org.apache.sis.internal.profile.fra;
 
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.metadata.Identifier;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
 import org.apache.sis.util.ComparisonMode;
 
@@ -71,7 +71,7 @@ public class DirectReferenceSystem extends ReferenceSystemMetadata {
      *
      * @param  identifier  the reference system identifier.
      */
-    public DirectReferenceSystem(final ReferenceIdentifier identifier) {
+    public DirectReferenceSystem(final Identifier identifier) {
         super(identifier);
     }
 
diff --git a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java
index 17f6ba5..a649347 100644
--- a/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java
+++ b/profiles/sis-french-profile/src/main/java/org/apache/sis/internal/profile/fra/IndirectReferenceSystem.java
@@ -18,8 +18,8 @@ package org.apache.sis.internal.profile.fra;
 
 import javax.xml.bind.annotation.XmlType;
 import javax.xml.bind.annotation.XmlRootElement;
+import org.opengis.metadata.Identifier;
 import org.opengis.referencing.ReferenceSystem;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.apache.sis.internal.jaxb.metadata.replace.ReferenceSystemMetadata;
 import org.apache.sis.util.ComparisonMode;
 
@@ -71,7 +71,7 @@ public class IndirectReferenceSystem extends ReferenceSystemMetadata {
      *
      * @param  identifier  the reference system identifier.
      */
-    public IndirectReferenceSystem(final ReferenceIdentifier identifier) {
+    public IndirectReferenceSystem(final Identifier identifier) {
         super(identifier);
     }
 
diff --git a/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java b/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java
index beab79f..3031f69 100644
--- a/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java
+++ b/profiles/sis-french-profile/src/test/java/org/apache/sis/internal/profile/fra/DirectReferenceSystemTest.java
@@ -18,7 +18,7 @@ package org.apache.sis.internal.profile.fra;
 
 import java.util.Collection;
 import javax.xml.bind.JAXBException;
-import org.opengis.metadata.citation.ResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 import org.apache.sis.metadata.iso.DefaultMetadata;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
@@ -58,7 +58,7 @@ public final strictfp class DirectReferenceSystemTest extends XMLTestCase {
     private static DefaultMetadata createMetadata(final boolean legacy) {
         final DefaultMetadata metadata = new DefaultMetadata();
         final DefaultCitation citation = new DefaultCitation("EPSG Geodetic Parameter Dataset");
-        Collection<ResponsibleParty> r = HardCodedCitations.EPSG.getCitedResponsibleParties();
+        Collection<Responsibility> r = HardCodedCitations.EPSG.getCitedResponsibleParties();
         if (legacy) {
             r = singleton(new DefaultResponsibleParty(TestUtilities.getSingleton(r)));
         }
diff --git a/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java b/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
index a3d4964..97babef 100644
--- a/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
+++ b/storage/sis-gdal/src/main/java/org/apache/sis/storage/gdal/PJ.java
@@ -20,9 +20,9 @@ import java.util.Objects;
 import java.io.Serializable;
 import java.io.ObjectStreamException;
 import java.io.InvalidObjectException;
+import org.opengis.metadata.Identifier;
 import org.opengis.util.FactoryException;
 import org.opengis.util.InternationalString;
-import org.opengis.referencing.ReferenceIdentifier;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.referencing.datum.Ellipsoid;
 import org.opengis.referencing.datum.GeodeticDatum;
@@ -51,7 +51,7 @@ import org.apache.sis.internal.system.OS;
  * @module
  */
 @SuppressWarnings("serial")     // serialVersionUID not needed since writeReplace() gives another kind of object.
-final class PJ implements ReferenceIdentifier, Serializable {
+final class PJ implements Identifier, Serializable {
     /**
      * Loads the {@literal Proj.4} library.
      * This static initializer may throw a {@link UnsatisfiedLinkError} if the static library can not be loaded.
diff --git a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
index b3b6c0d..48d59f5 100644
--- a/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
+++ b/storage/sis-netcdf/src/main/java/org/apache/sis/storage/netcdf/MetadataReader.java
@@ -187,7 +187,7 @@ final class MetadataReader extends MetadataBuilder {
      * An object very similar is used as the creator. The point of contact and the creator
      * are often identical except for their role attribute.
      */
-    private transient ResponsibleParty pointOfContact;
+    private transient Responsibility pointOfContact;
 
     /**
      * Creates a new <cite>netCDF to ISO</cite> mapper for the given source.
@@ -457,7 +457,7 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
      * @see AttributeNames#CONTRIBUTOR
      * @see AttributeNames#PUBLISHER
      */
-    private ResponsibleParty createResponsibleParty(final Responsible keys, final boolean isPointOfContact) {
+    private Responsibility createResponsibleParty(final Responsible keys, final boolean isPointOfContact) {
         String individualName   = stringValue(keys.NAME);
         String organisationName = stringValue(keys.INSTITUTION);
         final String email      = stringValue(keys.EMAIL);
@@ -489,7 +489,7 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
          * Verify if we can share the existing 'pointOfContact' instance. This is often the case in practice.
          * If we can not share the whole existing instance, we usually can share parts of it like the address.
          */
-        ResponsibleParty responsibility = pointOfContact;
+        Responsibility responsibility = pointOfContact;
         Contact        contact        = null;
         Address        address        = null;
         OnlineResource resource       = null;
@@ -542,8 +542,7 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
                 if (organisationName != null) party = new DefaultOrganisation(organisationName, null, (Individual) party, null);
                 if (party            == null) party = isOrganisation(keys) ? new DefaultOrganisation() : new DefaultIndividual();
                 if (contact          != null) party.setContactInfo(singleton(contact));
-                responsibility = new DefaultResponsibleParty(role);
-                ((DefaultResponsibleParty) responsibility).setParties(singleton(party));
+                responsibility = new DefaultResponsibility(role, null, party);
             }
         }
         return responsibility;
@@ -594,7 +593,7 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
          */
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final ResponsibleParty party = createResponsibleParty(CREATOR, true);
+            final Responsibility party = createResponsibleParty(CREATOR, true);
             if (party != pointOfContact) {
                 addPointOfContact(party, Scope.RESOURCE);
                 if (pointOfContact == null) {
@@ -615,11 +614,11 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
         Set<InternationalString> publisher = null;
         for (final String path : searchPath) {
             decoder.setSearchPath(path);
-            final ResponsibleParty contributor = createResponsibleParty(CONTRIBUTOR, false);
+            final Responsibility contributor = createResponsibleParty(CONTRIBUTOR, false);
             if (contributor != pointOfContact) {
                 addCitedResponsibleParty(contributor, null);
             }
-            final ResponsibleParty r = createResponsibleParty(PUBLISHER, false);
+            final Responsibility r = createResponsibleParty(PUBLISHER, false);
             if (r != null) {
                 addDistributor(r);
                 /*
@@ -653,7 +652,7 @@ split:  while ((start = CharSequences.skipLeadingWhitespaces(value, start, lengt
             for (final String keyword : split(stringValue(ACCESS_CONSTRAINT))) {
                 addAccessConstraint(forCodeName(Restriction.class, keyword));
             }
-            addTopicCategory(forCodeName(TopicCategory.class, stringValue(TOPIC_CATEGORY)));
+            addTopicCategory(forEnumName(TopicCategory.class, stringValue(TOPIC_CATEGORY)));
             addSpatialRepresentation(forCodeName(SpatialRepresentationType.class, stringValue(DATA_TYPE)));
             if (!hasExtent) {
                 /*
diff --git a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
index ab02e70..12f9f1e 100644
--- a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
+++ b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/MetadataBuilder.java
@@ -117,10 +117,8 @@ import static java.util.Collections.singleton;
 import static org.apache.sis.internal.util.StandardDateFormat.MILLISECONDS_PER_DAY;
 
 // Branch-dependent imports
-import org.opengis.metadata.citation.ResponsibleParty;
-import org.opengis.metadata.identification.CharacterSet;
 import org.opengis.feature.FeatureType;
-import org.apache.sis.metadata.iso.citation.DefaultResponsibleParty;
+import org.opengis.metadata.citation.Responsibility;
 
 
 /**
@@ -246,16 +244,16 @@ public class MetadataBuilder {
     /**
      * Part of the responsible party of the {@linkplain #citation}, or {@code null} if none.
      */
-    private DefaultResponsibleParty responsibility;
+    private DefaultResponsibility responsibility;
 
     /**
      * Creates the responsibility object if it does not already exists, then returns it.
      *
      * @return the responsibility party (never {@code null}).
      */
-    private DefaultResponsibleParty responsibility() {
+    private DefaultResponsibility responsibility() {
         if (responsibility == null) {
-            responsibility = new DefaultResponsibleParty();
+            responsibility = new DefaultResponsibility();
         }
         return responsibility;
     }
@@ -690,7 +688,7 @@ public class MetadataBuilder {
      */
     public final void newDistribution() {
         if (distribution != null) {
-            metadata().setDistributionInfo(distribution);
+            addIfNotPresent(metadata().getDistributionInfo(), distribution);
             distribution = null;
         }
     }
@@ -979,8 +977,7 @@ public class MetadataBuilder {
         if (encoding != null) {
             // No need to use 'addIfNotPresent(…)' because Charset collection is a Set by default.
             if (scope != Scope.RESOURCE) metadata().getCharacterSets().add(encoding);
-            if (scope != Scope.METADATA) identification().getCharacterSets().add(
-                    Types.forCodeName(CharacterSet.class, encoding.toString(), true));
+            if (scope != Scope.METADATA) identification().getCharacterSets().add(encoding);
         }
     }
 
@@ -1223,8 +1220,7 @@ public class MetadataBuilder {
     public final void addOtherCitationDetails(final CharSequence details) {
         final InternationalString i18n = trim(details);
         if (i18n != null) {
-            final DefaultCitation citation = citation();
-            citation.setOtherCitationDetails(append(citation.getOtherCitationDetails(), i18n));
+            addIfNotPresent(citation().getOtherCitationDetails(), i18n);
         }
     }
 
@@ -1349,10 +1345,10 @@ public class MetadataBuilder {
      * @param  party  the individual or organization that is responsible, or {@code null} for no-operation.
      * @param  role   the role to set, or {@code null} for leaving it unchanged.
      */
-    public final void addCitedResponsibleParty(ResponsibleParty party, final Role role) {
+    public final void addCitedResponsibleParty(Responsibility party, final Role role) {
         if (party != null) {
             if (role != null && !role.equals(party.getRole())) {
-                party = new DefaultResponsibleParty(party);
+                party = new DefaultResponsibility(party);
                 ((DefaultResponsibility) party).setRole(role);
             }
             addIfNotPresent(citation().getCitedResponsibleParties(), party);
@@ -1372,7 +1368,7 @@ public class MetadataBuilder {
      * @param  contact  means of communication with party associated with the resource, or {@code null} for no-operation.
      * @param  scope    whether the contact applies to data, to metadata or to both.
      */
-    public final void addPointOfContact(final ResponsibleParty contact, final Scope scope) {
+    public final void addPointOfContact(final Responsibility contact, final Scope scope) {
         ArgumentChecks.ensureNonNull("scope", scope);
         if (contact != null) {
             if (scope != Scope.RESOURCE)     addIfNotPresent(metadata().getContacts(), contact);
@@ -1390,7 +1386,7 @@ public class MetadataBuilder {
      *
      * @param  distributor  the distributor, or {@code null} for no-operation.
      */
-    public final void addDistributor(final ResponsibleParty distributor) {
+    public final void addDistributor(final Responsibility distributor) {
         if (distributor != null) {
             addIfNotPresent(distribution().getDistributors(), new DefaultDistributor(distributor));
         }
@@ -1407,11 +1403,9 @@ public class MetadataBuilder {
      * @param  credit  recognition of those who contributed to the resource, or {@code null} for no-operation.
      */
     public final void addCredits(final CharSequence credit) {
-        if (credit != null) {
-            final String c = CharSequences.trimWhitespaces(credit).toString();
-            if (!c.isEmpty()) {
-                addIfNotPresent(identification().getCredits(), c);
-            }
+        final InternationalString i18n = trim(credit);
+        if (i18n != null) {
+            addIfNotPresent(identification().getCredits(), i18n);
         }
     }
 
@@ -1594,8 +1588,7 @@ parse:      for (int i = 0; i < length;) {
                 buffer.setLength(i);
                 // Same limitation than MetadataBuilder.party().
                 final AbstractParty party = new AbstractParty(buffer, null);
-                final DefaultResponsibleParty r = new DefaultResponsibleParty(Role.OWNER);
-                r.setParties(Collections.singleton(party));
+                final DefaultResponsibility r = new DefaultResponsibility(Role.OWNER, null, party);
                 c.setCitedResponsibleParties(Collections.singleton(r));
             }
             constraints.getReferences().add(c);
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Copyright.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Copyright.java
index b7b275f..3b40632 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Copyright.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Copyright.java
@@ -45,7 +45,6 @@ import org.apache.sis.util.iso.Types;
 // Branch-dependent imports
 import org.opengis.metadata.citation.Party;
 import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.constraint.Releasability;
 import org.opengis.metadata.maintenance.Scope;
 
@@ -433,7 +432,7 @@ resp:   for (final Responsibility r : c.getResponsibleParties()) {
      * @see #getResponsibleParties()
      */
     @Override
-    public Collection<ResponsibleParty> getCitedResponsibleParties() {
+    public Collection<Responsibility> getCitedResponsibleParties() {
         return Collections.emptySet();
     }
 
@@ -466,8 +465,8 @@ resp:   for (final Responsibility r : c.getResponsibleParties()) {
      * @return other details.
      */
     @Override
-    public InternationalString getOtherCitationDetails() {
-        return null;
+    public Collection<InternationalString> getOtherCitationDetails() {
+        return Collections.emptySet();
     }
 
     /**
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java
index a885717..bdbe53a 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Link.java
@@ -26,7 +26,9 @@ import javax.xml.bind.annotation.XmlElement;
 import org.opengis.util.InternationalString;
 import org.opengis.metadata.citation.OnLineFunction;
 import org.opengis.metadata.citation.OnlineResource;
+import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.internal.jaxb.Context;
+import org.apache.sis.util.iso.Types;
 
 
 /**
@@ -132,7 +134,7 @@ public final class Link implements OnlineResource {
      */
     private Link(final OnlineResource r, final Locale locale) {
         uri  = r.getLinkage();
-        text = r.getName();
+        text = Types.toString(r.getName(), locale);
     }
 
     /**
@@ -183,8 +185,8 @@ public final class Link implements OnlineResource {
      * @return name of the online resource.
      */
     @Override
-    public String getName() {
-        return text;
+    public InternationalString getName() {
+        return (text != null) ? new SimpleInternationalString(text) : null;
     }
 
     /**
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java
index 218778d..01d4c9d 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Metadata.java
@@ -52,7 +52,6 @@ import org.apache.sis.util.iso.SimpleInternationalString;
 import org.apache.sis.util.iso.Types;
 
 // Branch-dependent imports
-import org.opengis.metadata.citation.ResponsibleParty;
 import org.opengis.metadata.citation.Responsibility;
 
 
@@ -320,10 +319,10 @@ public final class Metadata extends SimpleMetadata {
      * @return means of communication with person(s) and organisations(s) associated with the resource.
      */
     @Override
-    public Collection<ResponsibleParty> getPointOfContacts() {
+    public Collection<Responsibility> getPointOfContacts() {
         if (creator != null) {
             final Person p = new Person(creator);
-            return (author != null) ? UnmodifiableArrayList.wrap(new ResponsibleParty[] {p, author})
+            return (author != null) ? UnmodifiableArrayList.wrap(new Responsibility[] {p, author})
                                     : Collections.singletonList(author);
         }
         return (author != null) ? Collections.singletonList(author) : super.getPointOfContacts();
diff --git a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java
index 3d28e83..7cbad4f 100644
--- a/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java
+++ b/storage/sis-xmlstore/src/main/java/org/apache/sis/internal/storage/gpx/Person.java
@@ -16,10 +16,8 @@
  */
 package org.apache.sis.internal.storage.gpx;
 
-import java.util.AbstractSet;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.Locale;
 import java.util.Objects;
 import javax.xml.bind.annotation.XmlElement;
@@ -37,7 +35,6 @@ import org.apache.sis.util.iso.Types;
 // Branch-dependent imports
 import org.opengis.metadata.citation.Party;
 import org.opengis.metadata.citation.Responsibility;
-import org.opengis.metadata.citation.ResponsibleParty;
 
 
 /**
@@ -64,7 +61,7 @@ import org.opengis.metadata.citation.ResponsibleParty;
  * @since   0.8
  * @module
  */
-public final class Person implements ResponsibleParty, Party, Contact, Address {
+public final class Person implements Responsibility, Party, Contact, Address {
     /**
      * Name of person or organization.
      *
@@ -189,37 +186,6 @@ public final class Person implements ResponsibleParty, Party, Contact, Address {
     }
 
     /**
-     * ISO 19115 metadata property not specified by GPX. Actually could be the {@link #name},
-     * but we have no way to know if the author is an individual or an organization.
-     *
-     * @return name of the organization, or {@code null} if none.
-     */
-    @Override
-    public InternationalString getOrganisationName() {
-        return null;
-    }
-
-    /**
-     * ISO 19115 metadata property not specified by GPX.
-     *
-     * @return position of the individual in the organization, or {@code null} if none.
-     */
-    @Override
-    public InternationalString getPositionName() {
-        return null;
-    }
-
-    /**
-     * ISO 19115 metadata property determined by the {@link #name} field.
-     *
-     * @return name of the party, or {@code null} if none.
-     */
-    @Override
-    public String getIndividualName() {
-        return name;
-    }
-
-    /**
      * ISO 19115 metadata property determined by the {@link #email} and {@link #link} fields.
      * Invoking this method is one of the steps in the path from the {@code Responsibility} root
      * to the {@link #getElectronicMailAddresses()} and {@link #getOnlineResources()} methods.
@@ -230,28 +196,8 @@ public final class Person implements ResponsibleParty, Party, Contact, Address {
      * @see #getOnlineResources()
      */
     @Override
-    public Proxy getContactInfo() {        // Both Contact singleton and Collection<Contact>.
-        return new Proxy();
-    }
-
-    private final class Proxy extends AbstractSet<Contact> implements Contact {
-        @Override public int size() {
-            return (email != null || link != null) ? 1 : 0;
-        }
-
-        @Override public Iterator<Contact> iterator() {
-            return Collections.<Contact>singleton(Person.this).iterator();
-        }
-
-        @Override public Collection<Telephone>         getPhones()              {return Person.this.getPhones();}
-        @Override public Telephone                     getPhone()               {return Person.this.getPhone();}
-        @Override public Collection<? extends Address> getAddresses()           {return Person.this.getAddresses();}
-        @Override public Address                       getAddress()             {return Person.this.getAddress();}
-        @Override public Collection<OnlineResource>    getOnlineResources()     {return Person.this.getOnlineResources();}
-        @Override public OnlineResource                getOnlineResource()      {return Person.this.getOnlineResource();}
-        @Override public InternationalString           getHoursOfService()      {return Person.this.getHoursOfService();}
-        @Override public InternationalString           getContactInstructions() {return Person.this.getContactInstructions();}
-        @Override public InternationalString           getContactType()         {return Person.this.getContactType();}
+    public Collection<? extends Contact> getContactInfo() {
+        return thisOrEmpty(email != null || link != null);
     }
 
 
@@ -327,8 +273,8 @@ public final class Person implements ResponsibleParty, Party, Contact, Address {
      * @return time period when individuals can contact the organization or individual.
      */
     @Override
-    public InternationalString getHoursOfService() {
-        return null;
+    public Collection<InternationalString> getHoursOfService() {
+        return Collections.emptyList();
     }
 
     /**
@@ -363,7 +309,7 @@ public final class Person implements ResponsibleParty, Party, Contact, Address {
      * @return address line for the location.
      */
     @Override
-    public Collection<String> getDeliveryPoints() {
+    public Collection<InternationalString> getDeliveryPoints() {
         return Collections.emptyList();
     }
 

-- 
To stop receiving notification emails like this one, please contact
desruisseaux@apache.org.

Mime
View raw message