001/*
002 *    GeoAPI - Java interfaces for OGC/ISO standards
003 *    Copyright © 2003-2024 Open Geospatial Consortium, Inc.
004 *    http://www.geoapi.org
005 *
006 *    Licensed under the Apache License, Version 2.0 (the "License");
007 *    you may not use this file except in compliance with the License.
008 *    You may obtain a copy of the License at
009 *
010 *        http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *    Unless required by applicable law or agreed to in writing, software
013 *    distributed under the License is distributed on an "AS IS" BASIS,
014 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 *    See the License for the specific language governing permissions and
016 *    limitations under the License.
017 */
018package org.opengis.util;
019
020import java.io.Serializable;
021import java.io.ObjectStreamException;
022import java.lang.reflect.Array;
023import java.lang.reflect.Constructor;
024import java.lang.reflect.Field;
025import java.lang.reflect.Modifier;
026import java.lang.reflect.InaccessibleObjectException;
027import java.util.ArrayList;
028import java.util.Collection;
029import java.util.Map;
030import java.util.WeakHashMap;
031import java.util.Objects;
032import java.util.Optional;
033import java.util.function.Function;
034import java.util.function.Predicate;
035
036import org.opengis.annotation.UML;
037import static org.opengis.annotation.Specification.*;
038import org.opengis.geoapi.internal.Vocabulary;
039import org.opengis.geoapi.internal.Errors;
040
041
042/**
043 * Base class for all code lists. Code lists are like enumerations, but extensible.
044 * For example, invoking the {@code valueOf(String)} method in any subclass with a
045 * name that was not previously defined will create a new {@code CodeList} element
046 * and automatically add it to the arrays returned by {@code values()}.
047 *
048 * <h2>Guidance for subclasses</h2>
049 * The parameter type {@code <E>} <em>shall</em> be the same type as the code list subclass.
050 * In other words, if the subclass is {@code Foo}, then it must extend {@code CodeList<Foo>}.
051 * In addition, subclasses <em>should</em> provide {@code values(String)} and {@code values()} methods.
052 * The following code snippet is a suggested pattern for subclasses:
053 *
054 * {@snippet lang="java" :
055 * public final class Foo extends CodeList<Foo> {
056 *     public static final Foo BAR = new Foo("BAR");
057 *     public static final Foo BIZ = new Foo("BIZ");
058 *
059 *     private Foo(String name) {
060 *         super(name);
061 *     }
062 *
063 *     public static Foo valueOf(String name) {
064 *         return valueOf(Foo.class, name, Foo::new).get();
065 *     }
066 *
067 *     public static Foo[] values() {
068 *         return values(Foo.class);
069 *     }
070 *
071 *     @Override
072 *     public Foo[] family() {
073 *         return values();
074 *     }
075 * }
076 * }
077 *
078 * Above snippet is sufficient for classes in exported packages. If a code list is defined in a non-exported package,
079 * then its static fields may need to be initialized with {@code valueOf(String)} instead of {@code new Foo(String)}.
080 * It will have a small performance cost, but is needed because of Java Module System restrictions on reflection.
081 *
082 * @param  <E>  the type of this code list.
083 *
084 * @author  Martin Desruisseaux (IRD, Geomatys)
085 * @version 3.1
086 * @since   1.0
087 */
088@UML(identifier="CodeList", specification=ISO_19103)
089public abstract class CodeList<E extends CodeList<E>> implements ControlledVocabulary, Comparable<E>, Serializable {
090    /**
091     * Serial number for compatibility with different versions.
092     */
093    private static final long serialVersionUID = 5655809691319522885L;
094
095    /**
096     * The values for each code list.
097     * Map keys are the {@code CodeList} classes for which elements are listed, and map values are those elements.
098     * Each code list element shall be stored in the list at the index corresponding to its {@link #ordinal} value.
099     * Elements are stored as {@code CodeList} instances if available, or by their {@code String} names otherwise.
100     * Names are sometime used instead of instances because assigning {@code this} at construction time is unsafe.
101     * Those names will be replaced by the actual instances by the {@code valueOf(String)} method or by reflection.
102     *
103     * <h4>Class unloading</h4>
104     * The use of {@link WeakHashMap} allows class unloading, but can work only as long as the list
105     * associated to a class contains only {@code String} elements. After storing at least one instance,
106     * the indirect references to the class prevent the {@code Class} key from being garbage-collected.
107     *
108     * @see #values(Class)
109     */
110    private static final Map<Class<? extends CodeList<?>>, Elements> VALUES = new WeakHashMap<>();
111
112    /**
113     * Elements stored in the {@link #VALUES} map for a given {@code CodeList} class.
114     * This list contains {@link CodeList} instances when they are fully constructed,
115     * or only their names when storing the instance would be unsafe ("this-escape").
116     * The {@link #get(int)} method may return a {@link String} or a {@link CodeList}.
117     * If a {@code CodeList} is desired, use {@link #resolve(Class, int)} instead.
118     */
119    @SuppressWarnings("serial")     // Not intended to be serialized.
120    private static final class Elements extends ArrayList<Object> {
121        /**
122         * Whether all code list names in this list have been replaced by the actual instances.
123         * This is used for faster {@link #toArray(Class)} execution when there is no longer a
124         * need to check the type of each element.
125         *
126         * @see #toArray(Class)
127         */
128        boolean resolved;
129
130        /**
131         * Creates a new, initially empty, list.
132         *
133         * @param  type  the {@link #VALUES} map key to which this list will be associated.
134         */
135        Elements(final Class<? extends CodeList<?>> type) {
136            super(capacity(type));
137        }
138
139        /** Workaround while waiting for JEP 447: Statements before super(…). */
140        private static int capacity(final Class<? extends CodeList<?>> type) {
141            var desc = type.getAnnotation(Vocabulary.class);
142            return (desc != null) ? desc.capacity() : 8;        // Code lists typically have few elements.
143        }
144
145        /**
146         * Returns the element at the given index as a code list element of the specified class.
147         * Callers must invoke this method in a block synchronized on {@code this} list.
148         *
149         * @param  <E>       the compile-time type given as the {@code codeType} parameter.
150         * @param  codeType  the type of the code list for which to get an element.
151         * @param  index     index of the element to get.
152         * @return element at the specified index.
153         * @throws InaccessibleObjectException if the element needs to be resolved by reflection and this operation failed.
154         *         A failure is generally caused by an error in the declaration of static fields in the code list.
155         * @throws IllegalStateException if the code list is inconsistent (e.g., element having wrong index).
156         */
157        final <E extends CodeList<E>> E resolve(final Class<E> codeType, final int index) {
158            final E element;
159            final Object code = get(index);
160            if (code instanceof String) try {
161                final Field field;
162                if (codeType.isAnnotationPresent(Vocabulary.class)) {   // True if the code list is a GeoAPI class.
163                    field = codeType.getDeclaredField((String) code);
164                    field.setAccessible(true);
165                } else {
166                    field = codeType.getField((String) code);           // Be more conservative for user classes.
167                }
168                element = codeType.cast(field.get(null));
169                if (element.ordinal() == index && element.name().equals(code)) {
170                    set(index, element);
171                } else {
172                    throw new IllegalStateException("Conflict between " + element + " and " + code + '.');
173                }
174            } catch (ReflectiveOperationException | NullPointerException | ClassCastException e) {
175                /*
176                 * The search by reflection may fail with:
177                 * - IllegalAccessException  if the package containing `codeType` is not exported,
178                 * - NoSuchFieldException    if the field does not exist,
179                 * - NullPointerException    if the field is not static, or
180                 * - ClassCastException      if the field value is not an instance of <E>.
181                 */
182                throw (InaccessibleObjectException) new InaccessibleObjectException(cannotRead(codeType, code)).initCause(e);
183            } else {
184                element = codeType.cast(code);
185            }
186            return element;
187        }
188
189        /**
190         * Produces the message for a field that cannot be read by reflection.
191         * Used for exception messages or for log record messages.
192         *
193         * @param  codeType  the type of the code list.
194         * @param  code      the code that cannot be read.
195         * @return the message to use in exception or in log record.
196         */
197        static String cannotRead(final Class<?> codeType, final Object code) {
198            return "Cannot read the " + codeType.getSimpleName() + '.' + code + " field value.";
199        }
200
201        /**
202         * Returns all elements in this list.
203         *
204         * @param  <E>       the compile-time type given as the {@code codeType} parameter.
205         * @param  codeType  the type of the code list for which to get all elements.
206         * @return all elements that are known at the time that this method is invoked.
207         * @throws InaccessibleObjectException if an element needs to be resolved by reflection and this operation failed.
208         *         A failure is generally caused by an error in the declaration of static fields in the code list.
209         */
210        final synchronized <E extends CodeList<E>> E[] toArray(final Class<E> codeType) {
211            @SuppressWarnings("unchecked")
212            final E[] array = (E[]) Array.newInstance(codeType, size());
213            if (resolved) {
214                return toArray(array);
215            }
216            for (int i=0; i<array.length; i++) {
217                array[i] = resolve(codeType, i);
218            }
219            resolved = true;
220            return array;
221        }
222    }
223
224    /**
225     * The code value as a sequential number incremented in the order in which codes are created.
226     * This value is set at construction time and should be considered final. It is potentially
227     * modified only during deserialization, because the Java serialization mechanism bypasses
228     * the constructor.
229     *
230     * @see #ordinal()
231     * @see #readResolve()
232     */
233    private transient int ordinal;
234
235    /**
236     * The code name. If this {@code CodeList} instance is stored in a static field
237     * of the code list class, then this name shall be identical to the field name.
238     *
239     * @see #name()
240     * @see #names()
241     */
242    private final String name;
243
244    /**
245     * The identifier declared in the {@link UML} annotation, or an empty string if there is
246     * no such annotation or if the annotation contains an empty string.  This field will be
247     * computed only when first needed.
248     *
249     * @see #identifier()
250     * @see #names()
251     */
252    private transient String identifier;
253
254    /**
255     * Creates a new code list element and add it to the given collection. Subclasses
256     * will typically give a static reference to an {@link java.util.ArrayList} for
257     * the {@code values} argument. This list is used for {@code values()}
258     * method implementations.
259     *
260     * @param  name    the code name. Shall be the name of the static field if such field exist.
261     * @param  values  the collection to add the element to. Shall be the same for all elements.
262     *
263     * @deprecated This constructor is unsafe because a reference to {@code this} escapes before subclass is
264     * fully initialized (see <a href="https://github.com/opengeospatial/geoapi/issues/91">issue #91</a>).
265     * Use {@link #CodeList(String)} instead.
266     */
267    @Deprecated(since="3.1", forRemoval=true)
268    protected CodeList(String name, final Collection<E> values) {
269        this(name);
270        synchronized (values) {
271            this.ordinal = values.size();
272            if (!values.add((E) this)) {
273                // Should not happen with standard collection implementations.
274                throw new IllegalArgumentException("Duplicated value: " + name);
275            }
276        }
277    }
278
279    /**
280     * Creates a new code list element. If this constructor is invoked for initializing a static field,
281     * then the given name <em>shall</em> be the case-sensitive name of the static field.
282     *
283     * @param  name  the code name. Shall be the name of the static field if such field exist.
284     *
285     * @since 3.1
286     */
287    protected CodeList(final String name) {
288        this.name = name;
289        Class<?> type = getClass();
290        while (type.isAnonymousClass()) {
291            type = type.getSuperclass();
292            if (type.equals(CodeList.class)) {
293                throw new IllegalStateException("Class shall not be anonymous.");
294            }
295        }
296        @SuppressWarnings("unchecked")      // The following cast should never fail.
297        var codeType = (Class<? extends CodeList<?>>) type;
298        final Elements values = getOrCreateList(codeType);
299        synchronized (values) {
300            ordinal = values.size();
301            values.add(name);           // Needed for incrementing the list size.
302            values.resolved = false;
303        }
304    }
305
306    /**
307     * Returns the list associated to the specified type of code list, creating the list if needed.
308     * This method should be invoked only when the {@code codeType} class is known to be initialized.
309     * If the class may be uninitialized, use {@link #valueList(Class)} instead.
310     *
311     * @param  codeType  the type of code list for which to get the code list values.
312     * @return all values for the given type. Never {@code null} but potentially empty.
313     */
314    private static Elements getOrCreateList(final Class<? extends CodeList<?>> codeType) {
315        synchronized (VALUES) {
316            return VALUES.computeIfAbsent(codeType, Elements::new);
317        }
318    }
319
320    /**
321     * Used by {@link CodeList#valueOf(Class, Filter)} to select codes matching an arbitrary
322     * criterion.
323     *
324     * @deprecated Replaced by {@link Predicate} from the standard Java library.
325     */
326    @Deprecated(since="3.1", forRemoval=true)
327    public static interface Filter {
328        /**
329         * Returns {@code true} if the given code matches the criterion defined by this filter.
330         *
331         * @param  code  the code to test.
332         * @return {@code true} if the code matches the criterion.
333         */
334        boolean accept(CodeList<?> code);
335
336        /**
337         * Returns the name of the code being looked for, or {@code null} if unknown.
338         * This method is invoked by {@link CodeList#valueOf(Class, Filter)} if no code
339         * match the criterion defined by this filter. In such case, there is a choice:
340         *
341         * <ul>
342         *   <li>If this method returns a non-null name, then a new code of that name is created.</li>
343         *   <li>Otherwise, no new code is created and {@code CodeList.valueOf} returns {@code null}.</li>
344         * </ul>
345         *
346         * @return the name of the code being looked for, or {@code null}.
347         */
348        String codename();
349    }
350
351    /**
352     * Returns the code of the given type that matches the given name, or creates a new code if there is no match.
353     * More specifically, this methods returns the first instance of the given class for which
354     * <code>{@linkplain #name()}.{@linkplain String#equals equals}(name)</code> is {@code true}.
355     * If no such instance is found, then a new instance is created using the constructor expecting
356     * a single {@link String} argument.
357     *
358     * <p><strong>Note that invoking this method may result in the creation of a new code value.</strong>
359     * If this is not desired, use {@link #valueOf(Class, String, Function)} instead.</p>
360     *
361     * @param  <T>       the compile-time type given as the {@code codeType} parameter.
362     * @param  codeType  the type of code list.
363     * @param  name      the name of the code to obtain (case sensitive), or {@code null}.
364     * @return a code matching the given name (possible a new code), or {@code null} if the given name is null.
365     *
366     * @deprecated This method depends on reflection, which is restricted in the context of Java Module System.
367     * Use {@link #valueOf(Class, String, Function)} instead.
368     */
369    @Deprecated(since="3.1", forRemoval=true)
370    public static <T extends CodeList<T>> T valueOf(final Class<T> codeType, String name) {
371        if (name == null) {
372            return null;
373        }
374        name = name.trim();
375        final String n = name.trim();       // Need final for lambda.
376        return valueOf(codeType, new Filter() {
377            @Override public boolean accept(CodeList<?> code) {
378                return n.equals(code.name);
379            }
380
381            @Override public String codename() {
382                return n;
383            }
384        });
385    }
386
387    /**
388     * Returns the code of the given type that matches the given criterion, or returns a new one
389     * if none match it. More specifically, this methods returns the first element (in declaration
390     * order) of the given class where <code>filter.{@linkplain Filter#accept accept}(code)</code>
391     * returns {@code true}. If no such element is found, then there is a choice:
392     *
393     * <ul>
394     *   <li>If {@link Filter#codename()} returns {@code null}, then this method returns {@code null}.</li>
395     *   <li>Otherwise a new instance is created using the constructor expecting a single {@link String}
396     *       argument, which is given the value returned by {@code codename()}.</li>
397     * </ul>
398     *
399     * @param  <T>       the compile-time type given as the {@code codeType} parameter.
400     * @param  codeType  the type of code list.
401     * @param  filter    the criterion for the code to obtain.
402     * @return a code matching the given criterion, or {@code null} if there is no match and
403     *         {@link Filter#codename()} returns {@code null}.
404     *
405     * @deprecated This method depends on reflection, which is restricted in the context of Java Module System.
406     * Use {@link #valueOf(Class, String, Function)} instead.
407     */
408    @Deprecated(since="3.1", forRemoval=true)
409    public static <T extends CodeList<T>> T valueOf(final Class<T> codeType, final Filter filter) {
410        final Elements values = getOrCreateList(codeType);
411        /*
412         * At this point we got the list of all code list values. Now search for a value matching
413         * the filter specified to this method. The search and, eventually, the code creation are
414         * done in the same synchronized block for making sure that the same code is not created
415         * twice concurrently.
416         */
417        synchronized (values) {
418            for (int i=0; i<values.size(); i++) {
419                final CodeList<?> code = values.resolve(codeType, i);
420                if (filter.accept(code)) {
421                    return codeType.cast(code);
422                }
423            }
424            final String nameIfNew = filter.codename();
425            if (nameIfNew == null || Modifier.isAbstract(codeType.getModifiers())) {
426                return null;
427            }
428            /*
429             * No value value found, but the caller allows us to create a new value.
430             * We need access to the constructor, which may not be public.
431             */
432            try {
433                final Constructor<T> constructor = codeType.getDeclaredConstructor(String.class);
434                if (!Modifier.isPublic(constructor.getModifiers())) {
435                    constructor.setAccessible(true);
436                }
437                T code = constructor.newInstance(nameIfNew);
438                values.set(code.ordinal(), code);
439                return code;
440            } catch (ReflectiveOperationException exception) {
441                throw new IllegalArgumentException("Cannot create code of type " + codeType.getSimpleName(), exception);
442            }
443        }
444    }
445
446    /**
447     * Returns the code of the given type and name if it exists, or optionally creates a new code.
448     * This method returns the first instance (in declaration order) of the given class for which the
449     * {@linkplain #name() name} is {@linkplain String#equalsIgnoreCase(String) equals, ignoring case},
450     * to the given name. If no such instance is found, then there is a choice:
451     *
452     * <ul>
453     *   <li>If {@code constructor} is {@code null}, then this method returns an empty value.</li>
454     *   <li>Otherwise a {@linkplain Optional#ofNullable(Object) nullable} new instance is created
455     *       by a call to {@code constructor.apply(name)}.</li>
456     * </ul>
457     *
458     * This method can be used for the implementation of {@code valueOf(String)} in subclasses.
459     * See the "Guidance for subclasses" section in the class Javadoc.
460     *
461     * <h4>Name matching criterion</h4>
462     * As of GeoAPI 3.1, names are compared using {@link String#equalsIgnoreCase(String)}.
463     * This is different than GeoAPI 3.0, which compared names using {@link String#equals(Object)}.
464     * Being case-insensitive allows to recognize some UML identifiers as equivalent to the names
465     * of constants declared in {@code CodeList} subclasses.
466     *
467     * @param  <E>          the compile-time type given as the {@code codeType} parameter.
468     * @param  codeType     the type of the code list for which to get an element.
469     * @param  name         the name of the code to obtain (case-insensitive), or {@code null}.
470     * @param  constructor  the constructor to use if a new code needs to be created,
471     *                      or {@code null} for not creating any new code.
472     * @return a code matching the given name, or empty if the given name is null or blank,
473     *         or if no existing code matches the given name and {@code constructor} is null or returned a null value.
474     *
475     * @since 3.1
476     */
477    public static <E extends CodeList<E>> Optional<E> valueOf(final Class<E> codeType,
478            String name, final Function<? super String, ? extends E> constructor)
479    {
480        if (name != null && !(name = name.trim()).isBlank()) {
481            final Elements values = valueList(codeType);
482            /*
483             * The search and, eventually, the code creation are done in the same synchronized
484             * block for making sure that the same code is not created twice concurrently.
485             */
486            synchronized (values) {
487                final int size = values.size();
488                for (int i=0; i<size; i++) {
489                    final E element;
490                    final Object code = values.get(i);
491                    if (code instanceof String) {
492                        if (!name.equalsIgnoreCase((String) code)) continue;
493                        element = values.resolve(codeType, i);
494                    } else {
495                        element = codeType.cast(code);
496                    }
497                    if (name.equalsIgnoreCase(element.name())) {
498                        return Optional.of(element);
499                    }
500                }
501                if (constructor != null) {
502                    final E element = constructor.apply(name);
503                    if (element != null) {
504                        values.set(element.ordinal(), element);
505                        return Optional.of(element);
506                    }
507                }
508            }
509        }
510        return Optional.empty();
511    }
512
513    /**
514     * Returns the list of code list names or instances for the specified type of code list.
515     * Callers shall use the returned list in a block synchronized on the list instance.
516     *
517     * @param  codeType  the type of code list for which to get the current code list values.
518     * @return all current values for the given type (never {@code null}).
519     */
520    private static Elements valueList(final Class<? extends CodeList<?>> codeType) {
521        Elements values;
522        synchronized (VALUES) {
523            values = VALUES.get(codeType);
524        }
525        if (values == null) {
526            /*
527             * If no list has been found for the given type, maybe the class was not yet initialized.
528             * Try to force initialization of the given class in order to register its list of static
529             * final constants, then check again.
530             */
531            final String classname = Objects.requireNonNull(codeType, "The codeType argument shall not be null.").getName();
532            try {
533                Class.forName(classname, true, codeType.getClassLoader());
534            } catch (ClassNotFoundException e) {
535                throw new TypeNotPresentException(classname, e);             // Should never happen.
536            }
537            values = getOrCreateList(codeType);
538        }
539        return values;
540    }
541
542    /**
543     * Returns the values for the specified type of code list.
544     *
545     * @param  <E>       the compile-time type given as the {@code codeType} parameter.
546     * @param  codeType  the type of code list for which to get the current code list values.
547     * @return all current values for the given type (never {@code null}).
548     *
549     * @since 3.1
550     */
551    @SuppressWarnings("unchecked")
552    public static <E extends CodeList<E>> E[] values(final Class<E> codeType) {
553        return valueList(codeType).toArray(codeType);
554    }
555
556    /**
557     * Returns the list of codes of the same kind as this code.
558     * Invoking this method gives identical results than invoking the static {@code values()} methods
559     * provided in {@code CodeList} subclasses, except that {@code family()} does not require the class
560     * to be known at compile-time — provided that at least one instance of the family is available.
561     *
562     * @return the codes of the same kind as this code.
563     */
564    @Override
565    public abstract E[] family();
566    // We do not provide default implementation because casting to `CodeList<E>` is unsafe.
567
568    /**
569     * Returns the programmatic name of this code list element.
570     * If this element is a constant defined in a {@code CodeList} subclass,
571     * then this is the name of the public static field for that constant.
572     *
573     * @return the name of this code constant.
574     */
575    @Override
576    public final String name() {
577        return name;
578    }
579
580    /**
581     * Returns the identifier declared in the UML annotation.
582     * The UML identifier shall be the ISO or OGC name for this code constant.
583     *
584     * @return the ISO/OGC identifier for this code.
585     *
586     * @see UML#identifier()
587     */
588    @Override
589    public Optional<String> identifier() {
590        /*
591         * Save the field in a local variable for protection against concurrent change (this
592         * operation is guaranteed atomic according Java specification). We don't synchronize
593         * because it is not a problem if this method is executed twice in concurrent threads.
594         */
595        String id = identifier;
596        if (id == null) {
597            id = "";
598            try {
599                final Field field = getClass().getField(name);
600                if (Modifier.isStatic(field.getModifiers())) {
601                    boolean valid;
602                    try {
603                        valid = equals(field.get(null));
604                    } catch (IllegalAccessException e) {
605                        /*
606                         * Should never happen with accessible packages because `getField(String)` returns
607                         * only public fields. However, it may happen if the code list is defined in a user
608                         * module and that module does not export the package containing the code list.
609                         * In such case, we have to trust the name provided in this code list instance.
610                         */
611                        valid = true;
612                        System.getLogger(Errors.LOGGER).log(System.Logger.Level.DEBUG, this::cannotReadField, e);
613                    }
614                    if (valid) {
615                        // Fetching annotations is allowed even with non-exported packages.
616                        final UML annotation = field.getAnnotation(UML.class);
617                        if (annotation != null) {
618                            id = annotation.identifier().intern();
619                        }
620                    }
621                }
622            } catch (NoSuchFieldException e) {
623                /*
624                 * There is no field for a code of this name. It may be normal, because the user
625                 * may have created a custom `CodeList` without declaring it as a constant.
626                 */
627                System.getLogger(Errors.LOGGER).log(System.Logger.Level.TRACE, this::cannotReadField, e);
628            }
629            identifier = id;
630        }
631        return id.isEmpty() ? Optional.empty() : Optional.of(id);
632    }
633
634    /**
635     * Produces the message for a field that cannot be read by reflection.
636     * This is used for logging purposes.
637     */
638    private String cannotReadField() {
639        return Elements.cannotRead(getClass(), name);
640    }
641
642    /**
643     * Returns the ordinal of this code element. This is the index of this element in the array returned
644     * by {@link #family()}. Those elements are in the order of the constants declared in subclasses,
645     * where the first element is assigned an ordinal value of zero.
646     *
647     * <h4>Stability</h4>
648     * For a given GeoAPI version,
649     * the code list elements declared as constants in subclasses always have the same ordinal values.
650     * However, the ordinal value of the same constant may differ between different GeoAPI versions
651     * if new elements were inserted or deleted between existing elements.
652     * User-defined elements (created by calls to a {@code valueOf(…)} method) are not guaranteed
653     * to have the same ordinal value between different execution of the same application,
654     * because these values depend on the order in which code list elements are created.
655     *
656     * @return the position of this code in elements declaration.
657     */
658    @Override
659    public final int ordinal() {
660        return ordinal;
661    }
662
663    /**
664     * Compares this code with the specified object for order.
665     * Returns a negative integer, zero, or a positive integer as this object
666     * is less than, equal to, or greater than the specified object.
667     *
668     * <p>Code list constants are only comparable to other code list constants of the same type.
669     * The natural order implemented by this method is the order in which the constants are declared.</p>
670     *
671     * @param  other  the code constant to compare with this code.
672     * @return a negative value if the given code is less than this code,
673     *         a positive value if greater or 0 if equal.
674     */
675    @Override
676    @SuppressWarnings("rawtypes")
677    public final int compareTo(final E other) {
678        final Class<? extends CodeList> ct =  this.getClass();
679        final Class<? extends CodeList> co = other.getClass();
680        if (!ct.equals(co)) {
681            throw new ClassCastException("Cannot compare " + ct.getSimpleName() + " to " + co.getSimpleName() + '.');
682        }
683        return Integer.compare(ordinal, other.ordinal());
684    }
685
686    /*
687     * Do not define `equals(Object)` and `hashCode()`. The identity comparison is consistent with above
688     * `compareTo(E)` method because there is no two CodeLists of the same class having the same ordinal value.
689     */
690
691    /**
692     * {@return a string representation of this code list}.
693     */
694    @Override
695    public String toString() {
696        return getClass().getSimpleName() + '.' + name;
697    }
698
699    /**
700     * Resolves the code list to an unique instance after deserialization.
701     * The instance shall be resolved using its {@linkplain #name() name}, not its {@linkplain #ordinal() ordinal},
702     * because the latter value is not guaranteed to be stable between different GeoAPI versions or,
703     * in the case of user-defined code list elements, between different JVM executions.
704     *
705     * <p>The default implementation tries to replace the deserialized instance by the result of
706     * <code>{@link #valueOf(Class, String, Function) valueOf}(getClass(), name(), null)</code>.
707     * If {@code valueOf(…)} returned an empty value, then {@code this} is updated with a new
708     * ordinal value and added to the list of codes associated to its class.</p>
709     *
710     * @return either {@code this} or an existing code list for the same name (ignoring case).
711     * @throws ObjectStreamException if the deserialization failed.
712     */
713    protected Object readResolve() throws ObjectStreamException {
714        /*
715         * Casted to <E> in order to satisfy the compiler, but this code should be safe
716         * even if the class is not really `Class<E>` because this method returns `Object`.
717         */
718        @SuppressWarnings("unchecked")
719        final Class<E> codeType = (Class<E>) getClass();
720        final E element = valueOf(codeType, name, null).orElse(null);
721        if (element != null) {
722            return element;
723        }
724        final Elements values = getOrCreateList(codeType);
725        synchronized (values) {
726            ordinal = values.size();
727            values.add(this);
728        }
729        return this;
730    }
731}