You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2018/07/25 17:40:04 UTC

[sis] branch geoapi-4.0 updated (c22c705 -> 5d6255e)

This is an automated email from the ASF dual-hosted git repository.

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


    from c22c705  Remove the links to http://jira.geotoolkit.org since this server is not alive anymore.
     new f87e4f0  Move CitationsTest down in the test dependencies because the constants now depend on SQL storage.
     new 5d6255e  Introduce a new State mode: COMPLETABLE.

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../sis/internal/metadata/MetadataUtilities.java   | 24 ++++++-
 .../apache/sis/metadata/ModifiableMetadata.java    | 81 +++++++++++++++-------
 .../iso/DefaultApplicationSchemaInformation.java   | 14 ++--
 .../iso/DefaultExtendedElementInformation.java     | 22 +++---
 .../apache/sis/metadata/iso/DefaultIdentifier.java | 10 +--
 .../apache/sis/metadata/iso/DefaultMetadata.java   | 21 +++---
 .../iso/DefaultMetadataExtensionInformation.java   |  4 +-
 .../sis/metadata/iso/DefaultMetadataScope.java     |  4 +-
 .../org/apache/sis/metadata/iso/ISOMetadata.java   |  2 +-
 .../acquisition/DefaultAcquisitionInformation.java |  2 +-
 .../acquisition/DefaultEnvironmentalRecord.java    |  8 +--
 .../sis/metadata/iso/acquisition/DefaultEvent.java |  8 +--
 .../iso/acquisition/DefaultInstrument.java         |  6 +-
 .../metadata/iso/acquisition/DefaultObjective.java |  2 +-
 .../metadata/iso/acquisition/DefaultOperation.java | 12 ++--
 .../sis/metadata/iso/acquisition/DefaultPlan.java  |  6 +-
 .../metadata/iso/acquisition/DefaultPlatform.java  |  4 +-
 .../iso/acquisition/DefaultPlatformPass.java       |  2 +-
 .../iso/acquisition/DefaultRequestedDate.java      |  5 +-
 .../iso/acquisition/DefaultRequirement.java        |  9 +--
 .../sis/metadata/iso/citation/AbstractParty.java   |  2 +-
 .../sis/metadata/iso/citation/DefaultAddress.java  |  8 +--
 .../sis/metadata/iso/citation/DefaultCitation.java | 26 ++++---
 .../metadata/iso/citation/DefaultCitationDate.java |  5 +-
 .../sis/metadata/iso/citation/DefaultContact.java  |  4 +-
 .../metadata/iso/citation/DefaultIndividual.java   |  2 +-
 .../iso/citation/DefaultOnlineResource.java        | 14 ++--
 .../iso/citation/DefaultResponsibility.java        |  2 +-
 .../iso/citation/DefaultResponsibleParty.java      |  4 +-
 .../sis/metadata/iso/citation/DefaultSeries.java   |  6 +-
 .../metadata/iso/citation/DefaultTelephone.java    |  4 +-
 .../iso/constraint/DefaultConstraints.java         |  4 +-
 .../iso/constraint/DefaultReleasability.java       |  2 +-
 .../iso/constraint/DefaultSecurityConstraints.java |  8 +--
 .../sis/metadata/iso/content/DefaultBand.java      | 16 ++---
 .../iso/content/DefaultCoverageDescription.java    |  8 +--
 .../DefaultFeatureCatalogueDescription.java        |  6 +-
 .../iso/content/DefaultFeatureTypeInfo.java        |  4 +-
 .../iso/content/DefaultImageDescription.java       | 22 +++---
 .../iso/content/DefaultRangeDimension.java         |  4 +-
 .../content/DefaultRangeElementDescription.java    |  4 +-
 .../iso/content/DefaultSampleDimension.java        | 26 +++----
 .../metadata/iso/distribution/DefaultDataFile.java |  8 +--
 .../DefaultDigitalTransferOptions.java             |  6 +-
 .../iso/distribution/DefaultDistribution.java      |  2 +-
 .../iso/distribution/DefaultDistributor.java       |  2 +-
 .../metadata/iso/distribution/DefaultFormat.java   | 12 ++--
 .../metadata/iso/distribution/DefaultMedium.java   | 10 +--
 .../distribution/DefaultStandardOrderProcess.java  | 14 ++--
 .../iso/extent/AbstractGeographicExtent.java       |  2 +-
 .../sis/metadata/iso/extent/DefaultExtent.java     | 15 +++-
 .../iso/extent/DefaultGeographicBoundingBox.java   | 34 +++++----
 .../iso/extent/DefaultGeographicDescription.java   |  2 +-
 .../iso/extent/DefaultSpatialTemporalExtent.java   |  4 +-
 .../metadata/iso/extent/DefaultTemporalExtent.java |  6 +-
 .../metadata/iso/extent/DefaultVerticalExtent.java | 18 +++--
 .../iso/identification/AbstractIdentification.java |  8 +--
 .../DefaultAggregateInformation.java               |  2 +-
 .../identification/DefaultAssociatedResource.java  |  8 +--
 .../iso/identification/DefaultBrowseGraphic.java   |  6 +-
 .../iso/identification/DefaultCoupledResource.java |  8 +--
 .../identification/DefaultDataIdentification.java  |  4 +-
 .../iso/identification/DefaultKeywordClass.java    |  6 +-
 .../iso/identification/DefaultKeywords.java        |  6 +-
 .../DefaultOperationChainMetadata.java             |  4 +-
 .../identification/DefaultOperationMetadata.java   |  6 +-
 .../iso/identification/DefaultResolution.java      |  2 +-
 .../DefaultServiceIdentification.java              |  6 +-
 .../metadata/iso/identification/DefaultUsage.java  |  9 +--
 .../sis/metadata/iso/lineage/DefaultAlgorithm.java |  4 +-
 .../sis/metadata/iso/lineage/DefaultLineage.java   |  4 +-
 .../iso/lineage/DefaultNominalResolution.java      |  4 +-
 .../metadata/iso/lineage/DefaultProcessStep.java   | 10 +--
 .../iso/lineage/DefaultProcessStepReport.java      |  6 +-
 .../metadata/iso/lineage/DefaultProcessing.java    |  4 +-
 .../sis/metadata/iso/lineage/DefaultSource.java    | 18 ++---
 .../maintenance/DefaultMaintenanceInformation.java | 10 +--
 .../sis/metadata/iso/maintenance/DefaultScope.java |  2 +-
 .../iso/maintenance/DefaultScopeDescription.java   |  4 +-
 .../sis/metadata/iso/quality/AbstractElement.java  | 12 ++--
 .../iso/quality/DefaultConformanceResult.java      |  6 +-
 .../iso/quality/DefaultCoverageResult.java         | 10 +--
 .../metadata/iso/quality/DefaultDataQuality.java   |  4 +-
 .../iso/quality/DefaultQuantitativeResult.java     |  6 +-
 .../sis/metadata/iso/spatial/DefaultDimension.java | 12 ++--
 .../sis/metadata/iso/spatial/DefaultGCP.java       |  2 +-
 .../metadata/iso/spatial/DefaultGCPCollection.java |  6 +-
 .../iso/spatial/DefaultGeometricObjects.java       |  4 +-
 .../metadata/iso/spatial/DefaultGeorectified.java  | 10 +--
 .../iso/spatial/DefaultGeoreferenceable.java       |  8 +--
 .../spatial/DefaultGridSpatialRepresentation.java  | 17 +++--
 .../DefaultVectorSpatialRepresentation.java        |  2 +-
 .../apache/sis/metadata/sql/MetadataFallback.java  |  8 ++-
 .../sis/metadata/iso/ImmutableIdentifierTest.java  |  5 +-
 .../sis/metadata/iso/citation/CitationsTest.java   |  2 +
 .../sis/metadata/sql/MetadataSourceTest.java       | 44 ++++++++----
 .../apache/sis/test/suite/MetadataTestSuite.java   |  4 +-
 97 files changed, 492 insertions(+), 373 deletions(-)


[sis] 01/02: Move CitationsTest down in the test dependencies because the constants now depend on SQL storage.

Posted by de...@apache.org.
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 f87e4f0cc09fbf36703c4ffda50d9688ef2dd028
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jul 25 19:38:33 2018 +0200

    Move CitationsTest down in the test dependencies because the constants now depend on SQL storage.
---
 .../sis/metadata/iso/ImmutableIdentifierTest.java  |  5 +--
 .../sis/metadata/iso/citation/CitationsTest.java   |  2 +
 .../sis/metadata/sql/MetadataSourceTest.java       | 44 ++++++++++++++++------
 .../apache/sis/test/suite/MetadataTestSuite.java   |  4 +-
 4 files changed, 37 insertions(+), 18 deletions(-)

diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java
index 6623188..b9df3c7 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/ImmutableIdentifierTest.java
@@ -45,10 +45,7 @@ import static org.opengis.metadata.Identifier.*;
  * @since   0.3
  * @module
  */
-@DependsOn({
-    DefaultIdentifierTest.class,
-    org.apache.sis.metadata.iso.citation.CitationsTest.class
-})
+@DependsOn(DefaultIdentifierTest.class)
 public final strictfp class ImmutableIdentifierTest extends TestCase {
     /**
      * Returns the properties map to be used in argument to test methods.
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
index 776eb4b..aa32db5 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/iso/citation/CitationsTest.java
@@ -29,6 +29,7 @@ import org.apache.sis.internal.simple.SimpleCitation;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.xml.IdentifierSpace;
 import org.apache.sis.test.DependsOnMethod;
+import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 
@@ -45,6 +46,7 @@ import static org.apache.sis.test.MetadataAssert.*;
  * @since   0.6
  * @module
  */
+@DependsOn(org.apache.sis.metadata.sql.MetadataSourceTest.class)
 public final strictfp class CitationsTest extends TestCase {
     /**
      * Verifies that {@link Citations#values()} is complete by comparing with the list
diff --git a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java
index dcca10d..2b8236b 100644
--- a/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java
+++ b/core/sis-metadata/src/test/java/org/apache/sis/metadata/sql/MetadataSourceTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.metadata.sql;
 
+import java.util.Collection;
 import java.util.Collections;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.metadata.distribution.Format;
@@ -51,15 +52,8 @@ public final strictfp class MetadataSourceTest extends TestCase {
      */
     @Test
     public void testOnDerby() throws Exception {
-        try (TestDatabase db = TestDatabase.create("MetadataSource");
-             MetadataSource source = new MetadataSource(MetadataStandard.ISO_19115, db.source, "metadata", null))
-        {
-            source.install();
-            verifyFormats(source);
-            testSearch(source);
-
-            // Opportunistic verification using the database we have at hand.
-            MetadataFallbackVerifier.compare(source);
+        try (TestDatabase db = TestDatabase.create("MetadataSource")) {
+            testAll(db);
         }
     }
 
@@ -70,12 +64,23 @@ public final strictfp class MetadataSourceTest extends TestCase {
      */
     @Test
     public void testOnPostgreSQL() throws Exception {
-        try (TestDatabase db = TestDatabase.createOnPostgreSQL("metadata", false);
-             MetadataSource source = new MetadataSource(MetadataStandard.ISO_19115, db.source, "metadata", null))
-        {
+        try (TestDatabase db = TestDatabase.createOnPostgreSQL("metadata", false)) {
+            testAll(db);
+        }
+    }
+
+    /**
+     * Runs all public tests declared in this class.
+     * Also opportunistically run tests declared in {@link MetadataFallbackVerifier}.
+     */
+    private static void testAll(final TestDatabase db) throws Exception {
+        try (MetadataSource source = new MetadataSource(MetadataStandard.ISO_19115, db.source, "metadata", null)) {
             source.install();
             verifyFormats(source);
             testSearch(source);
+            testEmptyCollection(source);
+
+            // Opportunistic verification using the database we have at hand.
             MetadataFallbackVerifier.compare(source);
         }
     }
@@ -127,4 +132,19 @@ public final strictfp class MetadataSourceTest extends TestCase {
         specification.setTitle(null);
         assertNull(source.search(format));
     }
+
+    /**
+     * Verifies that empty collections are empty, not-null.
+     *
+     * @param  source  the instance to test.
+     * @throws MetadataStoreException if an error occurred while querying the database.
+     */
+    @TestStep
+    public static void testEmptyCollection(final MetadataSource source) throws MetadataStoreException {
+        final Citation c = source.lookup(Citation.class, "SIS");
+        final Collection<?> details = c.getOtherCitationDetails();
+        assertNotNull("Empty collection should not be null.", details);
+        assertTrue("Expected an empty collection.", details.isEmpty());
+        assertSame("Collection shall be unmodifiable.", Collections.EMPTY_LIST, details);
+    }
 }
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 8701cc7..cd803d0 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
@@ -103,7 +103,6 @@ import org.junit.BeforeClass;
     org.apache.sis.metadata.iso.citation.DefaultResponsibilityTest.class,
     org.apache.sis.metadata.iso.citation.DefaultCitationDateTest.class,
     org.apache.sis.metadata.iso.citation.DefaultCitationTest.class,
-    org.apache.sis.metadata.iso.citation.CitationsTest.class,
     org.apache.sis.metadata.iso.maintenance.DefaultScopeDescriptionTest.class,
     org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBoxTest.class,
     org.apache.sis.metadata.iso.extent.DefaultExtentTest.class,
@@ -142,7 +141,8 @@ import org.junit.BeforeClass;
     org.apache.sis.internal.metadata.sql.ScriptRunnerTest.class,
     org.apache.sis.metadata.sql.IdentifierGeneratorTest.class,
     org.apache.sis.metadata.sql.MetadataSourceTest.class,
-    org.apache.sis.metadata.sql.MetadataWriterTest.class
+    org.apache.sis.metadata.sql.MetadataWriterTest.class,
+    org.apache.sis.metadata.iso.citation.CitationsTest.class
 })
 public final strictfp class MetadataTestSuite extends TestSuite {
     /**


[sis] 02/02: Introduce a new State mode: COMPLETABLE.

Posted by de...@apache.org.
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 5d6255e17e80f91723734d7e92f6fc739f4e7f77
Author: Martin Desruisseaux <ma...@geomatys.com>
AuthorDate: Wed Jul 25 19:39:32 2018 +0200

    Introduce a new State mode: COMPLETABLE.
---
 .../sis/internal/metadata/MetadataUtilities.java   | 24 ++++++-
 .../apache/sis/metadata/ModifiableMetadata.java    | 81 +++++++++++++++-------
 .../iso/DefaultApplicationSchemaInformation.java   | 14 ++--
 .../iso/DefaultExtendedElementInformation.java     | 22 +++---
 .../apache/sis/metadata/iso/DefaultIdentifier.java | 10 +--
 .../apache/sis/metadata/iso/DefaultMetadata.java   | 21 +++---
 .../iso/DefaultMetadataExtensionInformation.java   |  4 +-
 .../sis/metadata/iso/DefaultMetadataScope.java     |  4 +-
 .../org/apache/sis/metadata/iso/ISOMetadata.java   |  2 +-
 .../acquisition/DefaultAcquisitionInformation.java |  2 +-
 .../acquisition/DefaultEnvironmentalRecord.java    |  8 +--
 .../sis/metadata/iso/acquisition/DefaultEvent.java |  8 +--
 .../iso/acquisition/DefaultInstrument.java         |  6 +-
 .../metadata/iso/acquisition/DefaultObjective.java |  2 +-
 .../metadata/iso/acquisition/DefaultOperation.java | 12 ++--
 .../sis/metadata/iso/acquisition/DefaultPlan.java  |  6 +-
 .../metadata/iso/acquisition/DefaultPlatform.java  |  4 +-
 .../iso/acquisition/DefaultPlatformPass.java       |  2 +-
 .../iso/acquisition/DefaultRequestedDate.java      |  5 +-
 .../iso/acquisition/DefaultRequirement.java        |  9 +--
 .../sis/metadata/iso/citation/AbstractParty.java   |  2 +-
 .../sis/metadata/iso/citation/DefaultAddress.java  |  8 +--
 .../sis/metadata/iso/citation/DefaultCitation.java | 26 ++++---
 .../metadata/iso/citation/DefaultCitationDate.java |  5 +-
 .../sis/metadata/iso/citation/DefaultContact.java  |  4 +-
 .../metadata/iso/citation/DefaultIndividual.java   |  2 +-
 .../iso/citation/DefaultOnlineResource.java        | 14 ++--
 .../iso/citation/DefaultResponsibility.java        |  2 +-
 .../iso/citation/DefaultResponsibleParty.java      |  4 +-
 .../sis/metadata/iso/citation/DefaultSeries.java   |  6 +-
 .../metadata/iso/citation/DefaultTelephone.java    |  4 +-
 .../iso/constraint/DefaultConstraints.java         |  4 +-
 .../iso/constraint/DefaultReleasability.java       |  2 +-
 .../iso/constraint/DefaultSecurityConstraints.java |  8 +--
 .../sis/metadata/iso/content/DefaultBand.java      | 16 ++---
 .../iso/content/DefaultCoverageDescription.java    |  8 +--
 .../DefaultFeatureCatalogueDescription.java        |  6 +-
 .../iso/content/DefaultFeatureTypeInfo.java        |  4 +-
 .../iso/content/DefaultImageDescription.java       | 22 +++---
 .../iso/content/DefaultRangeDimension.java         |  4 +-
 .../content/DefaultRangeElementDescription.java    |  4 +-
 .../iso/content/DefaultSampleDimension.java        | 26 +++----
 .../metadata/iso/distribution/DefaultDataFile.java |  8 +--
 .../DefaultDigitalTransferOptions.java             |  6 +-
 .../iso/distribution/DefaultDistribution.java      |  2 +-
 .../iso/distribution/DefaultDistributor.java       |  2 +-
 .../metadata/iso/distribution/DefaultFormat.java   | 12 ++--
 .../metadata/iso/distribution/DefaultMedium.java   | 10 +--
 .../distribution/DefaultStandardOrderProcess.java  | 14 ++--
 .../iso/extent/AbstractGeographicExtent.java       |  2 +-
 .../sis/metadata/iso/extent/DefaultExtent.java     | 15 +++-
 .../iso/extent/DefaultGeographicBoundingBox.java   | 34 +++++----
 .../iso/extent/DefaultGeographicDescription.java   |  2 +-
 .../iso/extent/DefaultSpatialTemporalExtent.java   |  4 +-
 .../metadata/iso/extent/DefaultTemporalExtent.java |  6 +-
 .../metadata/iso/extent/DefaultVerticalExtent.java | 18 +++--
 .../iso/identification/AbstractIdentification.java |  8 +--
 .../DefaultAggregateInformation.java               |  2 +-
 .../identification/DefaultAssociatedResource.java  |  8 +--
 .../iso/identification/DefaultBrowseGraphic.java   |  6 +-
 .../iso/identification/DefaultCoupledResource.java |  8 +--
 .../identification/DefaultDataIdentification.java  |  4 +-
 .../iso/identification/DefaultKeywordClass.java    |  6 +-
 .../iso/identification/DefaultKeywords.java        |  6 +-
 .../DefaultOperationChainMetadata.java             |  4 +-
 .../identification/DefaultOperationMetadata.java   |  6 +-
 .../iso/identification/DefaultResolution.java      |  2 +-
 .../DefaultServiceIdentification.java              |  6 +-
 .../metadata/iso/identification/DefaultUsage.java  |  9 +--
 .../sis/metadata/iso/lineage/DefaultAlgorithm.java |  4 +-
 .../sis/metadata/iso/lineage/DefaultLineage.java   |  4 +-
 .../iso/lineage/DefaultNominalResolution.java      |  4 +-
 .../metadata/iso/lineage/DefaultProcessStep.java   | 10 +--
 .../iso/lineage/DefaultProcessStepReport.java      |  6 +-
 .../metadata/iso/lineage/DefaultProcessing.java    |  4 +-
 .../sis/metadata/iso/lineage/DefaultSource.java    | 18 ++---
 .../maintenance/DefaultMaintenanceInformation.java | 10 +--
 .../sis/metadata/iso/maintenance/DefaultScope.java |  2 +-
 .../iso/maintenance/DefaultScopeDescription.java   |  4 +-
 .../sis/metadata/iso/quality/AbstractElement.java  | 12 ++--
 .../iso/quality/DefaultConformanceResult.java      |  6 +-
 .../iso/quality/DefaultCoverageResult.java         | 10 +--
 .../metadata/iso/quality/DefaultDataQuality.java   |  4 +-
 .../iso/quality/DefaultQuantitativeResult.java     |  6 +-
 .../sis/metadata/iso/spatial/DefaultDimension.java | 12 ++--
 .../sis/metadata/iso/spatial/DefaultGCP.java       |  2 +-
 .../metadata/iso/spatial/DefaultGCPCollection.java |  6 +-
 .../iso/spatial/DefaultGeometricObjects.java       |  4 +-
 .../metadata/iso/spatial/DefaultGeorectified.java  | 10 +--
 .../iso/spatial/DefaultGeoreferenceable.java       |  8 +--
 .../spatial/DefaultGridSpatialRepresentation.java  | 17 +++--
 .../DefaultVectorSpatialRepresentation.java        |  2 +-
 .../apache/sis/metadata/sql/MetadataFallback.java  |  8 ++-
 93 files changed, 455 insertions(+), 355 deletions(-)

diff --git a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java
index 972ce6c..3843385 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/MetadataUtilities.java
@@ -31,7 +31,7 @@ import org.apache.sis.internal.util.Utilities;
  * Miscellaneous utility methods for metadata.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 0.8
+ * @version 1.0
  * @since   0.3
  * @module
  *
@@ -68,6 +68,28 @@ public final class MetadataUtilities extends Static {
     }
 
     /**
+     * Returns {@link Boolean#TRUE} if the given value is a valid date, or {@code null} otherwise.
+     * This method is used for calls to {@code checkWritePermission(Object)}. The use of a boolean
+     * as return type is for avoiding to create new {@link Date} instances.
+     *
+     * @param  value  the time in milliseconds.
+     * @return {@code Boolean.TRUE} if the given value is a valid date.
+     */
+    public static Boolean isDateDefined(final long value) {
+        return (value != Long.MIN_VALUE) ? Boolean.TRUE : null;
+    }
+
+    /**
+     * Returns {@link Boolean#TRUE} if the given value is a valid double, or {@code null} if NaN.
+     *
+     * @param  value  the numeric value.
+     * @return {@code Boolean.TRUE} if the given value is non-NaN.
+     */
+    public static Boolean isDefined(final double value) {
+        return Double.isNaN(value) ? null : Boolean.TRUE;
+    }
+
+    /**
      * Ensures that the given property value is positive. If the user gave a negative value or (in some case) zero,
      * then this method logs a warning if we are in process of (un)marshalling a XML document or throw an exception
      * otherwise.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
index ceecee1..538ba9b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/ModifiableMetadata.java
@@ -98,9 +98,10 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
     private static final byte EDITABLE = 0;
 
     /**
-     * A bitmask for {@link #state} meaning that {@code apply(State.FINAL)} has been invoked.
+     * The {@link #state} value meaning that missing properties can be set,
+     * but no existing properties can be modified (including collections).
      */
-    private static final byte FINAL = 1;
+    private static final byte COMPLETABLE = 1;
 
     /**
      * See https://issues.apache.org/jira/browse/SIS-81 - not yet committed.
@@ -109,8 +110,15 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
 
     /**
      * A value for {@link #state} meaning that execution of {@code apply(State.FINAL)} is in progress.
+     * Must be greater than all other values except {@link #FINAL}.
      */
-    private static final byte FREEZING = FINAL | STAGED;
+    private static final byte FREEZING = 3;
+
+    /**
+     * A value for {@link #state} meaning that {@code apply(State.FINAL)} has been invoked.
+     * Must be greater than all other values.
+     */
+    private static final byte FINAL = 4;
 
     /**
      * Whether this metadata has been made unmodifiable, as one of {@link #EDITABLE}, {@link #FREEZING}
@@ -163,6 +171,12 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
         EDITABLE,
 
         /**
+         * The metadata allows missing values to be set, but does not allow existing values to be modified.
+         * This state is not appendable, i.e. it does not allow adding elements in a collection.
+         */
+        COMPLETABLE,
+
+        /**
          * The metadata is unmodifiable.
          * When a metadata is final, it can not be moved back to an editable state
          * (but it is still possible to create a modifiable copy with {@link MetadataCopier}).
@@ -176,12 +190,13 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
          * A mapping exists because {@code ModifiableMetadata} does not use the same set of enumeration values
          * (e.g. it has an internal {@link #FREEZING} value), and because future versions may use a bitmask.
          */
-        private static final State[] VALUES = new State[ModifiableMetadata.FREEZING + 1];
+        private static final State[] VALUES = new State[ModifiableMetadata.FINAL + 1];
         static {
-            VALUES[ModifiableMetadata.EDITABLE] = EDITABLE;
-            VALUES[ModifiableMetadata.STAGED]   = EDITABLE;
-            VALUES[ModifiableMetadata.FREEZING] = FINAL;
-            VALUES[ModifiableMetadata.FINAL]    = FINAL;
+            VALUES[ModifiableMetadata.EDITABLE]    = EDITABLE;
+            VALUES[ModifiableMetadata.COMPLETABLE] = COMPLETABLE;
+            VALUES[ModifiableMetadata.STAGED]      = EDITABLE;
+            VALUES[ModifiableMetadata.FREEZING]    = FINAL;
+            VALUES[ModifiableMetadata.FINAL]       = FINAL;
         }
     }
 
@@ -246,11 +261,11 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
     public boolean transition(final State target) {
         switch (target) {
             case EDITABLE: {
-                if ((state & FINAL) == 0) break;
+                if (state == EDITABLE) break;
                 throw new UnmodifiableMetadataException(Errors.format(Errors.Keys.UnmodifiableMetadata));
             }
             case FINAL: {
-                if ((state & FINAL) != 0) break;
+                if (state >= FREEZING) break;
                 byte result = state;
                 try {
                     state = FREEZING;
@@ -279,7 +294,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
      */
     @Deprecated
     public final boolean isModifiable() {
-        return (state & FINAL) == 0;
+        return state < FREEZING;
     }
 
     /**
@@ -317,7 +332,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
      */
     @Deprecated
     public AbstractMetadata unmodifiable() {
-        if ((state & FINAL) != 0) {
+        if (!isModifiable()) {
             unmodifiable = this;
         }
         /*
@@ -358,13 +373,11 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
     }
 
     /**
-     * Checks if changes in the metadata are allowed. All {@code setFoo(…)} methods in subclasses
-     * shall invoke this method (directly or indirectly) before to apply any change.
+     * @deprecated Replaced by {@link #checkWritePermission(Object)}.
      *
      * @throws UnmodifiableMetadataException if this metadata is unmodifiable.
-     *
-     * @see #state()
      */
+    @Deprecated
     protected void checkWritePermission() throws UnmodifiableMetadataException {
         if (state == FINAL) {
             throw new UnmodifiableMetadataException(Errors.format(Errors.Keys.UnmodifiableMetadata));
@@ -374,11 +387,29 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
     }
 
     /**
+     * Checks if changes in the metadata are allowed. All {@code setFoo(…)} methods in subclasses
+     * shall invoke this method (directly or indirectly) before to apply any change.
+     * The current property value should be specified in argument.
+     *
+     * @param  current  the current value, or {@code null} if none.
+     * @throws UnmodifiableMetadataException if this metadata is unmodifiable.
+     *
+     * @see #state()
+     */
+    protected void checkWritePermission(final Object current) throws UnmodifiableMetadataException {
+        if (state != COMPLETABLE) {
+            checkWritePermission();
+        } else if (current != null) {
+            throw new UnmodifiableMetadataException(Errors.format(Errors.Keys.UnmodifiableMetadata));
+        }
+    }
+
+    /**
      * Writes the content of the {@code source} collection into the {@code target} list,
      * creating it if needed. This method performs the following steps:
      *
      * <ul>
-     *   <li>Invokes {@link #checkWritePermission()} in order to ensure that this metadata is modifiable.</li>
+     *   <li>Invokes {@link #checkWritePermission(Object)} in order to ensure that this metadata is modifiable.</li>
      *   <li>If {@code source} is null or empty, returns {@code null}
      *       (meaning that the metadata property is not provided).</li>
      *   <li>If {@code target} is null, creates a new {@link List}.</li>
@@ -405,7 +436,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
             if (state == FREEZING) {
                 return (List<E>) source;
             }
-            checkWritePermission();
+            checkWritePermission(target);
             if (isNullOrEmpty(source)) {
                 target = null;
             } else {
@@ -425,7 +456,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
      * creating it if needed. This method performs the following steps:
      *
      * <ul>
-     *   <li>Invokes {@link #checkWritePermission()} in order to ensure that this metadata is modifiable.</li>
+     *   <li>Invokes {@link #checkWritePermission(Object)} in order to ensure that this metadata is modifiable.</li>
      *   <li>If {@code source} is null or empty, returns {@code null}
      *       (meaning that the metadata property is not provided).</li>
      *   <li>If {@code target} is null, creates a new {@link Set}.</li>
@@ -452,7 +483,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
             if (state == FREEZING) {
                 return (Set<E>) source;
             }
-            checkWritePermission();
+            checkWritePermission(target);
             if (isNullOrEmpty(source)) {
                 target = null;
             } else {
@@ -472,7 +503,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
      * creating it if needed. This method performs the following steps:
      *
      * <ul>
-     *   <li>Invokes {@link #checkWritePermission()} in order to ensure that this metadata is modifiable.</li>
+     *   <li>Invokes {@link #checkWritePermission(Object)} in order to ensure that this metadata is modifiable.</li>
      *   <li>If {@code source} is null or empty, returns {@code null}
      *       (meaning that the metadata property is not provided).</li>
      *   <li>If {@code target} is null, creates a new {@link Set} or a new {@link List}
@@ -515,7 +546,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
                 assert collectionType(elementType).isInstance(source);
                 return (Collection<E>) source;
             }
-            checkWritePermission();
+            checkWritePermission(target);
             if (isNullOrEmpty(source)) {
                 target = null;
             } else {
@@ -658,7 +689,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
         if (emptyCollectionAsNull()) {
             return null;
         }
-        if ((state & FINAL) == 0) {
+        if (state < FREEZING) {
             /*
              * Do not specify an initial capacity, because the list will stay empty in a majority of cases
              * (i.e. the users will want to iterate over the list elements more often than they will want
@@ -687,7 +718,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
         if (emptyCollectionAsNull()) {
             return null;
         }
-        if ((state & FINAL) == 0) {
+        if (state < FREEZING) {
             return createSet(elementType, INITIAL_CAPACITY);
         }
         return Collections.emptySet();
@@ -717,7 +748,7 @@ public abstract class ModifiableMetadata extends AbstractMetadata {
         if (emptyCollectionAsNull()) {
             return null;
         }
-        final boolean isModifiable = (state & FINAL) == 0;
+        final boolean isModifiable = (state < FREEZING);
         if (useSet(elementType)) {
             if (isModifiable) {
                 return createSet(elementType, INITIAL_CAPACITY);
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 56d30d9..14bcb47 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
@@ -193,7 +193,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new name.
      */
     public void setName(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -214,7 +214,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new schema language.
      */
     public void setSchemaLanguage(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(schemaLanguage);
         schemaLanguage = newValue;
     }
 
@@ -235,7 +235,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new constraint language.
      */
     public void setConstraintLanguage(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(constraintLanguage);
         constraintLanguage = newValue;
     }
 
@@ -257,7 +257,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new ASCII file.
      */
     public void setSchemaAscii(final CharSequence newValue) {
-        checkWritePermission();
+        checkWritePermission(schemaAscii);
         schemaAscii = newValue;
     }
 
@@ -279,7 +279,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new graphics file.
      */
     public void setGraphicsFile(final OnlineResource newValue) {
-        checkWritePermission();
+        checkWritePermission(graphicsFile);
         graphicsFile = newValue;
     }
 
@@ -301,7 +301,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new software development file.
      */
     public void setSoftwareDevelopmentFile(final OnlineResource newValue) {
-        checkWritePermission();
+        checkWritePermission(softwareDevelopmentFile);
         softwareDevelopmentFile = newValue;
     }
 
@@ -322,7 +322,7 @@ public class DefaultApplicationSchemaInformation extends ISOMetadata implements
      * @param  newValue  the new software development file format.
      */
     public void setSoftwareDevelopmentFileFormat(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(softwareDevelopmentFileFormat);
         softwareDevelopmentFileFormat = 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 56cbf06..450c8d8 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
@@ -294,7 +294,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new name.
      */
     public void setName(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -321,7 +321,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      */
     @Deprecated
     public void setShortName(final String newValue)  {
-        checkWritePermission();
+        checkWritePermission(shortName);
         shortName = newValue;
     }
 
@@ -350,7 +350,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      */
     @Deprecated
     public void setDomainCode(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(domainCode);
         domainCode = newValue;
     }
 
@@ -371,7 +371,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new definition.
      */
     public void setDefinition(final InternationalString newValue)  {
-        checkWritePermission();
+        checkWritePermission(definition);
         definition = newValue;
     }
 
@@ -392,7 +392,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new obligation.
      */
     public void setObligation(final Obligation newValue)  {
-        checkWritePermission();
+        checkWritePermission(obligation);
         obligation = newValue;
     }
 
@@ -415,7 +415,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new condition.
      */
     public void setCondition(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(condition);
         condition = newValue;
     }
 
@@ -436,7 +436,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new data type.
      */
     public void setDataType(final Datatype newValue) {
-        checkWritePermission();
+        checkWritePermission(dataType);
         dataType = newValue;
     }
 
@@ -462,7 +462,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setMaximumOccurrence(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(maximumOccurrence);
         if (ensurePositive(DefaultExtendedElementInformation.class, "maximumOccurrence", false, newValue)) {
             maximumOccurrence = newValue;
         }
@@ -489,7 +489,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new domain value.
      */
     public void setDomainValue(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(domainValue);
         domainValue = newValue;
     }
 
@@ -531,7 +531,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @param  newValue  the new rule.
      */
     public void setRule(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(rule);
         rule = newValue;
     }
 
@@ -556,7 +556,7 @@ public class DefaultExtendedElementInformation extends ISOMetadata implements Ex
      * @since 0.5
      */
     public void setRationale(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(rationale);
         rationale = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
index 6ba134a..c1ca67d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultIdentifier.java
@@ -251,7 +251,7 @@ public class DefaultIdentifier extends ISOMetadata implements Identifier {
      * @param  newValue  the new authority.
      */
     public void setAuthority(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(authority);
         authority = newValue;
     }
 
@@ -279,7 +279,7 @@ public class DefaultIdentifier extends ISOMetadata implements Identifier {
      * @param  newValue  the new code, or {@code null}.
      */
     public void setCode(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(code);
         code = newValue;
     }
 
@@ -307,7 +307,7 @@ public class DefaultIdentifier extends ISOMetadata implements Identifier {
      * @since 0.5
      */
     public void setCodeSpace(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(codeSpace);
         codeSpace = newValue;
     }
 
@@ -332,7 +332,7 @@ public class DefaultIdentifier extends ISOMetadata implements Identifier {
      * @param  newValue  the new version, or {@code null} if none.
      */
     public void setVersion(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(version);
         version = newValue;
     }
 
@@ -359,7 +359,7 @@ public class DefaultIdentifier extends ISOMetadata implements Identifier {
      * @since 0.5
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 }
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 6635325..bc0e1f8 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
@@ -545,7 +545,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      */
     @Deprecated
     public void setLanguage(final Locale newValue) {
-        checkWritePermission();
+        checkWritePermission(languages);
         setDefaultLocale(newValue);
     }
 
@@ -573,7 +573,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      */
     @Deprecated
     public void setLocales(final Collection<? extends Locale> newValues) {
-        checkWritePermission();
+        checkWritePermission(languages);
         setOtherLocales(newValues);
     }
 
@@ -684,7 +684,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      * @since 0.5
      */
     public void setParentMetadata(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(parentMetadata);
         parentMetadata = newValue;
     }
 
@@ -721,7 +721,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      */
     @Deprecated
     public void setParentIdentifier(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(parentMetadata);
         // See "Note about deprecated methods implementation"
         DefaultCitation parent = DefaultCitation.castOrCopy(parentMetadata);
         if (parent == null) {
@@ -801,7 +801,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      */
     @Deprecated
     public void setHierarchyLevels(final Collection<? extends ScopeCode> newValues) {
-        checkWritePermission();
+        checkWritePermission(metadataScopes);
         ((LegacyPropertyAdapter<ScopeCode,?>) getHierarchyLevels()).setValues(newValues);
     }
 
@@ -852,7 +852,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      */
     @Deprecated
     public void setHierarchyLevelNames(final Collection<? extends String> newValues) {
-        checkWritePermission();
+        checkWritePermission(metadataScopes);
         ((LegacyPropertyAdapter<String,?>) getHierarchyLevelNames()).setValues(newValues);
     }
 
@@ -873,7 +873,6 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      * @param  newValues  the new contacts.
      */
     public void setContacts(final Collection<? extends Responsibility> newValues) {
-        checkWritePermission();
         contacts = writeCollection(newValues, contacts, Responsibility.class);
     }
 
@@ -938,7 +937,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      */
     @Deprecated
     public void setDateStamp(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(dateInfo);
         Collection<CitationDate> newValues = dateInfo;      // See "Note about deprecated methods implementation"
         if (newValues == null) {
             if (newValue == null) {
@@ -1071,7 +1070,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      * {@link #setMetadataStandardVersion(String)} methods.
      */
     private void setMetadataStandard(final boolean version, final String newValue) {
-        checkWritePermission();
+        checkWritePermission(metadataStandards);
         final InternationalString i18n = (newValue != null) ? new SimpleInternationalString(newValue) : null;
         final List<Citation> newValues = (metadataStandards != null)
                 ? new ArrayList<>(metadataStandards)
@@ -1229,7 +1228,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
     @Deprecated
     public void setDataSetUri(final String newValue) throws URISyntaxException {
         final URI uri = new URI(newValue);
-        checkWritePermission();
+        checkWritePermission(identificationInfo);
         Collection<Identification> info = identificationInfo; // See "Note about deprecated methods implementation"
         AbstractIdentification firstId = AbstractIdentification.castOrCopy(CollectionsExt.first(info));
         if (firstId == null) {
@@ -1499,7 +1498,7 @@ public class DefaultMetadata extends ISOMetadata implements Metadata {
      * @see org.apache.sis.metadata.iso.identification.AbstractIdentification#setResourceMaintenances(Collection)
      */
     public void setMetadataMaintenance(final MaintenanceInformation newValue) {
-        checkWritePermission();
+        checkWritePermission(metadataMaintenance);
         metadataMaintenance = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataExtensionInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataExtensionInformation.java
index 14f74b4..b5b7366 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataExtensionInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataExtensionInformation.java
@@ -135,8 +135,8 @@ public class DefaultMetadataExtensionInformation extends ISOMetadata implements
      * @param  newValue  the new extension online resource.
      */
     public void setExtensionOnLineResource(final OnlineResource newValue) {
-        checkWritePermission();
-        this.extensionOnLineResource = newValue;
+        checkWritePermission(extensionOnLineResource);
+        extensionOnLineResource = newValue;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java
index 7236046..1e0a4dd 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/DefaultMetadataScope.java
@@ -144,7 +144,7 @@ public class DefaultMetadataScope extends ISOMetadata implements MetadataScope {
      * @param  newValue  the new code for the scope.
      */
     public void setResourceScope(final ScopeCode newValue) {
-        checkWritePermission();
+        checkWritePermission(resourceScope);
         resourceScope = newValue;
     }
 
@@ -165,7 +165,7 @@ public class DefaultMetadataScope extends ISOMetadata implements MetadataScope {
      * @param  newValue  the new description of the scope.
      */
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
index 45ccb67..77408e3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ISOMetadata.java
@@ -206,7 +206,7 @@ public class ISOMetadata extends ModifiableMetadata implements IdentifiedObject,
      * @since 1.0
      */
     protected void setIdentifier(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(identifiers);
         identifiers = nonNullCollection(identifiers, Identifier.class);
         identifiers = writeCollection(NonMarshalledAuthority.setMarshallable(identifiers, newValue), identifiers, Identifier.class);
     }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultAcquisitionInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultAcquisitionInformation.java
index e5e646c..c260bd7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultAcquisitionInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultAcquisitionInformation.java
@@ -212,7 +212,7 @@ public class DefaultAcquisitionInformation extends ISOMetadata implements Acquis
      * @param  newValue  the new environmental record value.
      */
     public void setEnvironmentalConditions(final EnvironmentalRecord newValue) {
-        checkWritePermission();
+        checkWritePermission(environmentalConditions);
         environmentalConditions = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java
index abe4cef..97b1cec 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEnvironmentalRecord.java
@@ -159,7 +159,7 @@ public class DefaultEnvironmentalRecord extends ISOMetadata implements Environme
      * @param  newValue  the new average air temperature value.
      */
     public void setAverageAirTemperature(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(averageAirTemperature);
         averageAirTemperature = newValue;
     }
 
@@ -182,7 +182,7 @@ public class DefaultEnvironmentalRecord extends ISOMetadata implements Environme
      * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setMaxRelativeHumidity(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(maxRelativeHumidity);
         if (ensureInRange(DefaultEnvironmentalRecord.class, "maxRelativeHumidity", 0, 100, newValue)) {
             maxRelativeHumidity = newValue;
         }
@@ -205,7 +205,7 @@ public class DefaultEnvironmentalRecord extends ISOMetadata implements Environme
      * @param  newValue  the new maximum altitude value.
      */
     public void setMaxAltitude(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(maxAltitude);
         maxAltitude = newValue;
     }
 
@@ -226,7 +226,7 @@ public class DefaultEnvironmentalRecord extends ISOMetadata implements Environme
      * @param  newValue  the meteorological conditions value.
      */
     public void setMeteorologicalConditions(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(meteorologicalConditions);
         meteorologicalConditions = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEvent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEvent.java
index b1ffe20..d75389d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEvent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultEvent.java
@@ -206,7 +206,7 @@ public class DefaultEvent extends ISOMetadata implements Event {
      * @param  newValue  the new trigger value.
      */
     public void setTrigger(final Trigger newValue) {
-        checkWritePermission();
+        checkWritePermission(trigger);
         trigger = newValue;
     }
 
@@ -227,7 +227,7 @@ public class DefaultEvent extends ISOMetadata implements Event {
      * @param  newValue  the new context value.
      */
     public void setContext(final Context newValue) {
-        checkWritePermission();
+        checkWritePermission(context);
         context = newValue;
     }
 
@@ -248,7 +248,7 @@ public class DefaultEvent extends ISOMetadata implements Event {
      * @param  newValue  the new sequence value.
      */
     public void setSequence(final Sequence newValue) {
-        checkWritePermission();
+        checkWritePermission(sequence);
         sequence = newValue;
     }
 
@@ -269,7 +269,7 @@ public class DefaultEvent extends ISOMetadata implements Event {
      * @param  newValue  the new time value.
      */
     public void setTime(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(time);
         time = toMilliseconds(newValue);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultInstrument.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultInstrument.java
index 9ef0545..b9a49b6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultInstrument.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultInstrument.java
@@ -195,7 +195,7 @@ public class DefaultInstrument extends ISOMetadata implements Instrument {
      * @param  newValue  the new type value.
      */
     public void setType(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(type);
         type = newValue;
     }
 
@@ -216,7 +216,7 @@ public class DefaultInstrument extends ISOMetadata implements Instrument {
      * @param  newValue  the new description value.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -237,7 +237,7 @@ public class DefaultInstrument extends ISOMetadata implements Instrument {
      * @param  newValue  the new platform value.
      */
     public void setMountedOn(final Platform newValue) {
-        checkWritePermission();
+        checkWritePermission(mountedOn);
         mountedOn = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java
index e51360e..d4a4bf6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultObjective.java
@@ -220,7 +220,7 @@ public class DefaultObjective extends ISOMetadata implements Objective {
      * @param  newValue  the new priority value.
      */
     public void setPriority(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(priority);
         priority = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultOperation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultOperation.java
index 425d859..2800bc6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultOperation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultOperation.java
@@ -204,7 +204,7 @@ public class DefaultOperation extends ISOMetadata implements Operation {
      * @param  newValue  the new description value.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -225,7 +225,7 @@ public class DefaultOperation extends ISOMetadata implements Operation {
      * @param  newValue  the new citation value.
      */
     public void setCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(citation);
         citation = newValue;
     }
 
@@ -267,7 +267,7 @@ public class DefaultOperation extends ISOMetadata implements Operation {
      * @param  newValue  the new status value.
      */
     public void setStatus(final Progress newValue) {
-        checkWritePermission();
+        checkWritePermission(status);
         status = newValue;
     }
 
@@ -288,7 +288,7 @@ public class DefaultOperation extends ISOMetadata implements Operation {
      * @param  newValue  the new type value.
      */
     public void setType(final OperationType newValue) {
-        checkWritePermission();
+        checkWritePermission(type);
         type = newValue;
     }
 
@@ -349,7 +349,7 @@ public class DefaultOperation extends ISOMetadata implements Operation {
      * @param  newValue  the new parent operation value.
      */
     public void setParentOperation(final Operation newValue) {
-        checkWritePermission();
+        checkWritePermission(parentOperation);
         parentOperation = newValue;
     }
 
@@ -370,7 +370,7 @@ public class DefaultOperation extends ISOMetadata implements Operation {
      * @param  newValue  the new plan value.
      */
     public void setPlan(final Plan newValue) {
-        checkWritePermission();
+        checkWritePermission(plan);
         plan = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlan.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlan.java
index 30311bf..23a4dd1 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlan.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlan.java
@@ -163,7 +163,7 @@ public class DefaultPlan extends ISOMetadata implements Plan {
      * @param  newValue  the new type value.
      */
     public void setType(final GeometryType newValue) {
-        checkWritePermission();
+        checkWritePermission(type);
         type = newValue;
     }
 
@@ -184,7 +184,7 @@ public class DefaultPlan extends ISOMetadata implements Plan {
      * @param  newValue  the new status value.
      */
     public void setStatus(final Progress newValue) {
-        checkWritePermission();
+        checkWritePermission(status);
         status = newValue;
     }
 
@@ -205,7 +205,7 @@ public class DefaultPlan extends ISOMetadata implements Plan {
      * @param  newValue  the new citation value.
      */
     public void setCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(citation);
         citation = newValue;
     }
 
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 34bed9c..6fae5c8 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
@@ -158,7 +158,7 @@ public class DefaultPlatform extends ISOMetadata implements Platform {
      * @param  newValue  the new citation value.
      */
     public void setCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(citation);
         citation = newValue;
     }
 
@@ -200,7 +200,7 @@ public class DefaultPlatform extends ISOMetadata implements Platform {
      * @param  newValue  the new description value.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatformPass.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatformPass.java
index 78a128a..8a05d43 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatformPass.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultPlatformPass.java
@@ -159,7 +159,7 @@ public class DefaultPlatformPass extends ISOMetadata implements PlatformPass {
      * @param  newValue  the new extent value.
      */
     public void setExtent(final Geometry newValue) {
-        checkWritePermission();
+        checkWritePermission(extent);
         extent = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequestedDate.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequestedDate.java
index 13bb801..661d337 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequestedDate.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/acquisition/DefaultRequestedDate.java
@@ -25,6 +25,7 @@ import org.apache.sis.metadata.iso.ISOMetadata;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
+import static org.apache.sis.internal.metadata.MetadataUtilities.isDateDefined;
 
 
 /**
@@ -138,7 +139,7 @@ public class DefaultRequestedDate extends ISOMetadata implements RequestedDate {
      * @param  newValue  the new requested date of collection value.
      */
     public void setRequestedDateOfCollection(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(isDateDefined(requestedDateOfCollection));
         requestedDateOfCollection = toMilliseconds(newValue);
     }
 
@@ -159,7 +160,7 @@ public class DefaultRequestedDate extends ISOMetadata implements RequestedDate {
      * @param  newValue  the new latest acceptable data value.
      */
     public void setLatestAcceptableDate(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(isDateDefined(latestAcceptableDate));
         latestAcceptableDate = toMilliseconds(newValue);
     }
 }
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 f7bbc0b..e83040b 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
@@ -32,6 +32,7 @@ import org.apache.sis.metadata.iso.ISOMetadata;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
+import static org.apache.sis.internal.metadata.MetadataUtilities.isDateDefined;
 
 
 /**
@@ -193,7 +194,7 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
      * @param  newValue  the new citation value.
      */
     public void setCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(citation);
         citation = newValue;
     }
 
@@ -275,7 +276,7 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
      * @param  newValue  the new priority value.
      */
     public void setPriority(final Priority newValue) {
-        checkWritePermission();
+        checkWritePermission(priority);
         priority = newValue;
     }
 
@@ -296,7 +297,7 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
      * @param  newValue  the new requested date value.
      */
     public void setRequestedDate(final RequestedDate newValue) {
-        checkWritePermission();
+        checkWritePermission(requestedDate);
         requestedDate = newValue;
     }
 
@@ -317,7 +318,7 @@ public class DefaultRequirement extends ISOMetadata implements Requirement {
      * @param  newValue  the new expiry date.
      */
     public void setExpiryDate(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(isDateDefined(expiryDate));
         expiryDate = toMilliseconds(newValue);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
index 2d1fef8..2bb73c7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/AbstractParty.java
@@ -166,7 +166,7 @@ public class AbstractParty extends ISOMetadata implements Party {
      * @param  newValue  the new name of the party.
      */
     public void setName(final InternationalString newValue) {
-       checkWritePermission();
+       checkWritePermission(name);
        name = newValue;
     }
 
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 72ba588..98e3be8 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
@@ -158,7 +158,7 @@ public class DefaultAddress extends ISOMetadata implements Address {
      * @param  newValue  the new administrative area.
      */
     public void setAdministrativeArea(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(administrativeArea);
         administrativeArea = newValue;
     }
 
@@ -179,7 +179,7 @@ public class DefaultAddress extends ISOMetadata implements Address {
      * @param  newValue  the new city, or {@code null} if none.
      */
     public void setCity(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(city);
         city = newValue;
     }
 
@@ -200,7 +200,7 @@ public class DefaultAddress extends ISOMetadata implements Address {
      * @param  newValue  the new country, or {@code null} if none.
      */
     public void setCountry(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(country);
         country = newValue;
     }
 
@@ -261,7 +261,7 @@ public class DefaultAddress extends ISOMetadata implements Address {
      * @param  newValue  the new postal code, or {@code null} if none.
      */
     public void setPostalCode(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(postalCode);
         postalCode = newValue;
     }
 }
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 f9fd71e..4608e1a 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
@@ -42,6 +42,7 @@ import org.apache.sis.xml.IdentifierMap;
 import static org.apache.sis.util.collection.Containers.isNullOrEmpty;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
+import static org.apache.sis.internal.metadata.MetadataUtilities.isDateDefined;
 
 
 /**
@@ -264,7 +265,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * @param  newValue  the new title, or {@code null} if none.
      */
     public void setTitle(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(title);
         title = newValue;
     }
 
@@ -327,7 +328,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * @param  newValue  the new edition, or {@code null} if none.
      */
     public void setEdition(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(edition);
         edition = newValue;
     }
 
@@ -348,7 +349,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * @param  newValue  the new edition date, or {@code null} if none.
      */
     public void setEditionDate(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(isDateDefined(editionDate));
         editionDate = toMilliseconds(newValue);
     }
 
@@ -456,7 +457,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * @param  newValue  the new series.
      */
     public void setSeries(final Series newValue) {
-        checkWritePermission();
+        checkWritePermission(series);
         series = newValue;
     }
 
@@ -504,11 +505,18 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      */
     @Deprecated
     public void setCollectiveTitle(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(collectiveTitle);
         collectiveTitle = newValue;
     }
 
     /**
+     * Returns the ISBN or ISSN identifier for the given authority, or {@code null} if none.
+     */
+    private String getIdentifier(final Citation authority) {
+        return isNullOrEmpty(identifiers) ? null : getIdentifierMap().get(authority);
+    }
+
+    /**
      * Returns the International Standard Book Number.
      * In this SIS implementation, invoking this method is equivalent to:
      *
@@ -524,7 +532,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
     @Override
     @XmlElement(name = "ISBN")
     public String getISBN() {
-        return isNullOrEmpty(identifiers) ? null : getIdentifierMap().get(Citations.ISBN);
+        return getIdentifier(Citations.ISBN);
     }
 
     /**
@@ -541,7 +549,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * @see Citations#ISBN
      */
     public void setISBN(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(getIdentifier(Citations.ISBN));
         if (newValue != null || !isNullOrEmpty(identifiers)) {
             getIdentifierMap().putSpecialized(Citations.ISBN, newValue);
         }
@@ -563,7 +571,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
     @Override
     @XmlElement(name = "ISSN")
     public String getISSN() {
-        return isNullOrEmpty(identifiers) ? null : getIdentifierMap().get(Citations.ISSN);
+        return getIdentifier(Citations.ISSN);
     }
 
     /**
@@ -580,7 +588,7 @@ public class DefaultCitation extends ISOMetadata implements Citation {
      * @see Citations#ISSN
      */
     public void setISSN(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(getIdentifier(Citations.ISSN));
         if (newValue != null || !isNullOrEmpty(identifiers)) {
             getIdentifierMap().putSpecialized(Citations.ISSN, newValue);
         }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java
index f863b29..a88c98a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultCitationDate.java
@@ -27,6 +27,7 @@ import org.apache.sis.metadata.TitleProperty;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
+import static org.apache.sis.internal.metadata.MetadataUtilities.isDateDefined;
 
 
 /**
@@ -151,7 +152,7 @@ public class DefaultCitationDate extends ISOMetadata implements CitationDate {
      * @param  newValue  the new date.
      */
     public void setDate(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(isDateDefined(date));
         date = toMilliseconds(newValue);
     }
 
@@ -172,7 +173,7 @@ public class DefaultCitationDate extends ISOMetadata implements CitationDate {
      * @param  newValue  the new event.
      */
     public void setDateType(final DateType newValue) {
-        checkWritePermission();
+        checkWritePermission(dateType);
         dateType = newValue;
     }
 }
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 2feb168..117d1bc 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
@@ -433,7 +433,7 @@ public class DefaultContact extends ISOMetadata implements Contact {
      * @param  newValue  the new contact instructions, or {@code null} if none.
      */
     public void setContactInstructions(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(contactInstructions);
         contactInstructions = newValue;
     }
 
@@ -460,7 +460,7 @@ public class DefaultContact extends ISOMetadata implements Contact {
      * @since 0.5
      */
     public void setContactType(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(contactType);
         contactType = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java
index ec1d72a..14449fe 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultIndividual.java
@@ -137,7 +137,7 @@ public class DefaultIndividual extends AbstractParty implements Individual {
      * @param  newValue  the new position of the individual in an organization.
      */
     public void setPositionName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(positionName);
         positionName = newValue;
     }
 }
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 90726bf..6d8f04d 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
@@ -188,7 +188,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @param  newValue  the new application profile.
      */
     public void setApplicationProfile(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(applicationProfile);
         applicationProfile = newValue;
     }
 
@@ -209,7 +209,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @param  newValue  the new name, or {@code null} if none.
      */
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -230,7 +230,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @param  newValue  the new description, or {@code null} if none.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -251,7 +251,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @param  newValue  the new function, or {@code null} if none.
      */
     public void setFunction(final OnLineFunction newValue) {
-        checkWritePermission();
+        checkWritePermission(function);
         function = newValue;
     }
 
@@ -275,7 +275,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @param  newValue  the new linkage, or {@code null} if none.
      */
     public void setLinkage(final URI newValue) {
-        checkWritePermission();
+        checkWritePermission(linkage);
         linkage = newValue;
     }
 
@@ -300,7 +300,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @param  newValue  the new protocol, or {@code null} if none.
      */
     public void setProtocol(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(protocol);
         protocol = newValue;
     }
 
@@ -337,7 +337,7 @@ public class DefaultOnlineResource extends ISOMetadata implements OnlineResource
      * @since 0.5
      */
     public void setProtocolRequest(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(protocolRequest);
         protocolRequest = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java
index b52c0e3..bb1fbf7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibility.java
@@ -170,7 +170,7 @@ public class DefaultResponsibility extends ISOMetadata implements Responsibility
      * @param  newValue  the new role, or {@code null} if none.
      */
     public void setRole(final Role newValue) {
-        checkWritePermission();
+        checkWritePermission(role);
         role = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
index a0bf497..cdcf6c6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultResponsibleParty.java
@@ -188,7 +188,7 @@ public class DefaultResponsibleParty extends DefaultResponsibility implements Re
      * @return {@code true} if the name has been set, or {@code false} otherwise.
      */
     private boolean setName(final Class<? extends Party> type, final boolean position, final InternationalString name) {
-        checkWritePermission();
+        checkWritePermission(null);
         final Iterator<Party> it = getParties().iterator();
         while (it.hasNext()) {
             final Party party = it.next();
@@ -370,7 +370,7 @@ public class DefaultResponsibleParty extends DefaultResponsibility implements Re
      */
     @Deprecated
     public void setContactInfo(final Contact newValue) {
-        checkWritePermission();
+        checkWritePermission(null);
         final Iterator<Party> it = getParties().iterator();
         while (it.hasNext()) {
             final Party party = it.next();
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 ec007be..26bcde0 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
@@ -145,7 +145,7 @@ public class DefaultSeries extends ISOMetadata implements Series {
      * @param  newValue  the new name, or {@code null} if none.
      */
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -166,7 +166,7 @@ public class DefaultSeries extends ISOMetadata implements Series {
      * @param  newValue  the new issue identification, or {@code null} if none.
      */
     public void setIssueIdentification(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(issueIdentification);
         issueIdentification = newValue;
     }
 
@@ -187,7 +187,7 @@ public class DefaultSeries extends ISOMetadata implements Series {
      * @param  newValue  the new page, or {@code null} if none.
      */
     public void setPage(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(page);
         page = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
index 462350d..f1aef1f 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/citation/DefaultTelephone.java
@@ -180,7 +180,7 @@ public class DefaultTelephone extends ISOMetadata implements Telephone {
      * @since 0.5
      */
     public void setNumber(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(number);
         number = newValue;
     }
 
@@ -206,7 +206,7 @@ public class DefaultTelephone extends ISOMetadata implements Telephone {
      * @since 0.5
      */
     public void setNumberType(final TelephoneType newValue) {
-        checkWritePermission();
+        checkWritePermission(numberType);
         numberType = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java
index c87caa8..10fe07a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultConstraints.java
@@ -227,7 +227,7 @@ public class DefaultConstraints extends ISOMetadata implements Constraints {
      * @since 0.5
      */
     public void setConstraintApplicationScope(final Scope newValue) {
-        checkWritePermission();
+        checkWritePermission(constraintApplicationScope);
         constraintApplicationScope = newValue;
     }
 
@@ -302,7 +302,7 @@ public class DefaultConstraints extends ISOMetadata implements Constraints {
      * @since 0.5
      */
     public void setReleasability(final Releasability newValue) {
-        checkWritePermission();
+        checkWritePermission(releasability);
         releasability = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java
index 44e4ba4..ed7bbdd 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultReleasability.java
@@ -157,7 +157,7 @@ public class DefaultReleasability extends ISOMetadata implements Releasability {
      * @param  newValue  the new release statement.
      */
     public void setStatement(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(statement);
         statement = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultSecurityConstraints.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultSecurityConstraints.java
index 0dc0d27..dbf91c9 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultSecurityConstraints.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/constraint/DefaultSecurityConstraints.java
@@ -166,7 +166,7 @@ public class DefaultSecurityConstraints extends DefaultConstraints implements Se
      * @param  newValue  the new classification.
      */
     public void setClassification(final Classification newValue) {
-        checkWritePermission();
+        checkWritePermission(classification);
         classification = newValue;
     }
 
@@ -189,7 +189,7 @@ public class DefaultSecurityConstraints extends DefaultConstraints implements Se
      * @param  newValue  the new user note.
      */
     public void setUserNote(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(userNote);
         userNote = newValue;
     }
 
@@ -210,7 +210,7 @@ public class DefaultSecurityConstraints extends DefaultConstraints implements Se
      * @param  newValue  the new classification system.
      */
     public void setClassificationSystem(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(classificationSystem);
         classificationSystem = newValue;
     }
 
@@ -231,7 +231,7 @@ public class DefaultSecurityConstraints extends DefaultConstraints implements Se
      * @param  newValue  the new handling description.
      */
     public void setHandlingDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(handlingDescription);
         handlingDescription = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
index 133180f..cf1d470 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultBand.java
@@ -207,7 +207,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @since 0.5
      */
     public void setBoundMin(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(boundMin);
         if (ensurePositive(DefaultBand.class, "boundMin", false, newValue)) {
             boundMin = newValue;
         }
@@ -239,7 +239,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @since 0.5
      */
     public void setBoundMax(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(boundMax);
         if (ensurePositive(DefaultBand.class, "boundMax", false, newValue)) {
             boundMax = newValue;
         }
@@ -269,7 +269,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @since 0.5
      */
     public void setBoundUnits(final Unit<Length> newValue) {
-        checkWritePermission();
+        checkWritePermission(boundUnits);
         boundUnits = newValue;
     }
 
@@ -290,7 +290,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @param  newValue  the new band definition.
      */
     public void setBandBoundaryDefinition(final BandDefinition newValue) {
-        checkWritePermission();
+        checkWritePermission(bandBoundaryDefinition);
         bandBoundaryDefinition = newValue;
     }
 
@@ -314,7 +314,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setPeakResponse(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(peakResponse);
         if (ensurePositive(DefaultBand.class, "peakResponse", false, newValue)) {
             peakResponse = newValue;
         }
@@ -338,7 +338,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @param  newValue  the new tone gradation.
      */
     public void setToneGradation(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(toneGradation);
         if (ensurePositive(DefaultBand.class, "toneGradation", false, newValue)) {
             toneGradation = newValue;
         }
@@ -401,7 +401,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @param  newValue  the new transmitted polarization.
      */
     public void setTransmittedPolarization(final PolarizationOrientation newValue) {
-        checkWritePermission();
+        checkWritePermission(transmittedPolarization);
         transmittedPolarization = newValue;
     }
 
@@ -422,7 +422,7 @@ public class DefaultBand extends DefaultSampleDimension implements Band {
      * @param  newValue  the new detected polarization.
      */
     public void setDetectedPolarization(final PolarizationOrientation newValue) {
-        checkWritePermission();
+        checkWritePermission(detectedPolarization);
         detectedPolarization = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
index 13e22f9..13a2fcc 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultCoverageDescription.java
@@ -174,7 +174,7 @@ public class DefaultCoverageDescription extends AbstractContentInformation imple
      * @param  newValue  the new attribute description.
      */
     public void setAttributeDescription(final RecordType newValue) {
-        checkWritePermission();
+        checkWritePermission(attributeDescription);
         attributeDescription = newValue;
     }
 
@@ -202,7 +202,7 @@ public class DefaultCoverageDescription extends AbstractContentInformation imple
      * @since 0.5
      */
     public void setProcessingLevelCode(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(processingLevelCode);
         processingLevelCode = newValue;
     }
 
@@ -276,7 +276,7 @@ public class DefaultCoverageDescription extends AbstractContentInformation imple
      */
     @Deprecated
     public void setContentType(final CoverageContentType newValue) {
-        checkWritePermission();
+        checkWritePermission(attributeGroups);
         final Collection<CoverageContentType> newValues = LegacyPropertyAdapter.asCollection(newValue);
         Collection<AttributeGroup> groups = attributeGroups;
         if (groups != null) {
@@ -346,7 +346,7 @@ public class DefaultCoverageDescription extends AbstractContentInformation imple
      */
     @Deprecated
     public void setDimensions(final Collection<? extends RangeDimension> newValues) {
-        checkWritePermission();
+        checkWritePermission(attributeGroups);
         ((LegacyPropertyAdapter<RangeDimension,?>) getDimensions()).setValues(newValues);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java
index 8398143..b4c2023 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureCatalogueDescription.java
@@ -175,7 +175,7 @@ public class DefaultFeatureCatalogueDescription extends AbstractContentInformati
      * @param  newValue  the new compliance value.
      */
     public void setCompliant(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(compliant);
         compliant = newValue;
     }
 
@@ -216,7 +216,7 @@ public class DefaultFeatureCatalogueDescription extends AbstractContentInformati
      * @param  newValue  {@code true} if the feature catalogue is included.
      */
     public void setIncludedWithDataset(final boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(includedWithDataset ? Boolean.TRUE : null);
         includedWithDataset = newValue;
     }
 
@@ -288,7 +288,7 @@ public class DefaultFeatureCatalogueDescription extends AbstractContentInformati
      */
     @Deprecated
     public void setFeatureTypes(final Collection<? extends GenericName> newValues) {
-        checkWritePermission();
+        checkWritePermission(featureTypes);
         ((LegacyPropertyAdapter<GenericName,?>) getFeatureTypes()).setValues(newValues);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
index ca06318..288f1bb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultFeatureTypeInfo.java
@@ -155,7 +155,7 @@ public class DefaultFeatureTypeInfo extends ISOMetadata implements FeatureTypeIn
      * @param  newValue  the new name.
      */
     public void setFeatureTypeName(final GenericName newValue) {
-        checkWritePermission();
+        checkWritePermission(featureTypeName);
         featureTypeName = newValue;
     }
 
@@ -178,7 +178,7 @@ public class DefaultFeatureTypeInfo extends ISOMetadata implements FeatureTypeIn
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setFeatureInstanceCount(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(featureInstanceCount);
         if (ensurePositive(DefaultFeatureTypeInfo.class, "featureInstanceCount", true, newValue)) {
             featureInstanceCount = newValue;
         }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java
index 19e02cf..708679b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultImageDescription.java
@@ -228,7 +228,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setIlluminationElevationAngle(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(illuminationElevationAngle);
         if (ensureInRange(DefaultImageDescription.class, "illuminationElevationAngle", -90, +90, newValue)) {
             illuminationElevationAngle = newValue;
         }
@@ -255,7 +255,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setIlluminationAzimuthAngle(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(illuminationAzimuthAngle);
         if (ensureInRange(DefaultImageDescription.class, "illuminationAzimuthAngle", 0, 360, newValue)) {
             illuminationAzimuthAngle = newValue;
         }
@@ -278,7 +278,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  the new imaging condition.
      */
     public void setImagingCondition(final ImagingCondition newValue) {
-        checkWritePermission();
+        checkWritePermission(imagingCondition);
         imagingCondition = newValue;
     }
 
@@ -299,7 +299,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  the new image quality code.
      */
     public void setImageQualityCode(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(imageQualityCode);
         imageQualityCode = newValue;
     }
 
@@ -322,7 +322,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @throws IllegalArgumentException if the given value is out of range.
      */
     public void setCloudCoverPercentage(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(cloudCoverPercentage);
         if (ensureInRange(DefaultImageDescription.class, "cloudCoverPercentage", 0, 100, newValue)) {
             cloudCoverPercentage = newValue;
         }
@@ -347,7 +347,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setCompressionGenerationQuantity(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(compressionGenerationQuantity);
         if (ensurePositive(DefaultImageDescription.class, "compressionGenerationQuantity", false, newValue)) {
             compressionGenerationQuantity = newValue;
         }
@@ -370,7 +370,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  the new triangulation indicator.
      */
     public void setTriangulationIndicator(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(triangulationIndicator);
         triangulationIndicator = newValue;
     }
 
@@ -393,7 +393,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  {@code true} if radiometric calibration data are available.
      */
     public void setRadiometricCalibrationDataAvailable(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(radiometricCalibrationDataAvailable);
         radiometricCalibrationDataAvailable = newValue;
     }
 
@@ -414,7 +414,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  {@code true} if camera calibration information are available.
      */
     public void setCameraCalibrationInformationAvailable(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(cameraCalibrationInformationAvailable);
         cameraCalibrationInformationAvailable = newValue;
     }
 
@@ -435,7 +435,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  {@code true} if film distortion information are available.
      */
     public void setFilmDistortionInformationAvailable(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(filmDistortionInformationAvailable);
         filmDistortionInformationAvailable = newValue;
     }
 
@@ -456,7 +456,7 @@ public class DefaultImageDescription extends DefaultCoverageDescription implemen
      * @param  newValue  {@code true} if lens distortion information are available.
      */
     public void setLensDistortionInformationAvailable(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(lensDistortionInformationAvailable);
         lensDistortionInformationAvailable = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
index a259c73..8a7c913 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeDimension.java
@@ -159,7 +159,7 @@ public class DefaultRangeDimension extends ISOMetadata implements RangeDimension
      * @param  newValue  the new sequence identifier.
      */
     public void setSequenceIdentifier(final MemberName newValue) {
-        checkWritePermission();
+        checkWritePermission(sequenceIdentifier);
         sequenceIdentifier = newValue;
     }
 
@@ -185,7 +185,7 @@ public class DefaultRangeDimension extends ISOMetadata implements RangeDimension
      * @since 0.5
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java
index 3d44d38..e03ca93 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultRangeElementDescription.java
@@ -145,7 +145,7 @@ public class DefaultRangeElementDescription extends ISOMetadata implements Range
      * @param  newValue  the new name value.
      */
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -166,7 +166,7 @@ public class DefaultRangeElementDescription extends ISOMetadata implements Range
      * @param  newValue  the new definition value.
      */
     public void setDefinition(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(definition);
         definition = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
index 16f67e0..9ee9902 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/content/DefaultSampleDimension.java
@@ -244,7 +244,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setNumberOfValues(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(numberOfValues);
         if (ensurePositive(DefaultSampleDimension.class, "numberOfValues", false, newValue)) {
             numberOfValues = newValue;
         }
@@ -267,7 +267,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new new minimum value.
      */
     public void setMinValue(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(minValue);
         minValue = newValue;
     }
 
@@ -288,7 +288,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new new maximum value.
      */
     public void setMaxValue(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(maxValue);
         maxValue = newValue;
     }
 
@@ -310,7 +310,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new mean value of data values in each dimension included in the resource.
      */
     public void setMeanValue(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(meanValue);
         meanValue = newValue;
     }
 
@@ -332,7 +332,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new standard deviation of data values in each dimension included in the resource.
      */
     public void setStandardDeviation(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(standardDeviation);
         standardDeviation = newValue;
     }
 
@@ -353,7 +353,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new units of data in the dimension.
      */
     public void setUnits(final Unit<?> newValue) {
-        checkWritePermission();
+        checkWritePermission(units);
         units = newValue;
     }
 
@@ -374,7 +374,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new scale factor which has been applied to the cell value.
      */
     public void setScaleFactor(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(scaleFactor);
         scaleFactor = newValue;
     }
 
@@ -395,7 +395,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new physical value corresponding to a cell value of zero.
      */
     public void setOffset(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(offset);
         offset = newValue;
     }
 
@@ -421,7 +421,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new transfer function value.
      */
     public void setTransferFunctionType(final TransferFunctionType newValue) {
-        checkWritePermission();
+        checkWritePermission(transferFunctionType);
         transferFunctionType = newValue;
     }
 
@@ -447,7 +447,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @throws IllegalArgumentException if the given value is zero or negative.
      */
     public void setBitsPerValue(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(bitsPerValue);
         if (ensurePositive(DefaultSampleDimension.class, "bitsPerValue", true, newValue)) {
             bitsPerValue = newValue;
         }
@@ -479,7 +479,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setNominalSpatialResolution(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(nominalSpatialResolution);
         if (ensurePositive(DefaultSampleDimension.class, "nominalSpatialResolution", true, newValue)) {
             nominalSpatialResolution = newValue;
         }
@@ -503,7 +503,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new type of other attribute description.
      */
     public void setOtherPropertyType(final RecordType newValue) {
-        checkWritePermission();
+        checkWritePermission(otherPropertyType);
         otherPropertyType = newValue;
     }
 
@@ -527,7 +527,7 @@ public class DefaultSampleDimension extends DefaultRangeDimension implements Sam
      * @param  newValue  the new instance of other/attributeType.
      */
     public void setOtherProperty(final Record newValue) {
-        checkWritePermission();
+        checkWritePermission(otherProperty);
         otherProperty = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java
index 49d55a9..b46cd11 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDataFile.java
@@ -180,7 +180,7 @@ public class DefaultDataFile extends ISOMetadata implements DataFile {
      * @since 1.0
      */
     public void setFileName(final URI newValue) {
-        checkWritePermission();
+        checkWritePermission(fileName);
         fileName = newValue;
     }
 
@@ -205,7 +205,7 @@ public class DefaultDataFile extends ISOMetadata implements DataFile {
      * @since 1.0
      */
     public void setFileDescription(final InternationalString newValue)  {
-        checkWritePermission();
+        checkWritePermission(fileDescription);
         fileDescription = newValue;
     }
 
@@ -231,7 +231,7 @@ public class DefaultDataFile extends ISOMetadata implements DataFile {
      * @param  newValue  the new file type.
      */
     public void setFileType(final String newValue)  {
-        checkWritePermission();
+        checkWritePermission(fileType);
         fileType = newValue;
     }
 
@@ -281,7 +281,7 @@ public class DefaultDataFile extends ISOMetadata implements DataFile {
      */
     @Deprecated
     public void setFileFormat(final Format newValue) {
-        checkWritePermission();
+        checkWritePermission(fileFormat);
         fileFormat = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
index b5bb2fb..1dca3e0 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDigitalTransferOptions.java
@@ -180,7 +180,7 @@ public class DefaultDigitalTransferOptions extends ISOMetadata implements Digita
      * @param  newValue  the new units of distribution.
      */
     public void setUnitsOfDistribution(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(unitsOfDistribution);
         unitsOfDistribution = newValue;
     }
 
@@ -205,7 +205,7 @@ public class DefaultDigitalTransferOptions extends ISOMetadata implements Digita
      * @throws IllegalArgumentException if the given value is NaN or negative.
      */
     public void setTransferSize(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(transferSize);
         if (ensurePositive(DefaultDigitalTransferOptions.class, "transferSize", true, newValue)) {
             transferSize = newValue;
         }
@@ -308,7 +308,7 @@ public class DefaultDigitalTransferOptions extends ISOMetadata implements Digita
      * @since 0.5
      */
     public void setTransferFrequency(final PeriodDuration newValue) {
-        checkWritePermission();
+        checkWritePermission(transferFrequency);
         transferFrequency = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
index efa1a55..70af366 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultDistribution.java
@@ -166,7 +166,7 @@ public class DefaultDistribution extends ISOMetadata implements Distribution {
      * @since 0.5
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
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 d641f4e..3d47d7d 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
@@ -169,7 +169,7 @@ public class DefaultDistributor extends ISOMetadata implements Distributor {
      * @param  newValue  the new distributor contact.
      */
     public void setDistributorContact(final Responsibility newValue) {
-        checkWritePermission();
+        checkWritePermission(distributorContact);
         distributorContact = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
index 359f099..5db6209 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultFormat.java
@@ -204,7 +204,7 @@ public class DefaultFormat extends ISOMetadata implements Format {
      * @since 0.5
      */
     public void setFormatSpecificationCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(formatSpecificationCitation);
         formatSpecificationCitation = newValue;
     }
 
@@ -262,7 +262,7 @@ public class DefaultFormat extends ISOMetadata implements Format {
      */
     @Deprecated
     public void setSpecification(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(formatSpecificationCitation);
         setFormatSpecificationCitation((citation, value) -> citation.setTitle(value), newValue);
     }
 
@@ -301,7 +301,7 @@ public class DefaultFormat extends ISOMetadata implements Format {
      */
     @Deprecated
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(formatSpecificationCitation);
         setFormatSpecificationCitation((citation, value) ->
                 citation.setAlternateTitles(LegacyPropertyAdapter.asCollection(value)), newValue);
     }
@@ -340,7 +340,7 @@ public class DefaultFormat extends ISOMetadata implements Format {
      */
     @Deprecated
     public void setVersion(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(formatSpecificationCitation);
         setFormatSpecificationCitation((citation, value) -> citation.setEdition(value), newValue);
     }
 
@@ -361,7 +361,7 @@ public class DefaultFormat extends ISOMetadata implements Format {
      * @param  newValue  the new amendment number.
      */
     public void setAmendmentNumber(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(amendmentNumber);
         amendmentNumber = newValue;
     }
 
@@ -385,7 +385,7 @@ public class DefaultFormat extends ISOMetadata implements Format {
      * @param  newValue  the new file decompression technique.
      */
     public void setFileDecompressionTechnique(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(fileDecompressionTechnique);
         fileDecompressionTechnique = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
index d8d92df..b301b20 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultMedium.java
@@ -196,7 +196,7 @@ public class DefaultMedium extends ISOMetadata implements Medium {
      * @param  newValue  the new name.
      */
     public void setName(final MediumName newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -226,7 +226,7 @@ public class DefaultMedium extends ISOMetadata implements Medium {
      * @since 0.5
      */
     public void setDensity(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(density);
         if (ensurePositive(DefaultMedium.class, "density", true, newValue)) {
             density = newValue;
         }
@@ -294,7 +294,7 @@ public class DefaultMedium extends ISOMetadata implements Medium {
      * @param  newValue  the new density units.
      */
     public void setDensityUnits(final Unit<?> newValue) {
-        checkWritePermission();
+        checkWritePermission(densityUnits);
         densityUnits = newValue;
     }
 
@@ -317,7 +317,7 @@ public class DefaultMedium extends ISOMetadata implements Medium {
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setVolumes(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(volumes);
         if (ensurePositive(DefaultMedium.class, "volumes", false, newValue)) {
             volumes = newValue;
         }
@@ -360,7 +360,7 @@ public class DefaultMedium extends ISOMetadata implements Medium {
      * @param  newValue  the new medium note.
      */
     public void setMediumNote(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(mediumNote);
         mediumNote = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
index f5447ea..ca3ca7f 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/distribution/DefaultStandardOrderProcess.java
@@ -183,7 +183,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @see #setCurrency(Currency)
      */
     public void setFees(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(fees);
         fees = newValue;
     }
 
@@ -219,7 +219,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @since 0.5
      */
     public void setCurrency(final Currency newValue) {
-        checkWritePermission();
+        checkWritePermission(currency);
         currency = newValue;
     }
 
@@ -240,7 +240,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @param  newValue  the new planned available time.
      */
     public void setPlannedAvailableDateTime(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(plannedAvailableDateTime);
         plannedAvailableDateTime = toMilliseconds(newValue);
     }
 
@@ -261,7 +261,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @param  newValue  the new ordering instructions.
      */
     public void setOrderingInstructions(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(orderingInstructions);
         orderingInstructions = newValue;
     }
 
@@ -282,7 +282,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @param  newValue  the new turnaround.
      */
     public void setTurnaround(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(turnaround);
         turnaround = newValue;
     }
 
@@ -310,7 +310,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @since 0.5
      */
     public void setOrderOptionType(final RecordType newValue) {
-        checkWritePermission();
+        checkWritePermission(orderOptionType);
         orderOptionType = newValue;
     }
 
@@ -340,7 +340,7 @@ public class DefaultStandardOrderProcess extends ISOMetadata implements Standard
      * @since 0.5
      */
     public void setOrderOptions(final Record newValue) {
-        checkWritePermission();
+        checkWritePermission(orderOptions);
         orderOptions = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/AbstractGeographicExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/AbstractGeographicExtent.java
index fd437ec..0e7d1a5 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/AbstractGeographicExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/AbstractGeographicExtent.java
@@ -159,7 +159,7 @@ public class AbstractGeographicExtent extends ISOMetadata implements GeographicE
      * @param newValue {@code true} if the bounding polygon encompasses an area covered by the data.
      */
     public void setInclusion(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(inclusion);
         inclusion = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java
index 7620f5f..7470204 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultExtent.java
@@ -214,7 +214,7 @@ public class DefaultExtent extends ISOMetadata implements Extent {
      * @param  newValue  the new description.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -279,6 +279,15 @@ public class DefaultExtent extends ISOMetadata implements Extent {
     }
 
     /**
+     * Returns a non-null value if this extent is non-empty.
+     * This implementation does not test if the elements are themselves empty.
+     */
+    private Boolean isNonEmpty() {
+        return (geographicElements != null) || (verticalElements != null) || (temporalElements != null)
+                || (description != null) ? Boolean.TRUE : null;
+    }
+
+    /**
      * Adds geographic, vertical or temporal extents inferred from the given envelope.
      * This method inspects the {@linkplain Envelope#getCoordinateReferenceSystem() envelope CRS}
      * and creates a {@link GeographicBoundingBox}, {@link VerticalExtent} or {@link TemporalExtent}
@@ -295,7 +304,7 @@ public class DefaultExtent extends ISOMetadata implements Extent {
      * @see DefaultTemporalExtent#setBounds(Envelope)
      */
     public void addElements(final Envelope envelope) throws TransformException {
-        checkWritePermission();
+        checkWritePermission(isNonEmpty());
         ArgumentChecks.ensureNonNull("envelope", envelope);
         ReferencingServices.getInstance().addElements(envelope, this);
     }
@@ -318,7 +327,7 @@ public class DefaultExtent extends ISOMetadata implements Extent {
      * @since 0.8
      */
     public void intersect(final Extent other) {
-        checkWritePermission();
+        checkWritePermission(isNonEmpty());
         ArgumentChecks.ensureNonNull("other", other);
         final InternationalString od = other.getDescription();
         if (od != null && !(description instanceof NilObject)) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java
index 3682a80..e27b0fb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicBoundingBox.java
@@ -37,6 +37,7 @@ import org.apache.sis.metadata.InvalidMetadataException;
 import org.apache.sis.xml.NilReason;
 
 import static java.lang.Double.doubleToLongBits;
+import static org.apache.sis.internal.metadata.MetadataUtilities.isDefined;
 
 
 /**
@@ -298,7 +299,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      *         or {@linkplain Double#NaN NaN} to undefine.
      */
     public void setWestBoundLongitude(double newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(westBoundLongitude));
         if (newValue != Longitude.MAX_VALUE) {                  // Do not normalize +180° to -180°.
             newValue = Longitude.normalize(newValue);
         }
@@ -331,7 +332,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      *         or {@linkplain Double#NaN NaN} to undefine.
      */
     public void setEastBoundLongitude(double newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(eastBoundLongitude));
         if (newValue != Longitude.MAX_VALUE) {                      // Do not normalize +180° to -180°.
             newValue = Longitude.normalize(newValue);
         }
@@ -363,7 +364,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      *         or {@linkplain Double#NaN NaN} to undefine.
      */
     public void setSouthBoundLatitude(final double newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(southBoundLatitude));
         southBoundLatitude = Latitude.clamp(newValue);
         if (southBoundLatitude > northBoundLatitude) {
             northBoundLatitude = Double.NaN;
@@ -395,7 +396,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      *         or {@linkplain Double#NaN NaN} to undefine.
      */
     public void setNorthBoundLatitude(final double newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(northBoundLatitude));
         northBoundLatitude = Latitude.clamp(newValue);
         if (northBoundLatitude < southBoundLatitude) {
             southBoundLatitude = Double.NaN;
@@ -488,7 +489,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
                           final double northBoundLatitude)
             throws IllegalArgumentException
     {
-        checkWritePermission();
+        checkWritePermission(isNonEmpty());
         verifyBounds(southBoundLatitude, northBoundLatitude);
         this.westBoundLongitude = westBoundLongitude;
         this.eastBoundLongitude = eastBoundLongitude;
@@ -521,7 +522,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      */
     public void setBounds(final Envelope envelope) throws TransformException {
         ArgumentChecks.ensureNonNull("envelope", envelope);
-        checkWritePermission();
+        checkWritePermission(isNonEmpty());
         ReferencingServices.getInstance().setBounds(envelope, this);
         setInclusion(Boolean.TRUE);                                     // Set only on success.
     }
@@ -648,7 +649,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      * @see org.apache.sis.geometry.GeneralEnvelope#add(Envelope)
      */
     public void add(final GeographicBoundingBox box) {
-        checkWritePermission();
+        checkWritePermission(isNonEmpty());
         ArgumentChecks.ensureNonNull("box", box);
         double λmin = box.getWestBoundLongitude();
         double λmax = box.getEastBoundLongitude();
@@ -706,7 +707,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      * @see org.apache.sis.geometry.GeneralEnvelope#intersect(Envelope)
      */
     public void intersect(final GeographicBoundingBox box) throws IllegalArgumentException {
-        checkWritePermission();
+        checkWritePermission(isNonEmpty());
         ArgumentChecks.ensureNonNull("box", box);
         if (getInclusion(getInclusion()) != getInclusion(box.getInclusion())) {
             throw new IllegalArgumentException(Errors.format(Errors.Keys.IncompatiblePropertyValue_1, "inclusion"));
@@ -736,6 +737,18 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
     }
 
     /**
+     * Returns an arbitrary non-null value if this bounding box is non-empty.
+     * The return value can be given to {@link #checkWritePermission(Object)}
+     * before to set the bounds of this geographic extent.
+     */
+    private Boolean isNonEmpty() {
+        return Double.isNaN(eastBoundLongitude) &&
+               Double.isNaN(westBoundLongitude) &&
+               Double.isNaN(northBoundLatitude) &&
+               Double.isNaN(southBoundLatitude) ? null : Boolean.TRUE;
+    }
+
+    /**
      * Returns {@code true} if this metadata is empty. This metadata is considered empty if
      * every bound values are {@linkplain Double#NaN NaN}. Note that this is different than
      * the <cite>Java2D</cite> or <cite>envelope</cite> definition of "emptiness", since we
@@ -748,10 +761,7 @@ public class DefaultGeographicBoundingBox extends AbstractGeographicExtent imple
      */
     @Override
     public boolean isEmpty() {
-        return Double.isNaN(eastBoundLongitude) &&
-               Double.isNaN(westBoundLongitude) &&
-               Double.isNaN(northBoundLatitude) &&
-               Double.isNaN(southBoundLatitude);
+        return isNonEmpty() == null;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
index 2780e20..e4aa216 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultGeographicDescription.java
@@ -202,7 +202,7 @@ public class DefaultGeographicDescription extends AbstractGeographicExtent imple
      * @param  newValue  the new geographic identifier.
      */
     public void setGeographicIdentifier(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(geographicIdentifier);
         geographicIdentifier = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java
index 46c0559..b27b81b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultSpatialTemporalExtent.java
@@ -181,7 +181,7 @@ public class DefaultSpatialTemporalExtent extends DefaultTemporalExtent implemen
      * @since 0.5
      */
     public void setVerticalExtent(final VerticalExtent newValue) {
-        checkWritePermission();
+        checkWritePermission(verticalExtent);
         verticalExtent = newValue;
     }
 
@@ -221,7 +221,7 @@ public class DefaultSpatialTemporalExtent extends DefaultTemporalExtent implemen
      */
     @Override
     public void setBounds(final Envelope envelope) throws TransformException {
-        checkWritePermission();
+        checkWritePermission(spatialExtent);
         ReferencingServices.getInstance().setBounds(envelope, this);
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
index 5155edd..8b42ffa 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultTemporalExtent.java
@@ -154,7 +154,7 @@ public class DefaultTemporalExtent extends ISOMetadata implements TemporalExtent
      * @param  newValue  the new content date.
      */
     public void setExtent(final TemporalPrimitive newValue) {
-        checkWritePermission();
+        checkWritePermission(extent);
         extent = newValue;
     }
 
@@ -240,7 +240,7 @@ public class DefaultTemporalExtent extends ISOMetadata implements TemporalExtent
      * @see DefaultVerticalExtent#setBounds(Envelope)
      */
     public void setBounds(final Envelope envelope) throws TransformException {
-        checkWritePermission();
+        checkWritePermission(extent);
         ReferencingServices.getInstance().setBounds(envelope, this);
     }
 
@@ -259,7 +259,7 @@ public class DefaultTemporalExtent extends ISOMetadata implements TemporalExtent
      * @since 0.8
      */
     public void intersect(final TemporalExtent other) {
-        checkWritePermission();
+        checkWritePermission(extent);
         final TemporalPrimitive ot = other.getExtent();
         if (ot != null && !(extent instanceof NilObject)) {
             if (extent == null || (ot instanceof NilObject)) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java
index 1c729a2..55e5c62 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/extent/DefaultVerticalExtent.java
@@ -181,7 +181,7 @@ public class DefaultVerticalExtent extends ISOMetadata implements VerticalExtent
      * @param  newValue  the new minimum value.
      */
     public void setMinimumValue(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(minimumValue);
         minimumValue = newValue;
     }
 
@@ -203,7 +203,7 @@ public class DefaultVerticalExtent extends ISOMetadata implements VerticalExtent
      * @param  newValue  the new maximum value.
      */
     public void setMaximumValue(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(maximumValue);
         maximumValue = newValue;
     }
 
@@ -229,11 +229,19 @@ public class DefaultVerticalExtent extends ISOMetadata implements VerticalExtent
      * @param  newValue  the new vertical CRS.
      */
     public void setVerticalCRS(final VerticalCRS newValue) {
-        checkWritePermission();
+        checkWritePermission(verticalCRS);
         verticalCRS = newValue;
     }
 
     /**
+     * Returns an arbitrary value, or {@code null} if both minimum and maximum are null.
+     * This is used for verifying if the bounds are already set or partially set.
+     */
+    private Double value() {
+        return (minimumValue != null) ? minimumValue : maximumValue;
+    }
+
+    /**
      * Sets this vertical extent to values inferred from the specified envelope. The envelope can
      * be multi-dimensional, in which case the {@linkplain Envelope#getCoordinateReferenceSystem()
      * envelope CRS} must have a vertical component.
@@ -249,7 +257,7 @@ public class DefaultVerticalExtent extends ISOMetadata implements VerticalExtent
      * @see DefaultTemporalExtent#setBounds(Envelope)
      */
     public void setBounds(final Envelope envelope) throws TransformException {
-        checkWritePermission();
+        checkWritePermission(value());
         ReferencingServices.getInstance().setBounds(envelope, this);
     }
 
@@ -272,7 +280,7 @@ public class DefaultVerticalExtent extends ISOMetadata implements VerticalExtent
      * @since 0.8
      */
     public void intersect(final VerticalExtent other) throws MismatchedReferenceSystemException {
-        checkWritePermission();
+        checkWritePermission(value());
         ArgumentChecks.ensureNonNull("other", other);
         Double min = other.getMinimumValue();
         Double max = other.getMaximumValue();
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 df8472f..eabfc35 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
@@ -334,7 +334,7 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
      * @param  newValue  the new citation.
      */
     public void setCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(citation);
         citation = newValue;
     }
 
@@ -355,7 +355,7 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
      * @param  newValue  the new summary of resource(s).
      */
     public void setAbstract(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(abstracts);
         abstracts = newValue;
     }
 
@@ -376,7 +376,7 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
      * @param  newValue  the new summary of intention.
      */
     public void setPurpose(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(purpose);
         purpose = newValue;
     }
 
@@ -610,7 +610,7 @@ public class AbstractIdentification extends ISOMetadata implements Identificatio
      * @since 0.5
      */
     public void setProcessingLevel(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(processingLevel);
         processingLevel = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java
index 9d38770..0e62d89 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAggregateInformation.java
@@ -194,7 +194,7 @@ public class DefaultAggregateInformation extends DefaultAssociatedResource imple
      */
     @Deprecated
     public void setAggregateDataSetIdentifier(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(null);
         Citation name = getAggregateDataSetName();
         if (newValue != null) {
             if (!(name instanceof DefaultCitation)) {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java
index bb833c3..fd47118 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultAssociatedResource.java
@@ -172,7 +172,7 @@ public class DefaultAssociatedResource extends ISOMetadata implements Associated
      * @param  newValue  the new citation information, or {@code null}.
      */
     public void setName(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -194,7 +194,7 @@ public class DefaultAssociatedResource extends ISOMetadata implements Associated
      * @param  newValue  the new type of relation.
      */
     public void setAssociationType(final AssociationType newValue) {
-        checkWritePermission();
+        checkWritePermission(associationType);
         associationType = newValue;
     }
 
@@ -216,7 +216,7 @@ public class DefaultAssociatedResource extends ISOMetadata implements Associated
      * @param  newValue  the new type of initiative.
      */
     public void setInitiativeType(final InitiativeType newValue) {
-        checkWritePermission();
+        checkWritePermission(initiativeType);
         initiativeType = newValue;
     }
 
@@ -238,7 +238,7 @@ public class DefaultAssociatedResource extends ISOMetadata implements Associated
      * @param  newValue  the new reference to the metadata.
      */
     public void setMetadataReference(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(metadataReference);
         metadataReference = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java
index 1dfc78b..36dd5d7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultBrowseGraphic.java
@@ -174,7 +174,7 @@ public class DefaultBrowseGraphic extends ISOMetadata implements BrowseGraphic {
      * @param  newValue  the new filename.
      */
     public void setFileName(final URI newValue) {
-        checkWritePermission();
+        checkWritePermission(fileName);
         fileName = newValue;
     }
 
@@ -195,7 +195,7 @@ public class DefaultBrowseGraphic extends ISOMetadata implements BrowseGraphic {
      * @param  newValue  the new file description.
      */
     public void setFileDescription(final InternationalString newValue)  {
-        checkWritePermission();
+        checkWritePermission(fileDescription);
         fileDescription = newValue;
     }
 
@@ -223,7 +223,7 @@ public class DefaultBrowseGraphic extends ISOMetadata implements BrowseGraphic {
      * @param  newValue  the new file type.
      */
     public void setFileType(final String newValue)  {
-        checkWritePermission();
+        checkWritePermission(fileType);
         fileType = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java
index 4ee2f81..7e48e70 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultCoupledResource.java
@@ -179,8 +179,8 @@ public class DefaultCoupledResource extends ISOMetadata implements CoupledResour
      * @param  newValue  the new identifier of the resource.
      */
     public void setScopedName(final ScopedName newValue) {
-        checkWritePermission();
-        this.scopedName = newValue;
+        checkWritePermission(scopedName);
+        scopedName = newValue;
     }
 
     /**
@@ -241,8 +241,8 @@ public class DefaultCoupledResource extends ISOMetadata implements CoupledResour
      * @param  newValue  the new service operation.
      */
     public void setOperation(final OperationMetadata newValue) {
-        checkWritePermission();
-        this.operation = newValue;
+        checkWritePermission(operation);
+        operation = newValue;
     }
 
 
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 e8640b2..2e6edb2 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
@@ -248,7 +248,7 @@ public class DefaultDataIdentification extends AbstractIdentification implements
      * @param  newValue  the new environment description.
      */
     public void setEnvironmentDescription(final InternationalString newValue)  {
-        checkWritePermission();
+        checkWritePermission(environmentDescription);
         environmentDescription = newValue;
     }
 
@@ -269,7 +269,7 @@ public class DefaultDataIdentification extends AbstractIdentification implements
      * @param  newValue  the new supplemental information.
      */
     public void setSupplementalInformation(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(supplementalInformation);
         supplementalInformation = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
index 8fd8704..79dde2c 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywordClass.java
@@ -159,7 +159,7 @@ public class DefaultKeywordClass extends ISOMetadata implements KeywordClass {
      * @param  newValue  the new keyword category in natural language.
      */
     public void setClassName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(className);
         className = newValue;
     }
 
@@ -180,7 +180,7 @@ public class DefaultKeywordClass extends ISOMetadata implements KeywordClass {
      * @param  newValue  the new URI of concept in the ontology.
      */
     public void setConceptIdentifier(final URI newValue) {
-        checkWritePermission();
+        checkWritePermission(conceptIdentifier);
         conceptIdentifier = newValue;
     }
 
@@ -201,7 +201,7 @@ public class DefaultKeywordClass extends ISOMetadata implements KeywordClass {
      * @param  newValue  the new reference that binds the keyword class to a formal conceptualization.
      */
     public void setOntology(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(ontology);
         ontology = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java
index 1a204ca..a09af15 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultKeywords.java
@@ -195,7 +195,7 @@ public class DefaultKeywords extends ISOMetadata implements Keywords {
      * @param newValue  the new keyword type.
      */
     public void setType(final KeywordType newValue) {
-        checkWritePermission();
+        checkWritePermission(type);
         type = newValue;
     }
 
@@ -216,7 +216,7 @@ public class DefaultKeywords extends ISOMetadata implements Keywords {
      * @param newValue  the new thesaurus name.
      */
     public void setThesaurusName(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(thesaurusName);
         thesaurusName = newValue;
     }
 
@@ -243,7 +243,7 @@ public class DefaultKeywords extends ISOMetadata implements Keywords {
      * @since 0.5
      */
     public void setKeywordClass(final KeywordClass newValue) {
-        checkWritePermission();
+        checkWritePermission(keywordClass);
         keywordClass = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
index e5c341f..fe61784 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationChainMetadata.java
@@ -159,7 +159,7 @@ public class DefaultOperationChainMetadata extends ISOMetadata implements Operat
      * @param  newValue  the new name used by the service for this chain.
      */
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -180,7 +180,7 @@ public class DefaultOperationChainMetadata extends ISOMetadata implements Operat
      * @param  newValue  the new a narrative explanation of the services in the chain and resulting output
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
index 7869f67..67439a6 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultOperationMetadata.java
@@ -196,7 +196,7 @@ public class DefaultOperationMetadata extends ISOMetadata implements OperationMe
      * @param  newValue  the new unique identifier for this interface.
      */
     public void setOperationName(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(operationName);
         operationName = newValue;
     }
 
@@ -237,7 +237,7 @@ public class DefaultOperationMetadata extends ISOMetadata implements OperationMe
      * @param  newValue  the new free text description of the intent of the operation and the results of the operation.
      */
     public void setOperationDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(operationDescription);
         operationDescription = newValue;
     }
 
@@ -259,7 +259,7 @@ public class DefaultOperationMetadata extends ISOMetadata implements OperationMe
      * @param  newValue  the new name used to invoke this interface within the context of the DCP.
      */
     public void setInvocationName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(invocationName);
         invocationName = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
index 2bb11f3..1d12aa0 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultResolution.java
@@ -219,7 +219,7 @@ public class DefaultResolution extends ISOMetadata implements Resolution {
      * @param  newValue  the new value.
      */
     private void setProperty(final byte code, final Object newValue) {
-        checkWritePermission();
+        checkWritePermission(value);
         if (value != null && property != code) {
             if (newValue == null) {
                 return;                                     // Do not erase the other property.
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java
index 9937bd0..0a74b2b 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/identification/DefaultServiceIdentification.java
@@ -239,7 +239,7 @@ public class DefaultServiceIdentification extends AbstractIdentification impleme
      * @param  newValue  the new service type name.
      */
     public void setServiceType(final GenericName newValue) {
-        checkWritePermission();
+        checkWritePermission(serviceType);
         serviceType = newValue;
     }
 
@@ -285,7 +285,7 @@ public class DefaultServiceIdentification extends AbstractIdentification impleme
      * @since 0.5
      */
     public void setAccessProperties(final StandardOrderProcess newValue) {
-        checkWritePermission();
+        checkWritePermission(accessProperties);
         accessProperties = newValue;
     }
 
@@ -306,7 +306,7 @@ public class DefaultServiceIdentification extends AbstractIdentification impleme
      * @param  newValue  the new type of coupling between service and associated data.
      */
     public void setCouplingType(final CouplingType newValue) {
-        checkWritePermission();
+        checkWritePermission(couplingType);
         couplingType = newValue;
     }
 
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 99a93e9..8b53c12 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
@@ -32,6 +32,7 @@ import org.apache.sis.util.iso.Types;
 
 import static org.apache.sis.internal.metadata.MetadataUtilities.toDate;
 import static org.apache.sis.internal.metadata.MetadataUtilities.toMilliseconds;
+import static org.apache.sis.internal.metadata.MetadataUtilities.isDateDefined;
 
 
 /**
@@ -203,7 +204,7 @@ public class DefaultUsage extends ISOMetadata implements Usage {
      * @param  newValue  the new specific usage.
      */
     public void setSpecificUsage(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(specificUsage);
         specificUsage = newValue;
     }
 
@@ -224,7 +225,7 @@ public class DefaultUsage extends ISOMetadata implements Usage {
      * @param  newValue  the new usage date.
      */
     public void setUsageDate(final Date newValue)  {
-        checkWritePermission();
+        checkWritePermission(isDateDefined(usageDate));
         usageDate = toMilliseconds(newValue);
     }
 
@@ -245,8 +246,8 @@ public class DefaultUsage extends ISOMetadata implements Usage {
      * @param  newValue  the new user determined limitations.
      */
     public void setUserDeterminedLimitations(final InternationalString newValue) {
-        checkWritePermission();
-        this.userDeterminedLimitations = newValue;
+        checkWritePermission(userDeterminedLimitations);
+        userDeterminedLimitations = newValue;
     }
 
     /**
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultAlgorithm.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultAlgorithm.java
index f87d7c5..01c7cc7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultAlgorithm.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultAlgorithm.java
@@ -137,7 +137,7 @@ public class DefaultAlgorithm extends ISOMetadata implements Algorithm {
      * @param  newValue  the new citation value.
      */
     public void setCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(citation);
         citation = newValue;
     }
 
@@ -158,7 +158,7 @@ public class DefaultAlgorithm extends ISOMetadata implements Algorithm {
      * @param  newValue  the new description value.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java
index 0bf71ea..24a9ceb 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultLineage.java
@@ -189,7 +189,7 @@ public class DefaultLineage extends ISOMetadata implements Lineage {
      * @param  newValue  the new statement.
      */
     public void setStatement(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(statement);
         statement = newValue;
     }
 
@@ -215,7 +215,7 @@ public class DefaultLineage extends ISOMetadata implements Lineage {
      * @since 0.5
      */
     public void setScope(final Scope newValue) {
-        checkWritePermission();
+        checkWritePermission(scope);
         scope = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultNominalResolution.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultNominalResolution.java
index 190d34f..399f88e 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultNominalResolution.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultNominalResolution.java
@@ -148,7 +148,7 @@ public class DefaultNominalResolution extends ISOMetadata implements NominalReso
      * @throws IllegalArgumentException if the given value is NaN, zero or negative.
      */
     public void setScanningResolution(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(scanningResolution);
         if (ensurePositive(DefaultNominalResolution.class, "scanningResolution", true, newValue)) {
             scanningResolution = newValue;
         }
@@ -175,7 +175,7 @@ public class DefaultNominalResolution extends ISOMetadata implements NominalReso
      * @throws IllegalArgumentException if the given value is NaN, zero or negative.
      */
     public void setGroundResolution(final Double newValue) {
-        checkWritePermission();
+        checkWritePermission(groundResolution);
         if (ensurePositive(DefaultNominalResolution.class, "groundResolution", true, newValue)) {
             groundResolution = newValue;
         }
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 d63446c..2798e42 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
@@ -225,7 +225,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * @param  newValue  the new description.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -246,7 +246,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * @param  newValue  the new rationale.
      */
     public void setRationale(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(rationale);
         rationale = newValue;
     }
 
@@ -271,7 +271,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * @since 1.0
      */
     public void setStepDateTime(final TemporalPrimitive newValue) {
-        checkWritePermission();
+        checkWritePermission(stepDateTime);
         stepDateTime = newValue;
     }
 
@@ -369,7 +369,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * @since 0.5
      */
     public void setScope(final Scope newValue) {
-        checkWritePermission();
+        checkWritePermission(scope);
         scope = newValue;
     }
 
@@ -434,7 +434,7 @@ public class DefaultProcessStep extends ISOMetadata implements ProcessStep {
      * @param  newValue  the new processing information value.
      */
     public void setProcessingInformation(final Processing newValue) {
-        checkWritePermission();
+        checkWritePermission(processingInformation);
         processingInformation = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java
index abc249f..676027f 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessStepReport.java
@@ -142,7 +142,7 @@ public class DefaultProcessStepReport extends ISOMetadata implements ProcessStep
      * @param  newValue  the new name value.
      */
     public void setName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(name);
         name = newValue;
     }
 
@@ -163,7 +163,7 @@ public class DefaultProcessStepReport extends ISOMetadata implements ProcessStep
      * @param  newValue  the new description value.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -184,7 +184,7 @@ public class DefaultProcessStepReport extends ISOMetadata implements ProcessStep
      * @param  newValue  the new file type value.
      */
     public void setFileType(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(fileType);
         fileType = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessing.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessing.java
index c4a734f..9aab3ef 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessing.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultProcessing.java
@@ -203,7 +203,7 @@ public class DefaultProcessing extends ISOMetadata implements Processing {
      * @param  newValue  the new procedure description value.
      */
     public void setProcedureDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(procedureDescription);
         procedureDescription = newValue;
     }
 
@@ -244,7 +244,7 @@ public class DefaultProcessing extends ISOMetadata implements Processing {
      * @param  newValue  the new runtime parameter value.
      */
     public void setRunTimeParameters(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(runTimeParameters);
         runTimeParameters = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
index 99fe75b..538e294 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/lineage/DefaultSource.java
@@ -233,7 +233,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @param  newValue  the new description.
      */
     public void setDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(description);
         description = newValue;
     }
 
@@ -259,7 +259,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @since 0.5
      */
     public void setSourceSpatialResolution(final Resolution newValue) {
-        checkWritePermission();
+        checkWritePermission(sourceSpatialResolution);
         sourceSpatialResolution = newValue;
     }
 
@@ -297,7 +297,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      */
     @Deprecated
     public void setScaleDenominator(final RepresentativeFraction newValue)  {
-        checkWritePermission();
+        checkWritePermission(sourceSpatialResolution);
         Resolution resolution = null;
         if (newValue != null) {
             resolution = sourceSpatialResolution;
@@ -334,7 +334,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @param  newValue  the new reference system.
      */
     public void setSourceReferenceSystem(final ReferenceSystem newValue) {
-        checkWritePermission();
+        checkWritePermission(sourceReferenceSystem);
         sourceReferenceSystem = newValue;
     }
 
@@ -355,7 +355,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @param  newValue  the new source citation.
      */
     public void setSourceCitation(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(sourceCitation);
         sourceCitation = newValue;
     }
 
@@ -406,7 +406,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @since 0.5
      */
     public void setScope(final Scope newValue){
-        checkWritePermission();
+        checkWritePermission(scope);
         scope = newValue;
     }
 
@@ -450,7 +450,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      */
     @Deprecated
     public void setSourceExtents(final Collection<? extends Extent> newValues) {
-        checkWritePermission();
+        checkWritePermission(scope);
         Scope scope = this.scope;
         if (!(scope instanceof DefaultScope)) {
             scope = new DefaultScope(scope);
@@ -496,7 +496,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @param  newValue  the new processed level value.
      */
     public void setProcessedLevel(final Identifier newValue) {
-        checkWritePermission();
+        checkWritePermission(processedLevel);
         processedLevel = newValue;
     }
 
@@ -517,7 +517,7 @@ public class DefaultSource extends ISOMetadata implements Source {
      * @param  newValue  the new nominal resolution value.
      */
     public void setResolution(final NominalResolution newValue) {
-        checkWritePermission();
+        checkWritePermission(resolution);
         resolution = newValue;
     }
 
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 259ad5d..7f4504f 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
@@ -198,7 +198,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      * @param  newValue  the new maintenance frequency.
      */
     public void setMaintenanceAndUpdateFrequency(final MaintenanceFrequency newValue) {
-        checkWritePermission();
+        checkWritePermission(maintenanceAndUpdateFrequency);
         maintenanceAndUpdateFrequency = newValue;
     }
 
@@ -262,7 +262,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      */
     @Deprecated
     public void setDateOfNextUpdate(final Date newValue) {
-        checkWritePermission();
+        checkWritePermission(maintenanceDates);
         Collection<CitationDate> dates = maintenanceDates;
         if (dates != null) {
             final Iterator<CitationDate> it = dates.iterator();
@@ -307,7 +307,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      * @param  newValue  the new user defined maintenance frequency.
      */
     public void setUserDefinedMaintenanceFrequency(final PeriodDuration newValue) {
-        checkWritePermission();
+        checkWritePermission(userDefinedMaintenanceFrequency);
         userDefinedMaintenanceFrequency = newValue;
     }
 
@@ -383,7 +383,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      */
     @Deprecated
     public void setUpdateScopes(final Collection<? extends ScopeCode> newValues) {
-        checkWritePermission();
+        checkWritePermission(maintenanceScopes);
         ((LegacyPropertyAdapter<ScopeCode,?>) getUpdateScopes()).setValues(newValues);
     }
 
@@ -438,7 +438,7 @@ public class DefaultMaintenanceInformation extends ISOMetadata implements Mainte
      */
     @Deprecated
     public void setUpdateScopeDescriptions(final Collection<? extends ScopeDescription> newValues) {
-        checkWritePermission();
+        checkWritePermission(maintenanceScopes);
         ((LegacyPropertyAdapter<ScopeDescription,?>) getUpdateScopeDescriptions()).setValues(newValues);
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java
index 054bb90..7aee4f8 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/maintenance/DefaultScope.java
@@ -161,7 +161,7 @@ public class DefaultScope extends ISOMetadata implements Scope {
      * @param  newValue  the new level.
      */
     public void setLevel(final ScopeCode newValue) {
-        checkWritePermission();
+        checkWritePermission(level);
         level = newValue;
     }
 
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 6b2c2e0..2000a20 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
@@ -295,7 +295,7 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * @param  newValue  the new dataset.
      */
     public void setDataset(final String newValue) {
-        checkWritePermission();
+        checkWritePermission(value);
         if (newValue != null || property == DATASET) {
             warningOnOverwrite(DATASET);
             property = DATASET;
@@ -461,7 +461,7 @@ public class DefaultScopeDescription extends ISOMetadata implements ScopeDescrip
      * @param newValue Other class of information.
      */
     public void setOther(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(value);
         if (newValue != null || property == OTHER) {
             warningOnOverwrite(OTHER);
             property = OTHER;
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/AbstractElement.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/AbstractElement.java
index 0412bd4..8d11995 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/AbstractElement.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/AbstractElement.java
@@ -430,7 +430,7 @@ public class AbstractElement extends ISOMetadata implements Element {
      * @param  newValue  the new measure identification.
      */
     public void setMeasureIdentification(final Identifier newValue)  {
-        checkWritePermission();
+        checkWritePermission(measureIdentification);
         measureIdentification = newValue;
     }
 
@@ -453,7 +453,7 @@ public class AbstractElement extends ISOMetadata implements Element {
      * @param  newValue  the new measure description.
      */
     public void setMeasureDescription(final InternationalString newValue)  {
-        checkWritePermission();
+        checkWritePermission(measureDescription);
         measureDescription = newValue;
     }
 
@@ -476,7 +476,7 @@ public class AbstractElement extends ISOMetadata implements Element {
      * @param  newValue  the new evaluation method type.
      */
     public void setEvaluationMethodType(final EvaluationMethodType newValue)  {
-        checkWritePermission();
+        checkWritePermission(evaluationMethodType);
         evaluationMethodType = newValue;
     }
 
@@ -499,7 +499,7 @@ public class AbstractElement extends ISOMetadata implements Element {
      * @param  newValue  the new evaluation method description.
      */
     public void setEvaluationMethodDescription(final InternationalString newValue)  {
-        checkWritePermission();
+        checkWritePermission(evaluationMethodDescription);
         evaluationMethodDescription = newValue;
     }
 
@@ -522,7 +522,7 @@ public class AbstractElement extends ISOMetadata implements Element {
      * @param  newValue  the new evaluation procedure.
      */
     public void setEvaluationProcedure(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(evaluationProcedure);
         evaluationProcedure = newValue;
     }
 
@@ -553,7 +553,7 @@ public class AbstractElement extends ISOMetadata implements Element {
      * @param  newValues  the new dates, or {@code null}.
      */
     public void setDates(final Collection<? extends Date> newValues) {
-        checkWritePermission();
+        checkWritePermission(dates);
         if (newValues != dates) {               // Mandatory check for avoiding the call to 'dates.clear()'.
             writeDates(newValues);
         }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java
index 83f2e29..bb15568 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultConformanceResult.java
@@ -166,7 +166,7 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma
      * @param  newValue  the new specification.
      */
     public void setSpecification(final Citation newValue) {
-        checkWritePermission();
+        checkWritePermission(specification);
         specification = newValue;
     }
 
@@ -187,7 +187,7 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma
      * @param  newValue  the new explanation.
      */
     public void setExplanation(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(explanation);
         explanation = newValue;
     }
 
@@ -207,7 +207,7 @@ public class DefaultConformanceResult extends AbstractResult implements Conforma
      * @param newValue {@code true} if the test pass.
      */
     public void setPass(final Boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(pass);
         pass = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultCoverageResult.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultCoverageResult.java
index f997a42..e36d1a1 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultCoverageResult.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultCoverageResult.java
@@ -166,7 +166,7 @@ public class DefaultCoverageResult extends AbstractResult implements CoverageRes
      * @param  newValue  the new spatial representation type value.
      */
     public void setSpatialRepresentationType(final SpatialRepresentationType newValue) {
-        checkWritePermission();
+        checkWritePermission(spatialRepresentationType);
         spatialRepresentationType = newValue;
     }
 
@@ -187,7 +187,7 @@ public class DefaultCoverageResult extends AbstractResult implements CoverageRes
      * @param  newValue  the new spatial representation value.
      */
     public void setResultSpatialRepresentation(final SpatialRepresentation newValue) {
-        checkWritePermission();
+        checkWritePermission(resultSpatialRepresentation);
         resultSpatialRepresentation = newValue;
     }
 
@@ -210,7 +210,7 @@ public class DefaultCoverageResult extends AbstractResult implements CoverageRes
      * @param  newValue  the new content description value.
      */
     public void setResultContentDescription(final CoverageDescription newValue) {
-        checkWritePermission();
+        checkWritePermission(resultContentDescription);
         resultContentDescription = newValue;
     }
 
@@ -231,7 +231,7 @@ public class DefaultCoverageResult extends AbstractResult implements CoverageRes
      * @param  newValue  the new result format value.
      */
     public void setResultFormat(final Format newValue) {
-        checkWritePermission();
+        checkWritePermission(resultFormat);
         resultFormat = newValue;
     }
 
@@ -252,7 +252,7 @@ public class DefaultCoverageResult extends AbstractResult implements CoverageRes
      * @param  newValue  the new result file value.
      */
     public void setResultFile(final DataFile newValue) {
-        checkWritePermission();
+        checkWritePermission(resultFile);
         resultFile = newValue;
     }
 }
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 4149399..9429bda 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
@@ -178,7 +178,7 @@ public class DefaultDataQuality extends ISOMetadata implements DataQuality {
      * @param  newValue  the new scope.
      */
     public void setScope(final Scope newValue) {
-        checkWritePermission();
+        checkWritePermission(scope);
         scope = newValue;
     }
 
@@ -221,7 +221,7 @@ public class DefaultDataQuality extends ISOMetadata implements DataQuality {
      * @param  newValue  the new lineage.
      */
     public void setLineage(final Lineage newValue) {
-        checkWritePermission();
+        checkWritePermission(lineage);
         lineage = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResult.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResult.java
index 63409a5..aadbc2a 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResult.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResult.java
@@ -193,7 +193,7 @@ public class DefaultQuantitativeResult extends AbstractResult implements Quantit
      * @param  newValue  the new value type.
      */
     public void setValueType(final RecordType newValue) {
-        checkWritePermission();
+        checkWritePermission(valueType);
         valueType = newValue;
     }
 
@@ -214,7 +214,7 @@ public class DefaultQuantitativeResult extends AbstractResult implements Quantit
      * @param  newValue  the new value unit.
      */
     public void setValueUnit(final Unit<?> newValue) {
-        checkWritePermission();
+        checkWritePermission(valueUnit);
         valueUnit = newValue;
     }
 
@@ -237,7 +237,7 @@ public class DefaultQuantitativeResult extends AbstractResult implements Quantit
      * @param  newValue  the new error statistic.
      */
     public void setErrorStatistic(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(errorStatistic);
         errorStatistic = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
index 892fb24..4d344a0 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultDimension.java
@@ -189,7 +189,7 @@ public class DefaultDimension extends ISOMetadata implements Dimension {
      * @param  newValue  the new dimension name.
      */
     public void setDimensionName(final DimensionNameType newValue) {
-        checkWritePermission();
+        checkWritePermission(dimensionName);
         dimensionName = newValue;
     }
 
@@ -212,7 +212,7 @@ public class DefaultDimension extends ISOMetadata implements Dimension {
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setDimensionSize(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(dimensionSize);
         if (ensurePositive(DefaultDimension.class, "dimensionSize", false, newValue)) {
             dimensionSize = newValue;
         }
@@ -238,8 +238,8 @@ public class DefaultDimension extends ISOMetadata implements Dimension {
      * @throws IllegalArgumentException if the given value is NaN, zero or negative.
      */
     public void setResolution(final Double newValue) {
-        checkWritePermission();
-        if (ensurePositive(DefaultDimension.class, "dimensionSize", true, newValue)) {
+        checkWritePermission(resolution);
+        if (ensurePositive(DefaultDimension.class, "resolution", true, newValue)) {
             resolution = newValue;
         }
     }
@@ -269,7 +269,7 @@ public class DefaultDimension extends ISOMetadata implements Dimension {
      * @since 0.5
      */
     public void setDimensionTitle(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(dimensionTitle);
         dimensionTitle = newValue;
     }
 
@@ -295,7 +295,7 @@ public class DefaultDimension extends ISOMetadata implements Dimension {
      * @since 0.5
      */
     public void setDimensionDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(dimensionDescription);
         dimensionDescription = newValue;
     }
 }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java
index 6b27b06..469a0e3 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCP.java
@@ -141,7 +141,7 @@ public class DefaultGCP extends ISOMetadata implements GCP {
      * @param  newValue  the new geographic coordinates values.
      */
     public void setGeographicCoordinates(final DirectPosition newValue) {
-        checkWritePermission();
+        checkWritePermission(geographicCoordinates);
         geographicCoordinates = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java
index c62295b..22d7793 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGCPCollection.java
@@ -157,7 +157,7 @@ public class DefaultGCPCollection extends AbstractGeolocationInformation impleme
      * @param  newValue  the new collection identifier value.
      */
     public void setCollectionIdentification(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(collectionIdentification);
         collectionIdentification = newValue;
     }
 
@@ -178,7 +178,7 @@ public class DefaultGCPCollection extends AbstractGeolocationInformation impleme
      * @param  newValue  the new collection name.
      */
     public void setCollectionName(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(collectionName);
         collectionName = newValue;
     }
 
@@ -199,7 +199,7 @@ public class DefaultGCPCollection extends AbstractGeolocationInformation impleme
      * @param  newValue  the new coordinate reference system value.
      */
     public void setCoordinateReferenceSystem(final ReferenceSystem newValue) {
-        checkWritePermission();
+        checkWritePermission(coordinateReferenceSystem);
         coordinateReferenceSystem = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeometricObjects.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeometricObjects.java
index f3af057..0ed0d14 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeometricObjects.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeometricObjects.java
@@ -152,7 +152,7 @@ public class DefaultGeometricObjects extends ISOMetadata implements GeometricObj
      * @param  newValue  the new geometric object type.
      */
     public void setGeometricObjectType(final GeometricObjectType newValue) {
-        checkWritePermission();
+        checkWritePermission(geometricObjectType);
         geometricObjectType = newValue;
     }
 
@@ -175,7 +175,7 @@ public class DefaultGeometricObjects extends ISOMetadata implements GeometricObj
      * @throws IllegalArgumentException if the given value is zero or negative.
      */
     public void setGeometricObjectCount(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(geometricObjectCount);
         if (ensurePositive(DefaultGeometricObjects.class, "geometricObjectCount", true, newValue)) {
             geometricObjectCount = newValue;
         }
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
index be472d7..e1ceea0 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeorectified.java
@@ -219,7 +219,7 @@ public class DefaultGeorectified extends DefaultGridSpatialRepresentation implem
      * @param newValue {@code true} if check points are available.
      */
     public void setCheckPointAvailable(final boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(CHECK_POINT_MASK));
         if (newValue) {
             booleans |= CHECK_POINT_MASK;
         } else {
@@ -255,7 +255,7 @@ public class DefaultGeorectified extends DefaultGridSpatialRepresentation implem
      * @param  newValue  the new check point description.
      */
     public void setCheckPointDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(checkPointDescription);
         checkPointDescription = newValue;
         if (newValue != null) {
             booleans |= CHECK_POINT_MASK;
@@ -308,7 +308,7 @@ public class DefaultGeorectified extends DefaultGridSpatialRepresentation implem
      * @param  newValue  the new center point.
      */
     public void setCenterPoint(final Point newValue) {
-        checkWritePermission();
+        checkWritePermission(centerPoint);
         centerPoint = newValue;
     }
 
@@ -329,7 +329,7 @@ public class DefaultGeorectified extends DefaultGridSpatialRepresentation implem
      * @param  newValue  the new point in a pixel.
      */
     public void setPointInPixel(final PixelOrientation newValue) {
-        checkWritePermission();
+        checkWritePermission(pointInPixel);
         pointInPixel = newValue;
     }
 
@@ -350,7 +350,7 @@ public class DefaultGeorectified extends DefaultGridSpatialRepresentation implem
      * @param  newValue  the new general description.
      */
     public void setTransformationDimensionDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(transformationDimensionDescription);
         transformationDimensionDescription = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeoreferenceable.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeoreferenceable.java
index ebd42db..fe3f168 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeoreferenceable.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGeoreferenceable.java
@@ -187,7 +187,7 @@ public class DefaultGeoreferenceable extends DefaultGridSpatialRepresentation im
      * @param newValue {@code true} if control points are available.
      */
     public void setControlPointAvailable(final boolean newValue) {
-       checkWritePermission();
+       checkWritePermission(isDefined(CONTROL_POINT_MASK));
         if (newValue) {
             booleans |= CONTROL_POINT_MASK;
         } else {
@@ -212,7 +212,7 @@ public class DefaultGeoreferenceable extends DefaultGridSpatialRepresentation im
      * @param newValue {@code true} if orientation parameter are available.
      */
     public void setOrientationParameterAvailable(final boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(OPERATION_MASK));
         if (newValue) {
             booleans |= OPERATION_MASK;
         } else {
@@ -237,7 +237,7 @@ public class DefaultGeoreferenceable extends DefaultGridSpatialRepresentation im
      * @param  newValue  the new orientation parameter description.
      */
     public void setOrientationParameterDescription(final InternationalString newValue) {
-        checkWritePermission();
+        checkWritePermission(orientationParameterDescription);
         orientationParameterDescription = newValue;
     }
 
@@ -258,7 +258,7 @@ public class DefaultGeoreferenceable extends DefaultGridSpatialRepresentation im
      * @param  newValue  the new georeferenced parameters.
      */
     public void setGeoreferencedParameters(final Record newValue) {
-        checkWritePermission();
+        checkWritePermission(georeferencedParameters);
         georeferencedParameters = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGridSpatialRepresentation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGridSpatialRepresentation.java
index 53d5ca7..1d1a6d7 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGridSpatialRepresentation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultGridSpatialRepresentation.java
@@ -203,7 +203,7 @@ public class DefaultGridSpatialRepresentation extends AbstractSpatialRepresentat
      * @throws IllegalArgumentException if the given value is negative.
      */
     public void setNumberOfDimensions(final Integer newValue) {
-        checkWritePermission();
+        checkWritePermission(numberOfDimensions);
         if (ensurePositive(DefaultGridSpatialRepresentation.class, "numberOfDimensions", false, newValue)) {
             numberOfDimensions = newValue;
         }
@@ -226,9 +226,7 @@ public class DefaultGridSpatialRepresentation extends AbstractSpatialRepresentat
      * @param  newValues  the new axis dimension properties.
      */
     public void setAxisDimensionProperties(final List<? extends Dimension> newValues) {
-        checkWritePermission();
-        axisDimensionProperties = (List<Dimension>)
-                writeCollection(newValues, axisDimensionProperties, Dimension.class);
+        axisDimensionProperties = writeList(newValues, axisDimensionProperties, Dimension.class);
     }
 
     /**
@@ -248,11 +246,18 @@ public class DefaultGridSpatialRepresentation extends AbstractSpatialRepresentat
      * @param  newValue  the new cell geometry.
      */
     public void setCellGeometry(final CellGeometry newValue) {
-        checkWritePermission();
+        checkWritePermission(cellGeometry);
         cellGeometry = newValue;
     }
 
     /**
+     * Returns {@link Boolean#TRUE} if the given flag is set, or {@code null} otherwise.
+     */
+    final Boolean isDefined(final byte mask) {
+        return (booleans & mask) != 0 ? Boolean.TRUE : null;
+    }
+
+    /**
      * Returns indication of whether or not parameters for transformation exists.
      *
      * @return whether or not parameters for transformation exists.
@@ -269,7 +274,7 @@ public class DefaultGridSpatialRepresentation extends AbstractSpatialRepresentat
      * @param newValue {@code true} if the transformation parameters are available.
      */
     public void setTransformationParameterAvailable(final boolean newValue) {
-        checkWritePermission();
+        checkWritePermission(isDefined(TRANSFORMATION_MASK));
         if (newValue) {
             booleans |= TRANSFORMATION_MASK;
         } else {
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultVectorSpatialRepresentation.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultVectorSpatialRepresentation.java
index c853abd..28071f1 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultVectorSpatialRepresentation.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/spatial/DefaultVectorSpatialRepresentation.java
@@ -132,7 +132,7 @@ public class DefaultVectorSpatialRepresentation extends AbstractSpatialRepresent
      * @param  newValue  the new topology level.
      */
     public void setTopologyLevel(final TopologyLevel newValue) {
-        checkWritePermission();
+        checkWritePermission(topologyLevel);
         topologyLevel = newValue;
     }
 
diff --git a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java
index 1ca0e4a..4a43928 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/MetadataFallback.java
@@ -183,11 +183,15 @@ final class MetadataFallback extends MetadataSource {
                 break;
             }
             case Constants.PROJ4: {
-                title = "Proj";
+                title     = "Proj";
+                code      = "Proj4";
+                codeSpace = "OSGeo";
                 break;
             }
             case "IHO S-57": {
-                title = "S-57";
+                title = code     = "S-57";
+                codeSpace        = "IHO";
+                version          = "3.1";
                 presentationForm = PresentationForm.DOCUMENT_DIGITAL;
                 break;
             }