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

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


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new e3bd2106f0 Update for a change in GeoAPI development branch. The way 
to declare a `CodeList` had to change in order to avoid a deadlock which 
occurred at class initialization time. The fix is to use less magic in the 
`CodeList` parent class, which requires that subclasses declare `VALUES` 
themselves.
e3bd2106f0 is described below

commit e3bd2106f0e64311be0589bdfa2d419f70d53cfb
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Mon Apr 13 21:21:46 2026 +0200

    Update for a change in GeoAPI development branch.
    The way to declare a `CodeList` had to change in order to avoid a deadlock 
which occurred at class initialization time.
    The fix is to use less magic in the `CodeList` parent class, which requires 
that subclasses declare `VALUES` themselves.
---
 .../apache/sis/filter/math/FilteringFunction.java  |  10 +-
 .../org.apache.sis.metadata/main/module-info.java  |   4 +
 .../apache/sis/metadata/iso/legacy/MediumName.java |  80 ++++++++++----
 .../sis/xml/bind/metadata/replace/SensorType.java  |  27 ++++-
 .../referencing/internal/VerticalDatumTypes.java   |   2 +-
 .../apache/sis/util/collection/CodeListSet.java    |  37 +++----
 .../apache/sis/util/internal/shared/CodeLists.java | 117 ++++++++++++---------
 .../sis/util/collection/CodeListSetTest.java       |  11 +-
 .../apache/sis/util/collection/LargeCodeList.java  |  30 +++---
 geoapi/snapshot                                    |   2 +-
 .../gui/referencing/PositionableProjection.java    |   9 +-
 11 files changed, 211 insertions(+), 118 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/FilteringFunction.java
 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/FilteringFunction.java
index 4129641998..ceae0fb5c6 100644
--- 
a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/FilteringFunction.java
+++ 
b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/filter/math/FilteringFunction.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.filter.math;
 
+import java.util.List;
 import org.opengis.util.CodeList;
 
 
@@ -31,6 +32,11 @@ final class FilteringFunction extends 
CodeList<FilteringFunction> {
      */
     private static final long serialVersionUID = -3980988422378881835L;
 
+    /**
+     * All code list values created in the currently running <abbr>JVM</abbr>.
+     */
+    private static final List<FilteringFunction> VALUES = initialValues();
+
     /**
      * Creates a new filtering function.
      *
@@ -47,7 +53,7 @@ final class FilteringFunction extends 
CodeList<FilteringFunction> {
      */
     @Override
     public FilteringFunction[] family() {
-        return values(FilteringFunction.class);
+        return VALUES.toArray(FilteringFunction[]::new);
     }
 
     /**
@@ -57,6 +63,6 @@ final class FilteringFunction extends 
CodeList<FilteringFunction> {
      * @return a code matching the given name, or {@code null}.
      */
     public static FilteringFunction valueOf(final String code) {
-        return valueOf(FilteringFunction.class, code, 
FilteringFunction::new).get();
+        return valueOf(VALUES, code, FilteringFunction::new);
     }
 }
diff --git a/endorsed/src/org.apache.sis.metadata/main/module-info.java 
b/endorsed/src/org.apache.sis.metadata/main/module-info.java
index 31f8ae9eb3..202fb514de 100644
--- a/endorsed/src/org.apache.sis.metadata/main/module-info.java
+++ b/endorsed/src/org.apache.sis.metadata/main/module-info.java
@@ -150,7 +150,11 @@ module org.apache.sis.metadata {
             org.glassfish.jaxb.core,            // TODO: need to export to 
Jakarta only.
             jakarta.xml.bind;                   // Seems ignored.
 
+    exports org.apache.sis.metadata.iso.legacy to
+            org.apache.sis.util;                // For calls to 
`MediumName.values()` by reflection.
+
     exports org.apache.sis.xml.bind.metadata.replace to
+            org.apache.sis.util,                // For calls to 
`SensorType.values()` by reflection.
             org.apache.sis.referencing,
             org.apache.sis.profile.france,
             org.glassfish.jaxb.runtime,         // For access to 
beforeUnmarshal(…).
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/legacy/MediumName.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/legacy/MediumName.java
index 6901065c3c..ce77df690e 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/legacy/MediumName.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/iso/legacy/MediumName.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.metadata.iso.legacy;
 
+import java.util.List;
 import org.opengis.annotation.UML;
 import org.opengis.metadata.citation.Citation;
 import org.opengis.util.CodeList;
@@ -46,75 +47,99 @@ public final class MediumName extends CodeList<MediumName> 
implements Citation {
 
     /** Read-only optical disk. */
     @UML(identifier="cdRom", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName CD_ROM = valueOf("CD_ROM");
+    public static final MediumName CD_ROM;
 
     /** Digital versatile disk. */
     @UML(identifier="dvd", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName DVD = valueOf("DVD");
+    public static final MediumName DVD;
 
     /** Digital versatile disk digital versatile disk, read only. */
     @UML(identifier="dvdRom", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName DVD_ROM = valueOf("DVD_ROM");
+    public static final MediumName DVD_ROM;
 
     /** 3½ inch magnetic disk. */
     @UML(identifier="3halfInchFloppy", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName FLOPPY_3_HALF_INCH = 
valueOf("FLOPPY_3_HALF_INCH");
+    public static final MediumName FLOPPY_3_HALF_INCH;
 
     /** 5¼ inch magnetic disk. */
     @UML(identifier="5quarterInchFloppy", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName FLOPPY_5_QUARTER_INCH = 
valueOf("FLOPPY_5_QUARTER_INCH");
+    public static final MediumName FLOPPY_5_QUARTER_INCH;
 
     /** 7 track magnetic tape. */
     @UML(identifier="7trackTape", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName TAPE_7_TRACK = valueOf("TAPE_7_TRACK");
+    public static final MediumName TAPE_7_TRACK;
 
     /** 9 track magnetic tape. */
     @UML(identifier="9trackTape", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName TAPE_9_TRACK = valueOf("TAPE_9_TRACK");
+    public static final MediumName TAPE_9_TRACK;
 
     /** 3480 cartridge tape drive. */
     @UML(identifier="3480Cartridge", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName CARTRIDGE_3480 = valueOf("CARTRIDGE_3480");
+    public static final MediumName CARTRIDGE_3480;
 
     /** 3490 cartridge tape drive. */
     @UML(identifier="3490Cartridge", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName CARTRIDGE_3490 = valueOf("CARTRIDGE_3490");
+    public static final MediumName CARTRIDGE_3490;
 
     /** 3580 cartridge tape drive. */
     @UML(identifier="3580Cartridge", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName CARTRIDGE_3580 = valueOf("CARTRIDGE_3580");
+    public static final MediumName CARTRIDGE_3580;
 
     /** 4 millimetre magnetic tape. */
     @UML(identifier="4mmCartridgeTape", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName CARTRIDGE_TAPE_4mm = 
valueOf("CARTRIDGE_TAPE_4mm");
+    public static final MediumName CARTRIDGE_TAPE_4mm;
 
     /** 8 millimetre magnetic tape. */
     @UML(identifier="8mmCartridgeTape", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName CARTRIDGE_TAPE_8mm = 
valueOf("CARTRIDGE_TAPE_8mm");
+    public static final MediumName CARTRIDGE_TAPE_8mm;
 
     /** ¼ inch magnetic tape. */
     @UML(identifier="1quarterInchCartridgeTape", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName CARTRIDGE_TAPE_1_QUARTER_INCH = 
valueOf("CARTRIDGE_TAPE_1_QUARTER_INCH");
+    public static final MediumName CARTRIDGE_TAPE_1_QUARTER_INCH;
 
     /** Half inch cartridge streaming tape drive. */
     @UML(identifier="digitalLinearTape", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName DIGITAL_LINEAR_TAPE = 
valueOf("DIGITAL_LINEAR_TAPE");
+    public static final MediumName DIGITAL_LINEAR_TAPE;
 
     /** Direct computer linkage. */
     @UML(identifier="onLine", obligation=CONDITIONAL, specification=ISO_19115)
-    public static final MediumName ON_LINE = valueOf("ON_LINE");
+    public static final MediumName ON_LINE;
 
     /** Linkage through a satellite communication system. */
     @UML(identifier="satellite", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName SATELLITE = valueOf("SATELLITE");
+    public static final MediumName SATELLITE;
 
     /** Communication through a telephone network. */
     @UML(identifier="telephoneLink", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName TELEPHONE_LINK = valueOf("TELEPHONE_LINK");
+    public static final MediumName TELEPHONE_LINK;
 
     /** Pamphlet or leaflet giving descriptive information. */
     @UML(identifier="hardcopy", obligation=CONDITIONAL, 
specification=ISO_19115)
-    public static final MediumName HARDCOPY = valueOf("HARDCOPY");
+    public static final MediumName HARDCOPY;
+
+    /**
+     * All code list values created in the currently running <abbr>JVM</abbr>.
+     */
+    private static final List<MediumName> VALUES = initialValues(
+        // Inline assignments for getting compiler error if a field is missing 
or duplicated.
+        CD_ROM                        = new MediumName("CD_ROM"),
+        DVD                           = new MediumName("DVD"),
+        DVD_ROM                       = new MediumName("DVD_ROM"),
+        FLOPPY_3_HALF_INCH            = new MediumName("FLOPPY_3_HALF_INCH"),
+        FLOPPY_5_QUARTER_INCH         = new 
MediumName("FLOPPY_5_QUARTER_INCH"),
+        TAPE_7_TRACK                  = new MediumName("TAPE_7_TRACK"),
+        TAPE_9_TRACK                  = new MediumName("TAPE_9_TRACK"),
+        CARTRIDGE_3480                = new MediumName("CARTRIDGE_3480"),
+        CARTRIDGE_3490                = new MediumName("CARTRIDGE_3490"),
+        CARTRIDGE_3580                = new MediumName("CARTRIDGE_3580"),
+        CARTRIDGE_TAPE_4mm            = new MediumName("CARTRIDGE_TAPE_4mm"),
+        CARTRIDGE_TAPE_8mm            = new MediumName("CARTRIDGE_TAPE_8mm"),
+        CARTRIDGE_TAPE_1_QUARTER_INCH = new 
MediumName("CARTRIDGE_TAPE_1_QUARTER_INCH"),
+        DIGITAL_LINEAR_TAPE           = new MediumName("DIGITAL_LINEAR_TAPE"),
+        ON_LINE                       = new MediumName("ON_LINE"),
+        SATELLITE                     = new MediumName("SATELLITE"),
+        TELEPHONE_LINK                = new MediumName("TELEPHONE_LINK"),
+        HARDCOPY                      = new MediumName("HARDCOPY"));
 
     /** Constructs an element of the given name. */
     private MediumName(final String name) {
@@ -124,11 +149,22 @@ public final class MediumName extends 
CodeList<MediumName> implements Citation {
     /**
      * Returns the list of {@code MediumName}s.
      *
-     * @return the list of codes declared in the current JVM.
+     * @return all code {@linkplain #values() values} for this code list.
      */
     @Override
     public MediumName[] family() {
-        return values(MediumName.class);
+        return values();
+    }
+
+    /**
+     * Returns the list of {@code MediumName}s.
+     * This method must be declared even if not invoked explicitly because it 
may be invoked
+     * by reflection by {@link 
org.apache.sis.util.internal.shared.CodeLists#values(Class)}.
+     *
+     * @return the list of codes declared in the current <abbr>JVM</abbr>.
+     */
+    public static MediumName[] values() {
+        return VALUES.toArray(MediumName[]::new);
     }
 
     /**
@@ -138,7 +174,7 @@ public final class MediumName extends CodeList<MediumName> 
implements Citation {
      * @return a code matching the given name, or {@code null}.
      */
     public static MediumName valueOf(final String code) {
-        return valueOf(MediumName.class, code, MediumName::new).get();
+        return valueOf(VALUES, code, MediumName::new);
     }
 
     /**
@@ -162,6 +198,8 @@ public final class MediumName extends CodeList<MediumName> 
implements Citation {
 
     /**
      * {@link Citation} methods provided for transition from legacy code list 
to new citation type.
+     *
+     * @return the medium name as a citation title.
      */
     @Override
     public InternationalString getTitle() {
diff --git 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/metadata/replace/SensorType.java
 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/metadata/replace/SensorType.java
index 2c96b8d2af..bb6ca798b4 100644
--- 
a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/metadata/replace/SensorType.java
+++ 
b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/bind/metadata/replace/SensorType.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.xml.bind.metadata.replace;
 
+import java.util.List;
 import org.opengis.annotation.UML;
 import org.opengis.annotation.Specification;
 import org.opengis.util.CodeList;
@@ -43,7 +44,14 @@ public final class SensorType extends CodeList<SensorType> {
     /**
      * The sensor is a radiometer.
      */
-    public static final SensorType RADIOMETER = valueOf("RADIOMETER");
+    public static final SensorType RADIOMETER;
+
+    /**
+     * All code list values created in the currently running <abbr>JVM</abbr>.
+     */
+    private static final List<SensorType> VALUES = initialValues(
+        // Inline assignments for getting compiler error if a field is missing 
or duplicated.
+        RADIOMETER = new SensorType("RADIOMETER"));
 
     /**
      * Constructs an element of the given name.
@@ -56,13 +64,24 @@ public final class SensorType extends CodeList<SensorType> {
     }
 
     /**
-     * Returns the list of codes of the same kind as this code list element.
+     * Returns the list of {@code SensorType}s.
      *
      * @return all code {@linkplain #values() values} for this code list.
      */
     @Override
     public SensorType[] family() {
-        return values(SensorType.class);
+        return values();
+    }
+
+    /**
+     * Returns the list of {@code SensorType}s.
+     * This method must be declared even if not invoked explicitly because it 
may be invoked
+     * by reflection by {@link 
org.apache.sis.util.internal.shared.CodeLists#values(Class)}.
+     *
+     * @return the list of codes declared in the current <abbr>JVM</abbr>.
+     */
+    public static SensorType[] values() {
+        return VALUES.toArray(SensorType[]::new);
     }
 
     /**
@@ -72,6 +91,6 @@ public final class SensorType extends CodeList<SensorType> {
      * @return a code matching the given name.
      */
     public static SensorType valueOf(String code) {
-        return valueOf(SensorType.class, code, SensorType::new).get();
+        return valueOf(VALUES, code, SensorType::new);
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
index b74977e6c3..56327cd5a3 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/internal/VerticalDatumTypes.java
@@ -204,7 +204,7 @@ public final class VerticalDatumTypes {
         if (method == null && name != null && !name.isBlank()) {
             final int s = name.lastIndexOf('-');
             if (s >= 0 && 
name.substring(s+1).strip().equalsIgnoreCase("based")) {
-                method = CodeLists.forCodeName(RealizationMethod.class, 
name.substring(0, s));
+                method = CodeLists.forName(RealizationMethod.values(), 
name.substring(0, s));
             }
             if (method == null) {
                 method = RealizationMethod.valueOf(name);
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/CodeListSet.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/CodeListSet.java
index d3f3fcabdc..6a8325fff4 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/CodeListSet.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/collection/CodeListSet.java
@@ -25,6 +25,7 @@ import java.io.Serializable;
 import java.lang.reflect.Modifier;
 import org.opengis.util.CodeList;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.internal.shared.CodeLists;
 
 
 /**
@@ -84,15 +85,14 @@ public class CodeListSet<E extends CodeList<E>> extends 
AbstractSet<E>
     private long values;
 
     /**
-     * The bit set for supplementary values beyond the {@code values} mask, or 
{@code null}
-     * if none. This is very rarely needed, but we need this field in case a 
code list has
-     * more than 64 elements.
+     * The bit set for supplementary values beyond the {@code values} mask, or 
{@code null} if none.
+     * This is very rarely needed, but we need this field in case a code list 
has more than 64 elements.
      *
      * <h4>Implementation note</h4>
      * The standard {@link java.util.EnumSet} class uses different 
implementations depending on whether
      * the enumeration contains more or less than 64 elements. We cannot apply 
the same strategy for
-     * {@code CodeListSet}, because new code list elements can be created at 
runtime. Consequently, this
-     * implementation needs to be able to growth its capacity.
+     * {@code CodeListSet}, because new code list elements can be created at 
runtime.
+     * Consequently, this implementation needs to be able to growth its 
capacity.
      */
     private BitSet supplementary;
 
@@ -134,7 +134,7 @@ public class CodeListSet<E extends CodeList<E>> extends 
AbstractSet<E>
     public CodeListSet(final Class<E> elementType, final boolean fill) throws 
IllegalArgumentException {
         this(elementType);
         if (fill) {
-            codes = POOL.unique(CodeList.values(elementType));
+            codes = POOL.unique(CodeLists.values(elementType));
             int n = codes.length;
             if (n < Long.SIZE) {
                 values = (1L << n) - 1;
@@ -173,10 +173,10 @@ public class CodeListSet<E extends CodeList<E>> extends 
AbstractSet<E>
      * Returns the code list for the given ordinal value. This methods depends
      * only on the code list type; it does not depend on the content of this 
set.
      */
-    final E valueOf(final int ordinal) {
+    private E valueOf(final int ordinal) {
         E[] array = codes;
         if (array == null || ordinal >= array.length) {
-            codes = array = POOL.unique(CodeList.values(elementType));
+            codes = array = POOL.unique(CodeLists.values(elementType));
         }
         return array[ordinal];
     }
@@ -331,7 +331,7 @@ public class CodeListSet<E extends CodeList<E>> extends 
AbstractSet<E>
                      * Code below this point checks for the rare cases
                      * where there is more than 64 code list elements.
                      */
-                    final BitSet s = supplementary;
+                    final BitSet s  =   supplementary;
                     final BitSet os = o.supplementary;
                     if (( s == null ||  s.isEmpty()) &&
                         (os == null || os.isEmpty()))
@@ -359,7 +359,7 @@ public class CodeListSet<E extends CodeList<E>> extends 
AbstractSet<E>
     @Override
     public boolean addAll(final Collection<? extends E> c) throws 
IllegalArgumentException {
         if (c instanceof CodeListSet) {
-            final CodeListSet<?> o = (CodeListSet<?>) c;
+            final var o = (CodeListSet<?>) c;
             /*
              * Following assertion should be ensured by parameterized types.
              */
@@ -367,23 +367,18 @@ public class CodeListSet<E extends CodeList<E>> extends 
AbstractSet<E>
             boolean changed = (values != (values |= o.values));
             /*
              * Code below this point is for the rare cases
-             * where there is more than 64 code list elements.
+             * when there are more than 64 code list elements.
              */
             final BitSet os = o.supplementary;
             if (os != null) {
                 final BitSet s = supplementary;
-                if (s == null) {
-                    if (!os.isEmpty()) {
-                        supplementary = (BitSet) os.clone();
-                        changed = true;
-                    }
-                } else if (changed) {
-                    // Avoid the cost of computing cardinality.
-                    s.or(os);
-                } else {
+                if (s != null) {
                     final int cardinality = s.cardinality();
                     s.or(os);
-                    changed = (cardinality != s.cardinality());
+                    changed |= (cardinality != s.cardinality());
+                } else if (!os.isEmpty()) {
+                    supplementary = (BitSet) os.clone();
+                    changed = true;
                 }
             }
             return changed;
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CodeLists.java
 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CodeLists.java
index fffa46f9d5..262525d49a 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CodeLists.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/CodeLists.java
@@ -16,10 +16,10 @@
  */
 package org.apache.sis.util.internal.shared;
 
+import java.lang.reflect.Array;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.InaccessibleObjectException;
 import java.lang.reflect.UndeclaredThrowableException;
-import java.util.function.Predicate;
 import org.opengis.util.CodeList;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Characters.Filter;
@@ -31,45 +31,43 @@ import org.opengis.util.ControlledVocabulary;
 
 /**
  * Implementation of some {@link org.apache.sis.util.iso.Types} methods needed 
by {@code org.apache.sis.util} module.
- * This class opportunistically implements {@link Predicate} interface, but 
this is an implementation details.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-public final class CodeLists implements Predicate<CodeList<?>> {
+public final class CodeLists {
     /**
-     * The name to compare during filtering operation.
+     * Do not allow instantiation of this class.
      */
-    private final String codename;
+    private CodeLists() {
+    }
 
     /**
-     * Creates a new filter for the specified code name.
-     *
-     * @param codename the name to compare during filtering operation.
+     * Returns {@code true} if the given names matches the name we are looking 
for.
      */
-    private CodeLists(final String codename) {
-        this.codename  = codename;
+    private static boolean accept(final String candidate, final String 
codename) {
+        return CharSequences.equalsFiltered(candidate, codename, 
Filter.LETTERS_AND_DIGITS, true);
     }
 
     /**
-     * Returns {@code true} if the given code matches the name we are looking 
for.
+     * Returns the code from the given array that matches the given name.
      *
-     * @param  code  the code list candidate.
+     * @param  <E>     the type of code.
+     * @param  values  the values to test.
+     * @param  name    the name of the code to obtain, or {@code null}.
+     * @return a code matching the given name, or {@code null} if none.
      */
-    @Override
-    public boolean test(final CodeList<?> code) {
-        for (final String candidate : code.names()) {
-            if (accept(candidate, codename)) {
-                return true;
+    public static <E extends ControlledVocabulary> E forName(final E[] values, 
String name) {
+        name = Strings.trimOrNull(name);
+        if (name != null) {
+            for (final E code : values) {
+                for (String candidate : code.names()) {
+                    if (accept(candidate, name)) {
+                        return code;
+                    }
+                }
             }
         }
-        return false;
-    }
-
-    /**
-     * Returns {@code true} if the given names matches the name we are looking 
for.
-     */
-    private static boolean accept(final String candidate, final String 
codename) {
-        return CharSequences.equalsFiltered(candidate, codename, 
Filter.LETTERS_AND_DIGITS, true);
+        return null;
     }
 
     /**
@@ -119,21 +117,13 @@ public final class CodeLists implements 
Predicate<CodeList<?>> {
      */
     public static <E extends CodeList<E>> E forCodeName(final Class<E> 
codeType, String name) {
         name = Strings.trimOrNull(name);
-        return (name != null) ? find(codeType, new CodeLists(name)) : null;
-    }
-
-    /**
-     * Returns the code of the given type that matches the filter.
-     *
-     * @param  <E>       the compile-time type given as the {@code codeType} 
parameter.
-     * @param  codeType  the type of code list.
-     * @param  filter    the criterion for selecting a code list.
-     * @return a code matching the given name, or {@code null} if none.
-     */
-    public static <E extends CodeList<E>> E find(final Class<E> codeType, 
final Predicate<? super CodeList<?>> filter) {
-        for (final E code : CodeList.values(codeType)) {
-            if (filter.test(code)) {
-                return code;
+        if (name != null) {
+            for (final E code : values(codeType)) {
+                for (String candidate : code.names()) {
+                    if (accept(candidate, name)) {
+                        return code;
+                    }
+                }
             }
         }
         return null;
@@ -159,15 +149,7 @@ public final class CodeLists implements 
Predicate<CodeList<?>> {
         if (code == null) try {
             code = codeType.cast(codeType.getMethod("valueOf", 
String.class).invoke(null, name));
         } catch (InvocationTargetException e) {
-            final Throwable cause = e.getCause();
-            if (cause instanceof RuntimeException) {
-                throw (RuntimeException) cause;
-            }
-            if (cause instanceof Error) {
-                throw (Error) cause;
-            }
-            // `CodeList.valueOf(String)` methods are not expected to throw 
checked exceptions.
-            throw new UndeclaredThrowableException(cause);
+            throw rethrowOrWrap(e.getCause());
         } catch (IllegalAccessException e) {
             throw (InaccessibleObjectException) new 
InaccessibleObjectException(e.getMessage()).initCause(e);
         } catch (NoSuchMethodException | NullPointerException e) {
@@ -175,4 +157,41 @@ public final class CodeLists implements 
Predicate<CodeList<?>> {
         }
         return code;
     }
+
+    /**
+     * Returns all known values for the given type of code list or enumeration.
+     * This method delegates to the public static {@code values()} method.
+     * If that method is not found, an empty list is returned.
+     *
+     * @param  <T>       the compile-time type given as the {@code codeType} 
parameter.
+     * @param  codeType  the type of code list or enumeration.
+     * @return the list of values for the given code list or enumeration, or 
an empty array if none.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends CodeList<?>> T[] values(final Class<T> codeType) {
+        Object values;
+        try {
+            values = codeType.getMethod("values", (Class<?>[]) 
null).invoke(null, (Object[]) null);
+        } catch (InvocationTargetException e) {
+            throw rethrowOrWrap(e.getCause());
+        } catch (NoSuchMethodException | IllegalAccessException e) {
+            values = Array.newInstance(codeType, 0);
+        }
+        return (T[]) values;
+    }
+
+    /**
+     * Re-throws the given exception if it is unchecked, or wraps it otherwise.
+     * In the latter case, the wrapper is {@link UndeclaredThrowableException}
+     * because this method is invoked in contexts where no checked exception 
was allowed.
+     */
+    private static UndeclaredThrowableException rethrowOrWrap(final Throwable 
cause) {
+        if (cause instanceof RuntimeException) {
+            throw (RuntimeException) cause;
+        } else if (cause instanceof Error) {
+            throw (Error) cause;
+        }
+        // `CodeList.valueOf(String)` methods are not expected to throw 
checked exceptions.
+        throw new UndeclaredThrowableException(cause);
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CodeListSetTest.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CodeListSetTest.java
index e6ecb333bf..a0b86b1acd 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CodeListSetTest.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/CodeListSetTest.java
@@ -37,6 +37,7 @@ import org.apache.sis.test.TestCase;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class CodeListSetTest extends TestCase {
     /**
      * Creates a new test case.
@@ -52,7 +53,7 @@ public final class CodeListSetTest extends TestCase {
      */
     @SuppressWarnings("fallthrough")
     private CodeListSet<AxisDirection> create(final int n) {
-        final CodeListSet<AxisDirection> c = new 
CodeListSet<>(AxisDirection.class);
+        final var c = new CodeListSet<AxisDirection>(AxisDirection.class);
         assertTrue(c.isEmpty());
         switch (n) {
             default: throw new AssertionError(n);
@@ -74,7 +75,7 @@ public final class CodeListSetTest extends TestCase {
     private CodeListSet<OnLineFunction> createOtherKind() {
         // For the validity of the tests, ordinal value must be the same.
         assertEquals(NORTH_NORTH_EAST.ordinal(), 
OnLineFunction.INFORMATION.ordinal());
-        final CodeListSet<OnLineFunction> c = new 
CodeListSet<>(OnLineFunction.class);
+        final var c = new CodeListSet<OnLineFunction>(OnLineFunction.class);
         assertTrue(c.add(OnLineFunction.INFORMATION));
         return c;
     }
@@ -104,6 +105,7 @@ public final class CodeListSetTest extends TestCase {
      * Tests the {@link CodeListSet#contains(Object)} method.
      */
     @Test
+    @SuppressWarnings("element-type-mismatch")
     public void testContains() {
         final CodeListSet<AxisDirection> c = create(4);
         assertTrue (c.contains(NORTH_NORTH_EAST));
@@ -123,6 +125,7 @@ public final class CodeListSetTest extends TestCase {
      * Tests the {@link CodeListSet#remove(Object)} method.
      */
     @Test
+    @SuppressWarnings("element-type-mismatch")
     public void testRemove() {
         final CodeListSet<AxisDirection> c = create(4);
         assertFalse(c.remove(null), "Should be null-safe.");
@@ -211,7 +214,7 @@ public final class CodeListSetTest extends TestCase {
      */
     @Test
     public void testFill() {
-        final CodeListSet<AxisDirection> c = new 
CodeListSet<>(AxisDirection.class, true);
+        final var c = new CodeListSet<AxisDirection>(AxisDirection.class, 
true);
         assertTrue(c.size() >= 32, "Expect at least 32 elements as of GeoAPI 
3.0.");
         assertTrue(c.toString().startsWith("[AxisDirection.NORTH, 
AxisDirection.NORTH_NORTH_EAST, "));
         /*
@@ -227,7 +230,7 @@ public final class CodeListSetTest extends TestCase {
      */
     @Test
     public void testLargeCodeList() {
-        final Set<LargeCodeList> main = new 
HashSet<>(Arrays.asList(LargeCodeList.values()));
+        final var main = new 
HashSet<LargeCodeList>(Arrays.asList(LargeCodeList.values()));
         assertTrue(main.size() > Long.SIZE, "This test requires more than 64 
elements.");
         final CodeListSet<LargeCodeList> c = new 
CodeListSet<>(LargeCodeList.class);
         /*
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/LargeCodeList.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/LargeCodeList.java
index 17954d32fb..b559ff698a 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/LargeCodeList.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/collection/LargeCodeList.java
@@ -16,33 +16,33 @@
  */
 package org.apache.sis.util.collection;
 
+import java.util.Arrays;
+import java.util.List;
 import org.opengis.util.CodeList;
 
-// Test dependencies
-import static org.junit.jupiter.api.Assertions.*;
-
 
 /**
- * A code list containing more than 64 elements. This implementation can be 
used by tests
- * that requires a large number of code list elements.
+ * A code list containing more than 64 elements.
+ * This implementation can be used by tests that requires a large number of 
code list elements.
+ * The implementation class must be public because the {@link #values()} 
method will be invoked
+ * by reflection from another package.
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
 @SuppressWarnings("serial")
 public final class LargeCodeList extends CodeList<LargeCodeList> {
     /**
-     * Creates 100 code list elements.
-     * We need to construct values with {@code valueOf(String)} instead of the 
constructor
-     * because this package is not exported to GeoAPI. See {@link CodeList} 
class javadoc.
+     * All code list values created in the currently running <abbr>JVM</abbr>.
      */
+    private static final List<LargeCodeList> VALUES;
     static {
-        for (int i=0; i<80; i++) {
-            assertEquals(i, valueOf("LC#" + i).ordinal());
-        }
+        final var codes = new LargeCodeList[80];
+        Arrays.setAll(codes, (i) -> new LargeCodeList("LC#" + i));
+        VALUES = initialValues(codes);
     }
 
     /**
-     * Constructs an element.
+     * Constructs an element with the given name.
      */
     private LargeCodeList(String name) {
         super(name);
@@ -50,11 +50,13 @@ public final class LargeCodeList extends 
CodeList<LargeCodeList> {
 
     /**
      * Returns the list of {@code LargeCodeList}s.
+     * This method must be declared even if not invoked explicitly because it 
may be invoked
+     * by reflection by {@link 
org.apache.sis.util.internal.shared.CodeLists#values(Class)}.
      *
      * @return the list of codes declared in the current JVM.
      */
     public static LargeCodeList[] values() {
-        return values(LargeCodeList.class);
+        return VALUES.toArray(LargeCodeList[]::new);
     }
 
     /**
@@ -74,6 +76,6 @@ public final class LargeCodeList extends 
CodeList<LargeCodeList> {
      * @return a code list element matching the given name.
      */
     public static LargeCodeList valueOf(final String code) {
-        return valueOf(LargeCodeList.class, code, LargeCodeList::new).get();
+        return valueOf(VALUES, code, LargeCodeList::new);
     }
 }
diff --git a/geoapi/snapshot b/geoapi/snapshot
index 02268bc994..97e0fd0d54 160000
--- a/geoapi/snapshot
+++ b/geoapi/snapshot
@@ -1 +1 @@
-Subproject commit 02268bc9949e5382ae15818aa9ba40996dd3a5b3
+Subproject commit 97e0fd0d54e67f99b0e7e61f5c04b84f63cef74e
diff --git 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/PositionableProjection.java
 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/PositionableProjection.java
index cd7ac24957..71d9d40b0d 100644
--- 
a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/PositionableProjection.java
+++ 
b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/PositionableProjection.java
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.gui.referencing;
 
+import java.util.List;
 import org.opengis.util.CodeList;
 import org.opengis.util.FactoryException;
 import org.opengis.geometry.DirectPosition;
@@ -119,6 +120,12 @@ public abstract class PositionableProjection extends 
CodeList<PositionableProjec
         }
     };
 
+    /**
+     * All code list values created in the currently running <abbr>JVM</abbr>.
+     */
+    private static final List<PositionableProjection> VALUES = initialValues(
+            ORTHOGRAPHIC, AZIMUTHAL_EQUIDISTANT, UTM, MERCATOR);
+
     /**
      * The projection name as a {@link Resources} keys.
      */
@@ -146,7 +153,7 @@ public abstract class PositionableProjection extends 
CodeList<PositionableProjec
      * @return the list of codes declared in the current JVM.
      */
     public static PositionableProjection[] values() {
-        return values(PositionableProjection.class);
+        return VALUES.toArray(PositionableProjection[]::new);
     }
 
     /**


Reply via email to