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. */
