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

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

commit dc78d5d1ab00812ffd57050d505578cfec497cb6
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu May 28 16:28:40 2026 +0200

    Move some `ParameterDescriptor` management to the public `OptionKey` class.
    The intent is to remove the internal `URIDataStoreOption` enumeration in 
the future.
---
 .../main/org/apache/sis/storage/OptionKey.java     |  99 +++++++++++++++++--
 .../org/apache/sis/storage/base/URIDataStore.java  |   2 +-
 .../sis/storage/base/URIDataStoreOption.java       | 106 +++++++--------------
 .../org/apache/sis/storage/csv/StoreProvider.java  |  14 ---
 4 files changed, 129 insertions(+), 92 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/OptionKey.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/OptionKey.java
index 2ee060376f..343e591405 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/OptionKey.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/OptionKey.java
@@ -17,6 +17,7 @@
 package org.apache.sis.storage;
 
 import java.util.Locale;
+import java.util.Optional;
 import java.util.logging.Logger;
 import java.util.function.Supplier;
 import java.time.ZoneId;
@@ -28,12 +29,16 @@ import java.nio.file.StandardOpenOption;
 import java.io.ObjectStreamException;
 import javax.xml.XMLConstants;
 import javax.xml.stream.XMLInputFactory;
+import org.opengis.parameter.ParameterValue;
+import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.setup.GeometryLibrary;
+import org.apache.sis.storage.internal.Resources;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.storage.modifier.CoverageModifier;
 import org.apache.sis.feature.FoliationRepresentation;
+import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.system.Modules;
 
 
@@ -85,7 +90,8 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
      * @see org.apache.sis.xml.XML#LOCALE
      * @see DataStore#setLocale(Locale)
      */
-    public static final OptionKey<Locale> LOCALE = new OptionKey<>("LOCALE", 
Locale.class);
+    public static final OptionKey<Locale> LOCALE =
+            new Parameter<>("LOCALE", Locale.class, "locale", 
Resources.Keys.DataStoreLocale);
 
     /**
      * The timezone to use when parsing or formatting dates and times without 
explicit timezone.
@@ -94,7 +100,8 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
      *
      * @see org.apache.sis.xml.XML#TIMEZONE
      */
-    public static final OptionKey<ZoneId> TIMEZONE = new 
OptionKey<>("TIMEZONE", ZoneId.class);
+    public static final OptionKey<ZoneId> TIMEZONE =
+            new Parameter<>("TIMEZONE", ZoneId.class, "timezone", 
Resources.Keys.DataStoreTimeZone);
 
     /**
      * The number of spaces to use for indentation when formatting texts in 
<abbr>WKT</abbr> or <abbr>XML</abbr>.
@@ -121,7 +128,8 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
      *
      * @see jakarta.xml.bind.Marshaller#JAXB_ENCODING
      */
-    public static final OptionKey<Charset> ENCODING = new 
OptionKey<>("ENCODING", Charset.class);
+    public static final OptionKey<Charset> ENCODING =
+            new Parameter<>("ENCODING", Charset.class, "encoding", 
Resources.Keys.DataStoreEncoding);
 
     /**
      * The encoding of a <abbr>URL</abbr> (<em>not</em> the encoding of the 
document content).
@@ -204,7 +212,8 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
      * main file without its extension. For example if the main file is {@code 
"city-center.tiff"},
      * then {@code "*.xml"} will become {@code "city-center.xml"}.
      */
-    public static final OptionKey<Path> METADATA_PATH = new 
OptionKey<>("METADATA_PATH", Path.class);
+    public static final OptionKey<Path> METADATA_PATH =
+            new Parameter<>("METADATA_PATH", Path.class, "metadata", 
Resources.Keys.MetadataLocation);
 
     /**
      * The coordinate reference system (<abbr>CRS</abbr>) of data to use if 
not explicitly defined.
@@ -214,14 +223,14 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
      * file giving the <abbr>CRS</abbr>.
      */
     public static final OptionKey<CoordinateReferenceSystem> DEFAULT_CRS =
-            new OptionKey<>("DEFAULT_CRS", CoordinateReferenceSystem.class);
+            new Parameter<>("DEFAULT_CRS", CoordinateReferenceSystem.class, 
"defaultCRS", Resources.Keys.DefaultCRS);
 
     /**
      * Whether to assemble trajectory fragments (distinct <abbr>CSV</abbr> 
lines) into a single {@code Feature}
      * instance forming a foliation. This is ignored if the file does not seem 
to contain moving features.
      */
     public static final OptionKey<FoliationRepresentation> 
FOLIATION_REPRESENTATION =
-            new OptionKey<>("FOLIATION_REPRESENTATION", 
FoliationRepresentation.class);
+            new Parameter<>("FOLIATION_REPRESENTATION", 
FoliationRepresentation.class, "foliation", 
Resources.Keys.FoliationRepresentation);
 
     /**
      * The library to use for creating geometric objects at reading time. Some 
available libraries are
@@ -280,7 +289,7 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
      * @return the unique {@code OptionKey} instance.
      * @throws ObjectStreamException required by specification but should 
never be thrown.
      */
-    private Object readResolve() throws ObjectStreamException {
+    final Object readResolve() throws ObjectStreamException {
         try {
             return OptionKey.class.getField(super.getName()).get(null);
         } catch (ReflectiveOperationException e) {
@@ -294,4 +303,80 @@ public class OptionKey<T> extends 
org.apache.sis.setup.OptionKey<T> {
             return this;
         }
     }
+
+    /**
+     * Returns this option as a parameter descriptor.
+     * Storing option values as {@link ParameterValue} instances is sometime 
convenient
+     * when the options need to be serialized, for example, in a text file or 
a database.
+     * While values are stored as Java objects of type {@code <T>},
+     * the {@link ParameterValue#setValue(Object)} method is capable
+     * to convert text representations to the expected object type.
+     *
+     * <p>Parameter descriptors are available only for a subset of the options.
+     * This method may return a non-empty value only if the values of this 
option
+     * have a text representation.</p>
+     *
+     * @return a parameter descriptor for this option.
+     *
+     * @see DataStoreProvider#getOpenParameters()
+     */
+    public Optional<ParameterDescriptor<T>> asOpenParameter() {
+        return Optional.empty();
+    }
+
+    /**
+     * An option which can be used as an open parameter.
+     *
+     * @param <T>  the type of option values.
+     */
+    private static final class Parameter<T> extends OptionKey<T> {
+        /**
+         * The parameter name. This is similar but not identical to the option 
name.
+         */
+        final String parameterName;
+
+        /**
+         * The resource key for the localized description of the parameter, or 
0 if none.
+         * This is 0 on deserialization because this number does not need to 
be consistent
+         * between different <abbr>SIS</abbr> releases.
+         */
+        private final transient short description;
+
+        /**
+         * The parameter descriptor for this option, or {@code null} if not 
yet constructed.
+         */
+        private transient ParameterDescriptor<T> parameter;
+
+        /**
+         * Creates a new key of the given name for values of the given type.
+         *
+         * @param name  the key name.
+         * @param type  the type of values.
+         */
+        Parameter(final String name, final Class<T> type, final String 
parameterName, final short description) {
+            super(name, type);
+            this.parameterName = parameterName;
+            this.description   = description;
+        }
+
+        /**
+         * Returns this option as a parameter descriptor.
+         */
+        @Override
+        public synchronized Optional<ParameterDescriptor<T>> asOpenParameter() 
{
+            ParameterDescriptor<T> p = parameter;
+            if (p == null) {
+                Object defaultValue = null;
+                if (this == FOLIATION_REPRESENTATION) {
+                    defaultValue = FoliationRepresentation.ASSEMBLED;
+                }
+                final Class<T> valueClass = getElementType();
+                p = new ParameterBuilder()
+                        .addName(parameterName)
+                        
.setDescription(Resources.formatInternational(description))
+                        .create(valueClass, valueClass.cast(defaultValue));
+            }
+            return Optional.of(p);
+        }
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
index 94eb3141d2..c2dd9ccce9 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStore.java
@@ -254,7 +254,7 @@ public abstract class URIDataStore extends DataStore 
implements StoreResource {
                     switch (option) {
                         default: continue;
                         case LOCATION: {
-                            final GeneralParameterDescriptor gp = 
descriptor.descriptor(option.parameterName);
+                            final GeneralParameterDescriptor gp = 
descriptor.descriptor(URIDataStoreProvider.LOCATION);
                             final boolean isPath = (gp instanceof 
ParameterDescriptor<?>) &&
                                     
Path.class.isAssignableFrom(((ParameterDescriptor<?>) gp).getValueClass());
                             value = isPath ? locationAsPath : location; break;
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStoreOption.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStoreOption.java
index b76c848684..2a11917c63 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStoreOption.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/URIDataStoreOption.java
@@ -17,18 +17,13 @@
 package org.apache.sis.storage.base;
 
 import java.net.URI;
-import java.nio.file.Path;
-import java.nio.charset.Charset;
 import java.nio.file.StandardOpenOption;
-import java.time.ZoneId;
-import java.util.Locale;
 import java.util.EnumSet;
 import java.util.Collection;
 import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.parameter.ParameterNotFoundException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.parameter.ParameterBuilder;
 import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.OptionKey;
@@ -70,14 +65,14 @@ public enum URIDataStoreOption {
      * @see URIDataStoreProvider#LOCATION
      * @see #createForLocationOnly(String)
      */
-    LOCATION(null, URIDataStoreProvider.LOCATION, 
Resources.Keys.DataStoreLocation, URI.class),
+    LOCATION(URIDataStoreProvider.LOCATION, Resources.Keys.DataStoreLocation, 
URI.class),
 
     /**
      * Description of the optional {@value URIDataStoreProvider#FORMAT} 
parameter.
      *
      * @see URIDataStoreProvider#FORMAT
      */
-    FORMAT(null, URIDataStoreProvider.FORMAT, 
Resources.Keys.DirectoryContentFormatName, String.class),
+    FORMAT(URIDataStoreProvider.FORMAT, 
Resources.Keys.DirectoryContentFormatName, String.class),
 
     /**
      * Description of the optional {@value URIDataStoreProvider#CREATE} 
parameter of writable data stores.
@@ -85,7 +80,7 @@ public enum URIDataStoreOption {
      * @see URIDataStoreProvider#CREATE
      * @see OptionKey#OPEN_OPTIONS
      */
-    CREATE(null, URIDataStoreProvider.CREATE, Resources.Keys.DataStoreCreate, 
Boolean.class),
+    CREATE(URIDataStoreProvider.CREATE, Resources.Keys.DataStoreCreate, 
Boolean.class),
 
     /**
      * Description of the optional parameter for character encoding used by 
the data store.
@@ -93,7 +88,7 @@ public enum URIDataStoreOption {
      *
      * @see OptionKey#ENCODING
      */
-    ENCODING(OptionKey.ENCODING, "encoding", Resources.Keys.DataStoreEncoding, 
Charset.class),
+    ENCODING(OptionKey.ENCODING),
 
     /**
      * Description of the parameter for formatting conventions of dates and 
numbers.
@@ -101,7 +96,7 @@ public enum URIDataStoreOption {
      *
      * @see OptionKey#LOCALE
      */
-    LOCALE(OptionKey.LOCALE, "locale", Resources.Keys.DataStoreLocale, 
Locale.class),
+    LOCALE(OptionKey.LOCALE),
 
     /**
      * Description of the optional parameter for the time zone used by the 
data store.
@@ -109,7 +104,7 @@ public enum URIDataStoreOption {
      *
      * @see OptionKey#TIMEZONE
      */
-    TIMEZONE(OptionKey.TIMEZONE, "timezone", Resources.Keys.DataStoreTimeZone, 
ZoneId.class),
+    TIMEZONE(OptionKey.TIMEZONE),
 
     /**
      * Description of the optional parameter for the default coordinate 
reference system.
@@ -118,93 +113,57 @@ public enum URIDataStoreOption {
      * @see OptionKey#DEFAULT_CRS
      * @todo Use {@link CodeType} when parsing from text.
      */
-    DEFAULT_CRS(OptionKey.DEFAULT_CRS, "defaultCRS", 
Resources.Keys.DefaultCRS, CoordinateReferenceSystem.class),
+    DEFAULT_CRS(OptionKey.DEFAULT_CRS),
 
     /**
      * Description of the optional "metadata" parameter.
      *
      * @see OptionKey#METADATA_PATH
      */
-    METADATA(OptionKey.METADATA_PATH, "metadata", 
Resources.Keys.MetadataLocation, Path.class),
+    METADATA(OptionKey.METADATA_PATH),
 
     /**
      * Description of the optional parameter for specifying whether to assemble
      * distinct lines into a single {@code Feature} instance forming a 
foliation.
      */
-    FOLIATION(OptionKey.FOLIATION_REPRESENTATION, "foliation");
+    FOLIATION(OptionKey.FOLIATION_REPRESENTATION);
 
     /**
-     * The parameter name. This is similar but not identical to the 
enumeration name.
+     * The option key for storing the parameter value in a storage connector,
+     * or {@code null} if none.
      */
-    final String parameterName;
+    private final OptionKey<?> option;
 
     /**
      * The parameter descriptor for this option, or {@code null} if not yet 
constructed.
      *
      * @see #getParameterDescriptor()
-     * @see #initializeParameterDescriptor(Class, Object, short)
      */
     private volatile ParameterDescriptor<?> parameter;
 
-    /**
-     * The option key for storing the parameter value in a storage connector.
-     */
-    private final OptionKey<?> option;
-
     /**
      * Creates a new enumeration value with deferred construction of the 
parameter descriptor.
      *
-     * @param option  associated option in {@link StorageConnector}, or {@code 
null} if none.
-     * @param name    name of the parameter to create.
+     * @param option  associated option in {@link StorageConnector}.
      */
-    private URIDataStoreOption(final OptionKey<?> option, final String name) {
+    private URIDataStoreOption(final OptionKey<?> option) {
         this.option = option;
-        parameterName = name;
     }
 
     /**
      * Creates a new enumeration value with immediate construction of the 
parameter descriptor.
      *
-     * @param <V>          for compile-time consistency check between {@code 
valueClass} and {@code option}.
-     * @param option       associated option in {@link StorageConnector}, or 
{@code null} if none.
-     * @param name         name of the parameter to create.
-     * @param description  constant from {@link Resources} keys for the 
localized description.
-     * @param valueClass   value of the parameter.
-     */
-    private <V> URIDataStoreOption(final OptionKey<V> option,
-                                   final String       name,
-                                   final short        description,
-                                   final Class<V>     valueClass)
-    {
-        this(option, name);
-        initializeParameterDescriptor(valueClass, null, description);
-    }
-
-    /**
-     * Creates the parameter descriptor of this enumeration value.
-     *
-     * @param  <V>           for compile-time consistency check between {@code 
valueClass} and {@code option}.
-     * @param  valueClass    value of the parameter.
-     * @param  defaultValue  default value, or {@code null} if none.
-     * @param  description   constant from {@link Resources} keys for the 
localized description.
-     * @return the parameter descriptor.
-     * @throws IllegalStateException if this parameter descriptor is already 
initialized.
+     * @param parameterName  name of the parameter to create.
+     * @param description    constant from {@link Resources} keys for the 
localized description.
+     * @param valueClass     type of value of the parameter.
      */
-    public final <V> ParameterDescriptor<V> initializeParameterDescriptor(
-            final Class<V> valueClass,
-            final V        defaultValue,
-            final short    description)
-    {
-        if (parameter != null) {
-            throw new IllegalStateException(name());
-        }
-        final ParameterDescriptor<V> descriptor = new ParameterBuilder()
+    private <V> URIDataStoreOption(final String parameterName, final short 
description, final Class<V> valueClass) {
+        option = null;
+        parameter = new ParameterBuilder()
                 .addName(parameterName)
                 .setDescription(Resources.formatInternational(description))
                 .setRequired(ordinal() == 0)
-                .create(valueClass, defaultValue);
-        parameter = descriptor;
-        return descriptor;
+                .create(valueClass, null);
     }
 
     /**
@@ -214,11 +173,18 @@ public enum URIDataStoreOption {
      * @throws IllegalStateException if the parameter has not yet been 
initialized.
      */
     public final ParameterDescriptor<?> getParameterDescriptor() {
-        final ParameterDescriptor<?> p = parameter;
-        if (p != null) {
-            return p;
+        ParameterDescriptor<?> p = parameter;
+        if (p == null) {
+            p = option.asOpenParameter().orElseThrow(() -> new 
IllegalStateException(name()));
         }
-        throw new IllegalStateException(name());
+        return p;
+    }
+
+    /**
+     * Returns the parameter name.
+     */
+    private String parameterName() {
+        return getParameterDescriptor().getName().getCode();
     }
 
     /**
@@ -269,7 +235,7 @@ public enum URIDataStoreOption {
             final ParameterDescriptorGroup descriptor = 
provider.getOpenParameters();
             if (descriptor != null) {
                 final ParameterValueGroup pg = descriptor.createValue();
-                pg.parameter(LOCATION.parameterName).setValue(location);
+                pg.parameter(URIDataStoreProvider.LOCATION).setValue(location);
                 return pg;
             }
         }
@@ -284,7 +250,7 @@ public enum URIDataStoreOption {
      */
     public final void setValueOf(final ParameterValueGroup parameters, final 
Object value) {
         if (value != null) {
-            parameters.parameter(parameterName).setValue(value);
+            parameters.parameter(parameterName()).setValue(value);
         }
     }
 
@@ -321,7 +287,7 @@ public enum URIDataStoreOption {
                 if (option.option == null) continue;
                 final Object value;
                 try {
-                    value = 
parameters.parameter(option.parameterName).getValue();
+                    value = 
parameters.parameter(option.parameterName()).getValue();
                 } catch (ParameterNotFoundException e) {
                     Logging.ignorableException(provider.getLogger(), 
URIDataStoreOption.class, "connector", e);
                     continue;
@@ -350,7 +316,7 @@ public enum URIDataStoreOption {
                     }
                 } catch (UnconvertibleObjectException e) {
                     throw new IllegalOpenParameterException(Errors.format(
-                            Errors.Keys.IllegalOptionValue_2, 
option.parameterName, value), e);
+                            Errors.Keys.IllegalOptionValue_2, 
option.parameterName(), value), e);
                 }
             }
         }
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/StoreProvider.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/StoreProvider.java
index 78ddec4b75..c16b21176b 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/StoreProvider.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/csv/StoreProvider.java
@@ -22,8 +22,6 @@ import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.ProbeResult;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.FeatureSet;
-import org.apache.sis.feature.FoliationRepresentation;
-import org.apache.sis.storage.internal.Resources;
 import org.apache.sis.storage.base.Capability;
 import org.apache.sis.storage.base.StoreMetadata;
 import org.apache.sis.storage.base.URIDataStoreOption;
@@ -112,18 +110,6 @@ public final class StoreProvider extends 
URIDataStoreProvider {
         }
     }
 
-    /*
-     * Creates the description of the optional parameter for specifying 
whether the reader should assemble
-     * distinct <abbr>CSV</abbr> lines into a single {@code Feature} instance 
forming a foliation.
-     * This is ignored if the <abbr>CSV</abbr> file does not seem to contain 
moving features.
-     */
-    static {
-        URIDataStoreOption.FOLIATION.initializeParameterDescriptor(
-                FoliationRepresentation.class,
-                FoliationRepresentation.ASSEMBLED,
-                Resources.Keys.FoliationRepresentation);
-    }
-
     /**
      * Creates a new provider.
      */

Reply via email to