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);
}
/**