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 7997e9f0068c4c3ecd0fa292eed90c43a17ee4a1
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Oct 3 14:40:03 2025 +0200

    Prepare the classes related to `org.opengis.util.Record` for removal.
    For now, we only put a warning in the Javadoc (not yet a deprecation)
    and we reduce the possibility to customize `DefaultRecordSchema`.
    Those records classes have been removed in ISO 19103:2024,
    but we have not yet decided what would be their replacement.
---
 .../metadata/internal/shared/RecordSchemaSIS.java  | 108 -----------------
 .../org/apache/sis/util/iso/DefaultNameSpace.java  |   6 +-
 .../org/apache/sis/util/iso/DefaultRecord.java     |  26 +++--
 .../apache/sis/util/iso/DefaultRecordSchema.java   | 128 ++++++++++++---------
 .../org/apache/sis/util/iso/DefaultRecordType.java |  86 ++++++++++----
 .../main/org/apache/sis/util/iso/package-info.java |   9 +-
 .../apache/sis/metadata/iso/MarshallingTest.java   |  16 +--
 .../iso/quality/DefaultQuantitativeResultTest.java |  23 ++--
 .../sis/util/iso/DefaultRecordSchemaTest.java      |  21 +++-
 .../org/apache/sis/util/iso/DefaultRecordTest.java |  13 ++-
 .../apache/sis/util/iso/DefaultRecordTypeTest.java |  10 +-
 .../sis/util/iso/SerializableRecordSchema.java     |  81 -------------
 .../internal/PositionalAccuracyConstant.java       |   4 +-
 .../test/org/apache/sis/test/TestCase.java         |   1 +
 14 files changed, 206 insertions(+), 326 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/shared/RecordSchemaSIS.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/shared/RecordSchemaSIS.java
deleted file mode 100644
index ebc4caa136..0000000000
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/internal/shared/RecordSchemaSIS.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.metadata.internal.shared;
-
-import java.util.Map;
-import java.io.Serializable;
-import java.io.ObjectStreamException;
-import org.opengis.util.TypeName;
-import org.opengis.util.InternationalString;
-import org.apache.sis.metadata.internal.Resources;
-import org.apache.sis.util.internal.shared.Constants;
-import org.apache.sis.util.iso.DefaultRecordType;
-import org.apache.sis.util.iso.DefaultRecordSchema;
-import org.apache.sis.util.resources.Vocabulary;
-
-
-/**
- * The system-wide schema in the "SIS" namespace.
- *
- * @author  Martin Desruisseaux (Geomatys)
- */
-@SuppressWarnings({"serial", "removal"})  // serialVersionUID not needed 
because of writeReplace().
-public final class RecordSchemaSIS extends DefaultRecordSchema implements 
Serializable {
-    /**
-     * The schema used in SIS for creating records.
-     */
-    public static final DefaultRecordSchema INSTANCE = new RecordSchemaSIS();
-
-    /**
-     * The type name for a record having an unknown number of fields.
-     * This is used at {@code <gco:RecordType>} unmarshalling time,
-     * where the type is not well defined, by assuming one field per line.
-     *
-     * @see <a href="https://issues.apache.org/jira/browse/SIS-419";>SIS-419</a>
-     */
-    public static final TypeName MULTILINE = INSTANCE.createRecordTypeName(
-            Resources.formatInternational(Resources.Keys.MultilineRecord));
-
-    /**
-     * The type of record instances for holding a single {@link String} value.
-     */
-    public static final DefaultRecordType STRING;
-
-    /**
-     * The type of record instances for holding a single {@link Double} value.
-     */
-    public static final DefaultRecordType REAL;
-    static {
-        final InternationalString field = 
Vocabulary.formatInternational(Vocabulary.Keys.Value);
-        STRING = singleton(Resources.Keys.SingleText,   field, String.class);
-        REAL   = singleton(Resources.Keys.SingleNumber, field, Double.class);
-    }
-
-    /**
-     * Creates the unique instance.
-     */
-    private RecordSchemaSIS() {
-        super(null, null, Constants.SIS);
-    }
-
-    /**
-     * Creates a new record type of the given name, which will contain the 
given field.
-     *
-     * @param  typeName    the record type name as a {@link Resources.Keys} 
code.
-     * @param  field       the name of the singleton record field.
-     * @param  valueClass  the expected value type for the singleton field.
-     * @return a record type of the given name and field.
-     */
-    private static DefaultRecordType singleton(final short typeName, final 
InternationalString field, final Class<?> valueClass) {
-        return (DefaultRecordType) 
INSTANCE.createRecordType(Resources.formatInternational(typeName), 
Map.of(field, valueClass));
-    }
-
-    /**
-     * On serialization, returns a proxy which will be resolved as {@link 
#INSTANCE} on deserialization.
-     *
-     * @return the object to use after deserialization.
-     * @throws ObjectStreamException if the serialized object defines an 
unknown data type.
-     */
-    protected Object writeReplace() throws ObjectStreamException {
-        return new Proxy();
-    }
-
-    /**
-     * The object to serialize instead of {@link DefaultRecordSchema}.
-     * This proxy is itself replaced by {@link RecordSchemaSIS#INSTANCE} on 
deserialization.
-     */
-    private static final class Proxy implements Serializable {
-        private static final long serialVersionUID = -4381124182735566127L;
-
-        Object readResolve() throws ObjectStreamException {
-            return INSTANCE;
-        }
-    }
-}
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultNameSpace.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultNameSpace.java
index a4e14627e3..e98e0f1a8d 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultNameSpace.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultNameSpace.java
@@ -274,7 +274,7 @@ public class DefaultNameSpace implements NameSpace, 
Serializable {
      */
     public static String getSeparator(final NameSpace ns, final boolean head) {
         if (ns instanceof DefaultNameSpace) {
-            final DefaultNameSpace ds = (DefaultNameSpace) ns;
+            final var ds = (DefaultNameSpace) ns;
             return head ? ds.headSeparator : ds.separator;
         }
         return DEFAULT_SEPARATOR_STRING;
@@ -333,7 +333,7 @@ public class DefaultNameSpace implements NameSpace, 
Serializable {
                 return path;
             }
             depth = depth(this);
-            final DefaultLocalName[] names = new DefaultLocalName[depth];
+            final var names = new DefaultLocalName[depth];
             DefaultNameSpace scan = this;
             for (int i=depth; --i>=0;) {
                 names[i] = new DefaultLocalName(scan.parent, scan.name);
@@ -536,7 +536,7 @@ public class DefaultNameSpace implements NameSpace, 
Serializable {
     @Override
     public boolean equals(final Object object) {
         if (object != null && object.getClass() == getClass()) {
-            final DefaultNameSpace that = (DefaultNameSpace) object;
+            final var that = (DefaultNameSpace) object;
             return equalsIgnoreParent(that) && Objects.equals(this.parent, 
that.parent);
         }
         return false;
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecord.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecord.java
index ac464b57cc..6a5eb66750 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecord.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecord.java
@@ -33,7 +33,6 @@ import org.apache.sis.util.Utilities;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.internal.shared.Strings;
 import org.apache.sis.util.internal.shared.AbstractMapEntry;
-import org.apache.sis.metadata.internal.shared.RecordSchemaSIS;
 
 
 /**
@@ -43,24 +42,24 @@ import 
org.apache.sis.metadata.internal.shared.RecordSchemaSIS;
  * Since all fields are expected to be assigned a value, the initial values on 
{@code DefaultRecord}
  * instantiation are unspecified. Some may be null, or some may be zero.
  *
+ * <div class="warning"><b>Possible future change:</b>
+ * This class is derived from ISO 19103:2005. The record attributes and 
methods have been modified
+ * in ISO 19103:2015, then all classes related to records have been fully 
removed in ISO 19103:2024.
+ * The implication for Apache <abbr>SIS</abbr> has not yet been determined.
+ * This class may be replaced by a simple {@code Feature}.</div>
+ *
  * <h2>Limitations</h2>
  * <ul>
  *   <li><b>Multi-threading:</b> {@code DefaultRecord} instances are 
<strong>not</strong> thread-safe.
  *       Synchronization, if needed, shall be done externally by the 
caller.</li>
- *   <li><b>Serialization:</b> this class is serializable if the associated 
{@code RecordType} and all
- *        values are also serializable. Note in particular that {@link 
DefaultRecordSchema} is currently
- *        <strong>not</strong> serializable, so users wanting serialization 
may need to define their own
- *        schema implementation.</li>
+ *   <li><b>Serialization:</b> this class is serializable only if the 
associated {@code RecordType}
+ *        and all values are also serializable.</li>
  * </ul>
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Cullen Rombach (Image Matters)
- * @version 1.4
- *
- * @see DefaultRecordType
- * @see DefaultRecordSchema
- *
- * @since 0.5
+ * @version 1.6
+ * @since   0.5
  */
 public class DefaultRecord implements Record, Serializable {
     /**
@@ -412,14 +411,16 @@ public class DefaultRecord implements Record, 
Serializable {
      * Constructs an initially empty record expecting exactly one value as a 
string.
      * See {@link #setValue(String)} for a description of the supported XML 
content.
      */
+    @SuppressWarnings("unused")
     private DefaultRecord() {
-        definition = RecordSchemaSIS.STRING;
+        definition = DefaultRecordType.SINGLE_STRING;
     }
 
     /**
      * Returns the record value as a string.
      */
     @XmlValue
+    @SuppressWarnings("unused")
     private String getValue() {
         if (values != null) {
             switch (Array.getLength(values)) {
@@ -447,6 +448,7 @@ public class DefaultRecord implements Record, Serializable {
      *
      * @see <a href="https://issues.apache.org/jira/browse/SIS-419";>SIS-419</a>
      */
+    @SuppressWarnings("unused")
     private void setValue(String value) {
         value = Strings.trimOrNull(value);
         if (value != null) {
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordSchema.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordSchema.java
index ee91574252..35bd16dcb3 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordSchema.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordSchema.java
@@ -22,6 +22,8 @@ import java.util.Collections;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ConcurrentHashMap;
+import java.io.Serializable;
+import java.io.ObjectStreamException;
 import org.opengis.util.Type;
 import org.opengis.util.TypeName;
 import org.opengis.util.LocalName;
@@ -37,6 +39,7 @@ import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.collection.WeakValueHashMap;
 import org.apache.sis.metadata.simple.SimpleAttributeType;
 import org.apache.sis.converter.SurjectiveConverter;
+import org.apache.sis.util.internal.shared.Constants;
 import org.apache.sis.util.internal.shared.Strings;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
@@ -44,79 +47,72 @@ import org.opengis.feature.AttributeType;
 
 
 /**
- * A collection of record types in a given namespace.
- * This class works also as a factory for creating {@code RecordType} and 
{@code Record} instances.
- * The factory methods are:
+ * A factory for creating {@code RecordType} instances.
  *
- * <ul>
- *   <li>{@link #createRecordType(CharSequence, Map)}</li>
- * </ul>
- *
- * Subclasses can modify the characteristics of the records to be created
- * by overriding the following methods:
- *
- * <ul>
- *   <li>{@link DefaultNameFactory#toTypeName(Class)} if the factory given to 
the constructor.</li>
- * </ul>
+ * <div class="warning"><b>Possible future change:</b>
+ * This class is derived from ISO 19103:2005. The record attributes and 
methods have been modified
+ * in ISO 19103:2015, then all classes related to records have been fully 
removed in ISO 19103:2024.
+ * The implication for Apache <abbr>SIS</abbr> has not yet been determined.
+ * In the meantime, this class should be considered as merely a factory of 
{@link DefaultRecordType} instances.</div>
  *
  * <h2>Thread safety</h2>
  * The same {@code DefaultRecordSchema} instance can be safely used by many 
threads without synchronization
  * on the part of the caller if the {@link NameFactory} given to the 
constructor is also thread-safe.
  * Subclasses should make sure that any overridden methods remain safe to call 
from multiple threads.
  *
- * <h2>Limitations</h2>
- * This class is currently not serializable because {@code RecordSchema} 
contain an arbitrary number of record
- * types in its {@linkplain #getDescription() description} map. Since each 
{@code RecordType} has a reference
- * to its schema, serializing a single {@code RecordType} could imply 
serializing all of them.
- * In order to reduce the risk of unexpected behavior, serialization is 
currently left to subclasses.
- * For example, a subclass may define a {@code Object readResolve()} method 
(as documented in the
- * {@link java.io.Serializable} interface) returning a system-wide static 
constant for their schema.
- *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.5
+ * @version 1.6
  *
  * @see DefaultRecordType
  * @see DefaultRecord
  *
  * @since 0.5
- *
- * @deprecated The {@code RecordSchema} interface has been removed in the 2015 
revision of the ISO 19103 standard.
  */
-@Deprecated(since = "1.5", forRemoval = true)
-public class DefaultRecordSchema implements RecordSchema {
+@SuppressWarnings("deprecation")
+public final class DefaultRecordSchema implements RecordSchema, Serializable {
     /**
-     * The factory to use for creating names.
-     * This is the factory given at construction time.
+     * For cross-version compatibility.
      */
-    protected final NameFactory nameFactory;
+    private static final long serialVersionUID = -4381124182735566127L;
 
     /**
-     * The helper class to use for mapping Java classes to {@code TypeName} 
instances, or {@code null} if not needed.
-     * This helper class is needed only if {@link #nameFactory} is not an 
instance of {@link DefaultNameFactory}.
+     * The schema used for creating records in <abbr>SIS</abbr> namespace.
      */
-    private final TypeNames typeFactory;
+    static final DefaultRecordSchema SIS = new 
DefaultRecordSchema(Constants.SIS);
+
+    /**
+     * On serialization, returns a singleton instance if possible.
+     *
+     * @return the object to use after deserialization.
+     * @throws ObjectStreamException if the serialized object defines an 
unknown data type.
+     */
+    final Object readResolve() throws ObjectStreamException {
+        final String schemaName = getSchemaName().toString();
+        return Constants.SIS.equals(schemaName) ? SIS : new 
DefaultRecordSchema(schemaName);
+    }
 
     /**
      * The namespace of {@link RecordType} to be created by this class.
      * This is also (indirectly) the {@linkplain #getSchemaName() schema name}.
      */
+    @SuppressWarnings("serial")     // SIS implementations are serializable.
     private final NameSpace namespace;
 
     /**
      * The record types in the namespace of this schema.
      */
-    private final Map<TypeName,RecordType> description;
+    private final transient Map<TypeName, DefaultRecordType> description;
 
     /**
      * The pool of attribute types created so far.
      */
-    private final ConcurrentMap<Class<?>,Type> attributeTypes;
+    private final transient ConcurrentMap<Class<?>, Type> attributeTypes;
 
     /**
      * The converter to use for converting Java {@link Class} to ISO 19103 
{@link Type}.
      * This converter delegates its work to the {@link 
#toAttributeType(Class)} method.
      */
-    private final ObjectConverter<Class<?>,Type> toTypes = new 
SurjectiveConverter<Class<?>, Type>() {
+    private final transient ObjectConverter<Class<?>,Type> toTypes = new 
SurjectiveConverter<Class<?>, Type>() {
         @SuppressWarnings("unchecked")
         @Override public Class<Class<?>> getSourceClass() {return (Class) 
Class.class;}
         @Override public Class<Type>     getTargetClass() {return Type.class;}
@@ -126,18 +122,13 @@ public class DefaultRecordSchema implements RecordSchema {
     /**
      * Creates a new schema of the given name.
      *
-     * @param nameFactory  the factory to use for creating names, or {@code 
null} for the default factory.
-     * @param parent       the parent namespace, or {@code null} if none.
-     * @param schemaName   the name of the new schema.
+     * @param schemaName  the name of the new schema.
+     *
+     * @since 1.6
      */
-    public DefaultRecordSchema(NameFactory nameFactory, final NameSpace 
parent, final CharSequence schemaName) {
-        ArgumentChecks.ensureNonNull("schemaName", schemaName);
-        if (nameFactory == null) {
-            nameFactory = DefaultNameFactory.provider();
-        }
-        this.nameFactory    = nameFactory;
-        this.typeFactory    = (nameFactory instanceof DefaultNameFactory) ? 
null : new TypeNames(nameFactory);
-        this.namespace      = 
nameFactory.createNameSpace(nameFactory.createLocalName(parent, schemaName), 
null);
+    public DefaultRecordSchema(final CharSequence schemaName) {
+        final DefaultNameFactory nameFactory = DefaultNameFactory.provider();
+        this.namespace      = 
nameFactory.createNameSpace(nameFactory.createLocalName(null, schemaName), 
null);
         this.description    = new WeakValueHashMap<>(TypeName.class);
         this.attributeTypes = new ConcurrentHashMap<>();
     }
@@ -161,6 +152,7 @@ public class DefaultRecordSchema implements RecordSchema {
      * @since 1.3
      */
     public TypeName createRecordTypeName(final CharSequence typeName) {
+        final DefaultNameFactory nameFactory = DefaultNameFactory.provider();
         return nameFactory.createTypeName(namespace, 
Objects.requireNonNull(typeName), null);
     }
 
@@ -173,16 +165,17 @@ public class DefaultRecordSchema implements RecordSchema {
      * @return a record type of the given name and fields.
      * @throws IllegalArgumentException if a record already exists for the 
given name but with different fields.
      */
-    public RecordType createRecordType(final CharSequence typeName, final 
Map<CharSequence,Class<?>> fields)
+    public DefaultRecordType createRecordType(final CharSequence typeName, 
final Map<CharSequence,Class<?>> fields)
             throws IllegalArgumentException
     {
         ArgumentChecks.ensureNonNull("fields", fields);
         final TypeName name = createRecordTypeName(typeName);
         final Map<CharSequence,Type> fieldTypes = 
ObjectConverters.derivedValues(fields, CharSequence.class, toTypes);
-        RecordType record;
+        DefaultRecordType record;
         synchronized (description) {
-            record = description.get(typeName);
+            record = description.get(name);
             if (record == null) {
+                final DefaultNameFactory nameFactory = 
DefaultNameFactory.provider();
                 record = new DefaultRecordType(name, this, fieldTypes, 
nameFactory);
                 description.put(name, record);
                 return record;
@@ -227,13 +220,8 @@ public class DefaultRecordSchema implements RecordSchema {
             if (valueClass == Void.TYPE) {
                 throw new 
IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, 
"valueClass", "void"));
             }
-            final TypeName name;
-            if (nameFactory instanceof DefaultNameFactory) {
-                name = ((DefaultNameFactory) 
nameFactory).toTypeName(valueClass);
-            } else {
-                name = typeFactory.toTypeName(nameFactory, valueClass);
-            }
-            type = new SimpleAttributeType<>(name, valueClass);
+            final DefaultNameFactory nameFactory = 
DefaultNameFactory.provider();
+            type = new 
SimpleAttributeType<>(nameFactory.toTypeName(valueClass), valueClass);
             final Type old = attributeTypes.putIfAbsent(valueClass, type);
             if (old != null) {      // May happen if the type has been 
computed concurrently.
                 return old;
@@ -264,8 +252,36 @@ public class DefaultRecordSchema implements RecordSchema {
         return description.get(name);
     }
 
+    /**
+     * Compares the given object with this schema for equality.
+     *
+     * @param  other  the object to compare with this schema.
+     * @return {@code true} if both objects are equal.
+     * @hidden
+     */
+    @Override
+    public boolean equals(final Object other) {
+        if (other instanceof DefaultRecordSchema) {
+            final var that = (DefaultRecordSchema) other;
+            return namespace.equals(that.namespace);
+        }
+        return false;
+    }
+
+    /**
+     * Returns a hash code value for this {@code RecordType}.
+     *
+     * @hidden
+     */
+    @Override
+    public int hashCode() {
+        return namespace.hashCode() ^ (int) serialVersionUID;
+    }
+
     /**
      * Returns a string representation of this schema for debugging purpose 
only.
+     *
+     * @hidden
      */
     @Override
     public String toString() {
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
index 71937351ed..0c94341564 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/DefaultRecordType.java
@@ -37,12 +37,14 @@ import org.opengis.util.NameSpace;
 import org.opengis.util.Record;
 import org.opengis.util.RecordType;
 import org.opengis.util.RecordSchema;
+import org.opengis.util.InternationalString;
 import org.apache.sis.pending.jdk.JDK19;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.ObjectConverters;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.resources.Vocabulary;
 import org.apache.sis.converter.SurjectiveConverter;
-import org.apache.sis.metadata.internal.shared.RecordSchemaSIS;
+import org.apache.sis.metadata.internal.Resources;
 
 // Specific to the geoapi-3.1 and geoapi-4.0 branches:
 import org.opengis.util.NameFactory;
@@ -59,6 +61,12 @@ import org.opengis.util.NameFactory;
  * The set of fields in a {@code RecordType} can be though as equivalent to 
the set of fields in a class.
  * </div>
  *
+ * <div class="warning"><b>Possible future change:</b>
+ * This class is derived from ISO 19103:2005. The record attributes and 
methods have been modified
+ * in ISO 19103:2015, then all classes related to records have been fully 
removed in ISO 19103:2024.
+ * The implication for Apache <abbr>SIS</abbr> has not yet been determined.
+ * This class may be replaced by a simple {@code FeatureType}.</div>
+ *
  * <h2>Immutability and thread safety</h2>
  * This class is immutable and thus inherently thread-safe if the {@link 
TypeName}, the {@link RecordSchema}
  * and all ({@link MemberName}, {@link Type}) entries in the map given to the 
constructor are also immutable.
@@ -67,11 +75,9 @@ import org.opengis.util.NameFactory;
  *
  * <h2>Serialization</h2>
  * This class is serializable if all elements given to the constructor are 
also serializable.
- * Note in particular that {@link DefaultRecordSchema} is currently 
<strong>not</strong> serializable,
- * so users wanting serialization may need to provide their own schema.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.5
+ * @version 1.6
  *
  * @see DefaultRecord
  * @see DefaultMemberName
@@ -85,6 +91,45 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
      */
     private static final long serialVersionUID = -1534515712654429099L;
 
+    /**
+     * The type name for a record having an unknown number of fields.
+     * This is used at {@code <gco:RecordType>} unmarshalling time,
+     * where the type is not well defined, by assuming one field per line.
+     */
+    private static final TypeName MULTILINE = 
DefaultRecordSchema.SIS.createRecordTypeName(
+            Resources.formatInternational(Resources.Keys.MultilineRecord));
+
+    /**
+     * A type of record instances for holding a single {@link String} value.
+     *
+     * @since 1.6
+     */
+    public static final DefaultRecordType SINGLE_STRING;
+
+    /**
+     * A type of record instances for holding a single {@link Double} value.
+     *
+     * @since 1.6
+     */
+    public static final DefaultRecordType SINGLE_REAL;
+    static {
+        final InternationalString field = 
Vocabulary.formatInternational(Vocabulary.Keys.Value);
+        SINGLE_STRING = singleton(Resources.Keys.SingleText,   field, 
String.class);
+        SINGLE_REAL   = singleton(Resources.Keys.SingleNumber, field, 
Double.class);
+    }
+
+    /**
+     * Creates a new record type of the given name with a single field of the 
given name.
+     *
+     * @param  typeName    the record type name as a {@link Resources.Keys} 
code.
+     * @param  fieldName   the name of the singleton record field.
+     * @param  valueClass  the expected value type for the singleton field.
+     * @return a record type of the given name and field.
+     */
+    private static DefaultRecordType singleton(final short typeName, final 
InternationalString fieldName, final Class<?> valueClass) {
+        return 
DefaultRecordSchema.SIS.createRecordType(Resources.formatInternational(typeName),
 Map.of(fieldName, valueClass));
+    }
+
     /**
      * The name that identifies this record type.
      *
@@ -147,14 +192,9 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
      * @param fields     the name and type of the fields to be included in 
this record type.
      *
      * @see DefaultRecordSchema#createRecordType(CharSequence, Map)
-     *
-     * @deprecated The {@code RecordSchema} interface has been removed in the 
2015 revision of the ISO 19103 standard.
      */
-    @SuppressWarnings("this-escape")
-    @Deprecated(since = "1.5", forRemoval = true)
-    public DefaultRecordType(final TypeName typeName, final RecordSchema 
container,
-            final Map<? extends MemberName, ? extends Type> fields)
-    {
+    @SuppressWarnings({"deprecation", "this-escape"})
+    DefaultRecordType(final TypeName typeName, final RecordSchema container, 
final Map<? extends MemberName, ? extends Type> fields) {
         this.typeName   = Objects.requireNonNull(typeName);
         this.container  = container;
         this.fieldTypes = computeTransientFields(fields);
@@ -194,7 +234,7 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
      *
      * @deprecated To be removed after {@link DefaultRecordSchema} has been 
removed.
      */
-    @Deprecated(since = "1.5", forRemoval = true)
+    @Deprecated(since = "1.5")
     DefaultRecordType(final TypeName typeName, final RecordSchema container,
             final Map<? extends CharSequence, ? extends Type> fields, final 
NameFactory nameFactory)
     {
@@ -227,7 +267,7 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
         final int size = in.readInt();
         final Map<MemberName,Type> fields = JDK19.newLinkedHashMap(size);
         for (int i=0; i<size; i++) {
-            final MemberName member = (MemberName) in.readObject();
+            final var member = (MemberName) in.readObject();
             final Type type = (Type) in.readObject();
             if (fields.put(member, type) != null) {
                 throw new 
InvalidObjectException(Errors.format(Errors.Keys.DuplicatedElement_1, member));
@@ -290,13 +330,7 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
     }
 
     /**
-     * Returns the name that identifies this record type. If this {@code 
RecordType} is contained in a
-     * {@linkplain DefaultRecordSchema record schema}, then the record type 
name shall be valid in the
-     * {@linkplain DefaultNameSpace name space} of the record schema:
-     *
-     * {@snippet lang="java" :
-     *     NameSpace namespace = getContainer().getSchemaName().scope()
-     *     }
+     * Returns the name that identifies this record type.
      *
      * <div class="note"><b>Comparison with Java reflection:</b>
      * If we think about this {@code RecordType} as equivalent to a {@code 
Class} instance,
@@ -419,7 +453,7 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
             return true;
         }
         if (other != null && other.getClass() == getClass()) {
-            final DefaultRecordType that = (DefaultRecordType) other;
+            final var that = (DefaultRecordType) other;
             return Objects.equals(typeName,   that.typeName)   &&
                    Objects.equals(container,  that.container)  &&
                    Arrays .equals(fieldTypes, that.fieldTypes) &&
@@ -458,8 +492,8 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
      */
     @SuppressWarnings("unused")
     private DefaultRecordType() {
-        typeName  = RecordSchemaSIS.MULTILINE;
-        container = RecordSchemaSIS.STRING.container;
+        typeName  = MULTILINE;
+        container = DefaultRecordSchema.SIS;
     }
 
     /**
@@ -467,6 +501,7 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
      * one field per line, but it may change in any future version for 
adapting to common practice.
      */
     @XmlValue
+    @SuppressWarnings("unused")
     private String getValue() {
         switch (size()) {
             case 0:  return null;
@@ -489,9 +524,10 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
      *
      * @see <a href="https://issues.apache.org/jira/browse/SIS-419";>SIS-419</a>
      */
+    @SuppressWarnings("unused")
     private void setValue(final String value) {
         if (value != null) {
-            final Map<MemberName,Type> fields = new LinkedHashMap<>();
+            final var fields = new LinkedHashMap<MemberName, Type>();
             for (CharSequence element : CharSequences.splitOnEOL(value)) {
                 final int s = ((String) element).indexOf(':');
                 if (s >= 0) {
@@ -499,7 +535,7 @@ public class DefaultRecordType extends RecordDefinition 
implements RecordType, S
                     // TODO: the part after ":" is the description. For now, 
we have no room for storing it.
                 }
                 final MemberName m = Names.createMemberName(typeName, element, 
String.class);
-                fields.put(m, 
RecordSchemaSIS.INSTANCE.toAttributeType(String.class));
+                fields.put(m, 
DefaultRecordSchema.SIS.toAttributeType(String.class));
             }
             fieldTypes = computeTransientFields(fields);
         }
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/package-info.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/package-info.java
index 717e892a63..59a6e79ced 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/package-info.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/util/iso/package-info.java
@@ -28,13 +28,6 @@
  *       <li>{@link org.apache.sis.util.iso.DefaultScopedName} for a composite 
of a <i>head</i> name and a <i>tail</i> name.</li>
  *     </ul>
  *   </li>
- *   <li>Implementations of {@link org.opengis.util.Record} and related 
classes (derived from ISO 19103):
- *     <ul>
- *       <li>{@link org.apache.sis.util.iso.DefaultRecord}       for a list of 
logically related elements as (<var>name</var>, <var>value</var>) pairs.</li>
- *       <li>{@link org.apache.sis.util.iso.DefaultRecordType}   for 
definition of the type of a {@code Record}.</li>
- *       <li>{@link org.apache.sis.util.iso.DefaultRecordSchema} for a 
collection of {@code RecordType}s in a given namespace.</li>
- *     </ul>
- *   </li>
  *   <li>Static utility methods:
  *     <ul>
  *       <li>{@link org.apache.sis.util.iso.Types} for working with UML 
identifiers and description of GeoAPI types.</li>
@@ -99,7 +92,7 @@
  * </table>
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.5
+ * @version 1.6
  * @since   0.3
  */
 @XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace = 
Namespaces.GCO, xmlns = {
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/MarshallingTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/MarshallingTest.java
index b6ed972225..1be0ea128d 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/MarshallingTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/MarshallingTest.java
@@ -22,7 +22,6 @@ import java.util.List;
 import java.util.Set;
 import java.util.Map;
 import java.util.Collection;
-import java.util.LinkedHashMap;
 import java.util.MissingResourceException;
 import java.util.logging.Filter;
 import java.util.logging.LogRecord;
@@ -56,7 +55,6 @@ import org.apache.sis.metadata.iso.maintenance.*;
 import org.apache.sis.metadata.iso.spatial.*;
 import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.util.DefaultInternationalString;
-import org.apache.sis.util.iso.DefaultRecordSchema;
 import org.apache.sis.util.iso.Names;
 import org.apache.sis.measure.Units;
 import org.apache.sis.xml.XML;
@@ -70,6 +68,7 @@ import 
org.apache.sis.xml.bind.metadata.replace.ReferenceSystemMetadata;
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.metadata.xml.TestUsingFile;
+import org.apache.sis.util.iso.DefaultRecordSchemaTest;
 
 
 /**
@@ -81,6 +80,7 @@ import org.apache.sis.metadata.xml.TestUsingFile;
  *
  * @see <a href="https://issues.apache.org/jira/browse/SIS-400";>SIS-400</a>
  */
+@SuppressWarnings("exports")
 public final class MarshallingTest extends TestUsingFile implements Filter {
     /**
      * The marshaller used to handle marshalling the created DefaultMetadata 
object.
@@ -549,12 +549,12 @@ public final class MarshallingTest extends TestUsingFile 
implements Filter {
             {
                 coverageDescription = new DefaultCoverageDescription();
                 // Attribute description
-                final var schema = new DefaultRecordSchema(null, null, 
"IslandFeatures");
-                final var members = new LinkedHashMap<CharSequence,Class<?>>();
-                members.put("city",      String.class);
-                members.put("latitude",  Double.class);
-                members.put("longitude", Double.class);
-                final RecordType recordType = 
schema.createRecordType("SettledArea", members);
+                final RecordType recordType = 
DefaultRecordSchemaTest.createRecordType(
+                        "IslandFeatures",
+                        "SettledArea",
+                        Map.of("city",      String.class,
+                               "latitude",  Double.class,
+                               "longitude", Double.class));
                 coverageDescription.setAttributeDescription(recordType);
                 {
                     /*
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResultTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResultTest.java
index f94f637944..aba54b402a 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResultTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/metadata/iso/quality/DefaultQuantitativeResultTest.java
@@ -26,17 +26,20 @@ import org.opengis.util.RecordType;
 import org.opengis.util.MemberName;
 import org.opengis.metadata.quality.Element;
 import org.opengis.metadata.quality.QuantitativeResult;
-import org.apache.sis.metadata.internal.shared.RecordSchemaSIS;
 import org.apache.sis.xml.XML;
 import org.apache.sis.xml.internal.shared.LegacyNamespaces;
 import org.apache.sis.util.SimpleInternationalString;
 import org.apache.sis.util.iso.DefaultRecord;
+import org.apache.sis.util.iso.DefaultRecordType;
+import org.apache.sis.util.internal.shared.Constants;
+import org.apache.sis.metadata.internal.Resources;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.test.TestUtilities;
 import org.apache.sis.test.TestCase;
+import org.apache.sis.util.iso.DefaultRecordSchemaTest;
 
 
 /**
@@ -45,6 +48,7 @@ import org.apache.sis.test.TestCase;
  * @author  Martin Desruisseaux (Geomatys)
  * @author  Guilhem Legal (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class DefaultQuantitativeResultTest extends TestCase {
     /**
      * Creates a new test case.
@@ -62,7 +66,7 @@ public final class DefaultQuantitativeResultTest extends 
TestCase {
     @Test
     @SuppressWarnings("deprecation")
     public void testIsEmpty() {
-        final DefaultQuantitativeResult r = new DefaultQuantitativeResult();
+        final var r = new DefaultQuantitativeResult();
         assertTrue(r.isEmpty());
         r.setErrorStatistic(new SimpleInternationalString("a description"));
         assertFalse(r.isEmpty());
@@ -86,28 +90,29 @@ public final class DefaultQuantitativeResultTest extends 
TestCase {
          * The `RecordType` constructor invoked at unmarshalling time sets the 
name
          * to the hard-coded "Multiline record" string. We need to use the 
same name.
          */
-        final RecordType recordType = 
RecordSchemaSIS.INSTANCE.createRecordType(
-                RecordSchemaSIS.MULTILINE.toInternationalString(),
+        final RecordType recordType = DefaultRecordSchemaTest.createRecordType(
+                Constants.SIS,
+                Resources.formatInternational(Resources.Keys.MultilineRecord),
                 Map.of("Result of quality measurement", String.class));
         /*
          * The `Record` constructor invoked at unmarshalling time sets the type
          * to the hard-coded "Single text" value. We need to use the same type.
          */
-        final RecordType singleText = RecordSchemaSIS.STRING;
-        final DefaultRecord  record = new DefaultRecord(singleText);
+        final RecordType singleText = DefaultRecordType.SINGLE_STRING;
+        final var record = new DefaultRecord(singleText);
         record.set(TestUtilities.getSingleton(singleText.getMembers()), "The 
quality is okay");
         /*
          * Record type and record value are set independently in two 
properties.
          * In current implementation, `record.type` is not equal to 
`recordType`.
          */
-        assertNotEquals(recordType, record.getRecordType());        // 
Actually a limitation, not an intended behavior.
-        final DefaultQuantitativeResult result = new 
DefaultQuantitativeResult();
+        // assertEquals(recordType, record.getRecordType());    // Limitation 
of current implementation.
+        final var result = new DefaultQuantitativeResult();
         result.setValues(List.of(record));
         result.setValueType(recordType);
         /*
          * Opportunistically test the redirection implemented in deprecated 
methods.
          */
-        final DefaultQuantitativeAttributeAccuracy element = new 
DefaultQuantitativeAttributeAccuracy();
+        final var element = new DefaultQuantitativeAttributeAccuracy();
         element.setNamesOfMeasure(Set.of(new SimpleInternationalString("Some 
quality flag")));
         element.setResults(Set.of(result));
         return element;
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordSchemaTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordSchemaTest.java
index 0a61396e4d..11dbc1a1d8 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordSchemaTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordSchemaTest.java
@@ -34,6 +34,7 @@ import org.apache.sis.test.TestCase;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class DefaultRecordSchemaTest extends TestCase {
     /**
      * Creates a new test case.
@@ -41,23 +42,35 @@ public final class DefaultRecordSchemaTest extends TestCase 
{
     public DefaultRecordSchemaTest() {
     }
 
+    /**
+     * Creates a record type in a temporary schema.
+     *
+     * @param  schemaName  name of the schema.
+     * @param  recordName  name of the record.
+     * @param  fields      record fields.
+     * @return the record in a temporary schema.
+     */
+    public static RecordType createRecordType(CharSequence schemaName, 
CharSequence recordName, Map<CharSequence, Class<?>> fields) {
+        final var schema = new DefaultRecordSchema(schemaName);
+        return schema.createRecordType(recordName, fields);
+    }
+
     /**
      * Tests {@link DefaultRecordSchema#createRecordType(CharSequence, Map)}.
      */
     @Test
-    @SuppressWarnings({"deprecation", "removal"})
+    @SuppressWarnings("deprecation")
     public void testCreateRecordType() {
-        final var schema = new DefaultRecordSchema(null, null, "MySchema");
+        // Do not use `Map.of(…)` because we need to preserve order.
         final var fields = new LinkedHashMap<CharSequence,Class<?>>(8);
         assertNull(fields.put("city",       String.class));
         assertNull(fields.put("latitude",   Double.class));
         assertNull(fields.put("longitude",  Double.class));
         assertNull(fields.put("population", Integer.class));
-        final RecordType recordType = schema.createRecordType("MyRecordType", 
fields);
+        final RecordType recordType = createRecordType("MySchema", 
"MyRecordType", fields);
         /*
          * Inspect properties.
          */
-        assertSame(schema, recordType.getContainer());
         assertEquals(Names.createTypeName("MySchema", ":", "MyRecordType"), 
recordType.getTypeName());
         int count = 0;
         for (final Map.Entry<MemberName,Type> entry : 
recordType.getFieldTypes().entrySet()) {
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTest.java
index 0333f62b55..a0cb54b9a5 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTest.java
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.parallel.ExecutionMode;
 import org.apache.sis.test.TestCase;
 import static org.apache.sis.test.Assertions.assertMessageContains;
 import static org.apache.sis.test.Assertions.assertMultilinesEquals;
+import static org.apache.sis.test.Assertions.assertSerializedEquals;
 
 
 /**
@@ -37,13 +38,14 @@ import static 
org.apache.sis.test.Assertions.assertMultilinesEquals;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 @Execution(ExecutionMode.CONCURRENT)
 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
 public final class DefaultRecordTest extends TestCase {
     /**
      * The record schema for the record types to create.
      */
-    private final SerializableRecordSchema schema;
+    private final DefaultRecordSchema schema;
 
     /**
      * The record type to be shared by all tests.
@@ -59,7 +61,7 @@ public final class DefaultRecordTest extends TestCase {
         assertNull(members.put("latitude",   Double.class));
         assertNull(members.put("longitude",  Double.class));
         assertNull(members.put("population", Integer.class));
-        schema     = new SerializableRecordSchema("MySchema");
+        schema     = new DefaultRecordSchema("MySchema");
         recordType = schema.createRecordType("MyRecordType", members);
     }
 
@@ -156,7 +158,7 @@ public final class DefaultRecordTest extends TestCase {
     public void testSerialization() {
         final var record = new DefaultRecord(recordType);
         record.setAll("Machu Picchu", -13.1639, -72.5468, null);
-        assertNotSame(record, schema.testSerialization(record));
+        assertNotSame(record, assertSerializedEquals(record));
     }
 
     /**
@@ -168,7 +170,7 @@ public final class DefaultRecordTest extends TestCase {
         final var members = new LinkedHashMap<CharSequence,Class<?>>(8);
         assertNull(members.put("latitude",  Double.class));
         assertNull(members.put("longitude", Double.class));
-        final var record = new 
DefaultRecord(schema.createRecordType("MyRecordType", members));
+        final var record = new 
DefaultRecord(schema.createRecordType("AnotherRecordType", members));
         /*
          * As a side effect of the fact that DefaultRecord uses an array of 
primitive type,
          * initial values should be zero instead of null. We use this trick as 
a way to
@@ -181,11 +183,10 @@ public final class DefaultRecordTest extends TestCase {
          */
         setAllAndCompare(record, -13.1639, -72.5468);
         assertMultilinesEquals(
-                "Record[“MyRecordType”] {\n" +
+                "Record[“AnotherRecordType”] {\n" +
                 "    latitude  : -13.1639\n" +
                 "    longitude : -72.5468\n" +
                 "}\n",
                 record.toString());
-        assertNotSame(record, schema.testSerialization(record));
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTypeTest.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTypeTest.java
index caeb353a2c..7d0a22680a 100644
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTypeTest.java
+++ 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/DefaultRecordTypeTest.java
@@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test;
 import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.test.TestCase;
 import static org.apache.sis.test.Assertions.assertMessageContains;
+import static org.apache.sis.test.Assertions.assertSerializedEquals;
 import static org.apache.sis.test.TestUtilities.getSingleton;
 
 
@@ -35,9 +36,10 @@ import static org.apache.sis.test.TestUtilities.getSingleton;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class DefaultRecordTypeTest extends TestCase {
     /** Value of {@link DefaultRecordType#getContainer()}. */
-    private final SerializableRecordSchema container;
+    private final DefaultRecordSchema container;
 
     /** Value of {@link DefaultRecordType#getTypeName()}.   */ private 
DefaultTypeName   recordTypeName;
     /** Value of {@link DefaultRecordType#getMembers()}.    */ private 
DefaultMemberName fieldName;
@@ -55,14 +57,14 @@ public final class DefaultRecordTypeTest extends TestCase {
         fieldNamespace  = new DefaultNameSpace (recordNamespace, 
"MyRecordType", ":", ":");
         fieldTypeName   = new DefaultTypeName  (new DefaultNameSpace(null, 
"gco", ":", ":"), "Integer");
         fieldName       = new DefaultMemberName(fieldNamespace, "aMember", 
fieldTypeName);
-        container       = new SerializableRecordSchema("MyNameSpace");
+        container       = new DefaultRecordSchema("MyNameSpace");
         assertEquals("MyNameSpace:MyRecordType:aMember", 
fieldName.toFullyQualifiedName().toString());
     }
 
     /**
      * Creates a new record type from the current values of private fields.
      */
-    @SuppressWarnings("removal")
+    @SuppressWarnings("deprecation")
     private DefaultRecordType create() throws IllegalArgumentException {
         final Type fieldType = new SimpleAttributeType<>(fieldTypeName, 
Integer.class);
         return new DefaultRecordType(recordTypeName, container, 
Map.of(fieldName, fieldType));
@@ -130,6 +132,6 @@ public final class DefaultRecordTypeTest extends TestCase {
      */
     @Test
     public void testSerialization() {
-        container.testSerialization(create());
+        assertSerializedEquals(create());
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/SerializableRecordSchema.java
 
b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/SerializableRecordSchema.java
deleted file mode 100644
index 2d005ea8a1..0000000000
--- 
a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/util/iso/SerializableRecordSchema.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.sis.util.iso;
-
-import java.io.Serializable;
-import java.io.ObjectStreamException;
-
-// Test dependencies
-import static org.apache.sis.test.Assertions.assertSerializedEquals;
-
-
-/**
- * A serializable {@link DefaultRecordSchema} for testing purpose only.
- * On deserialization, the schema is replaced by the {@link #INSTANCE}.
- *
- * @author  Martin Desruisseaux (Geomatys)
- */
-@SuppressWarnings("serial")
-final class SerializableRecordSchema extends DefaultRecordSchema implements 
Serializable {
-    /**
-     * The unique instance for the shema.
-     */
-    private static DefaultRecordSchema INSTANCE;
-
-    /**
-     * Construct a new record schema.
-     *
-     * @param schemaName The name of the new schema.
-     */
-    SerializableRecordSchema(final String schemaName) {
-        super(null, null, schemaName);
-    }
-
-    /**
-     * On serialization, returns a proxy which will be resolved as {@link 
#INSTANCE} on deserialization.
-     */
-    protected Object writeReplace() throws ObjectStreamException {
-        return new Proxy();
-    }
-
-    /**
-     * The object to serialize instead of {@link DefaultRecordSchema}.
-     * This proxy is itself replaced by {@link 
SerializableRecordSchema#INSTANCE} on deserialization.
-     */
-    private static final class Proxy implements Serializable {
-        Object readResolve() throws ObjectStreamException {
-            return INSTANCE;
-        }
-    }
-
-    /**
-     * Tests serialization of a {@code Record} or {@code RecordType}.
-     *
-     * @param  record the object to serialize.
-     * @return the deserialized object.
-     */
-    final Object testSerialization(final Object record) {
-        synchronized (SerializableRecordSchema.class) {
-            try {
-                INSTANCE = this;
-                return assertSerializedEquals(record);
-            } finally {
-                INSTANCE = null;
-            }
-        }
-    }
-}
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/PositionalAccuracyConstant.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/PositionalAccuracyConstant.java
index a7bfc358bb..b55e2e10d4 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/PositionalAccuracyConstant.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/PositionalAccuracyConstant.java
@@ -40,9 +40,9 @@ import 
org.apache.sis.metadata.iso.quality.DefaultEvaluationMethod;
 import org.apache.sis.metadata.iso.quality.DefaultConformanceResult;
 import 
org.apache.sis.metadata.iso.quality.DefaultAbsoluteExternalPositionalAccuracy;
 import org.apache.sis.metadata.iso.quality.DefaultQuantitativeResult;
-import org.apache.sis.metadata.internal.shared.RecordSchemaSIS;
 import org.apache.sis.util.collection.WeakValueHashMap;
 import org.apache.sis.util.resources.Vocabulary;
+import org.apache.sis.util.iso.DefaultRecordType;
 import org.apache.sis.util.iso.DefaultRecord;
 import org.apache.sis.system.Configuration;
 
@@ -175,7 +175,7 @@ public final class PositionalAccuracyConstant extends 
DefaultAbsoluteExternalPos
             results.add(result);
         }
         if (accuracy != null) {
-            final RecordType type = RecordSchemaSIS.REAL;
+            final RecordType type = DefaultRecordType.SINGLE_REAL;
             final var record = new DefaultRecord(type);
             record.setAll(accuracy);
 
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/TestCase.java 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/TestCase.java
index a103440797..74414615ff 100644
--- a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/TestCase.java
+++ b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/TestCase.java
@@ -49,6 +49,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("UseOfSystemOutOrSystemErr")
 @ExtendWith(FailureDetailsReporter.class)
 @TestInstance(TestInstance.Lifecycle.PER_METHOD)
 public abstract class TestCase {

Reply via email to