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 120b6be14dd92777ed95a438497a9ab628ab4f1b Author: Martin Desruisseaux <[email protected]> AuthorDate: Fri Oct 16 15:46:38 2026 +0200 Removed the deprecated `LocalizedException` interface. --- .../org/apache/sis/feature/EnvelopeOperation.java | 8 +- .../sis/feature/FeatureOperationException.java | 46 +++++------- .../sis/feature/InvalidFeatureException.java | 38 +++++----- .../main/org/apache/sis/feature/package-info.java | 2 +- .../sis/metadata/MetadataVisitorException.java | 52 +++++++++---- .../main/org/apache/sis/openoffice/CalcAddins.java | 20 +---- .../sis/io/wkt/UnparsableObjectException.java | 49 +++++++++---- .../main/org/apache/sis/io/wkt/package-info.java | 2 +- .../org/apache/sis/storage/DataStoreException.java | 55 +++++++++----- .../src/org.apache.sis.util/main/module-info.java | 3 +- .../main/org/apache/sis/util/Exceptions.java | 44 ++++------- .../org/apache/sis/util/LocalizedException.java | 85 ---------------------- .../internal/shared/LocalizedParseException.java | 38 +++++++--- .../main/org/apache/sis/util/logging/Logging.java | 4 +- .../main/org/apache/sis/util/package-info.java | 2 +- .../sis/util/resources/IndexedResourceBundle.java | 8 +- .../shared/LocalizedParseExceptionTest.java | 12 +-- .../org/apache/sis/gui/referencing/WKTPane.java | 7 +- 18 files changed, 223 insertions(+), 252 deletions(-) diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java index 5c2806c8ec..b3e00c8932 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/EnvelopeOperation.java @@ -417,7 +417,7 @@ final class EnvelopeOperation extends AbstractOperation { final Object geomCRS; if (at != null && (geomCRS = at.getValue()) != null) { if (!(geomCRS instanceof CoordinateReferenceSystem)) { - throw new FeatureOperationException(Resources.formatInternational( + throw new FeatureOperationException(Resources.format( Resources.Keys.IllegalCharacteristicsType_3, AttributeConvention.CRS_CHARACTERISTIC, CoordinateReferenceSystem.class, @@ -443,7 +443,7 @@ final class EnvelopeOperation extends AbstractOperation { genv = Envelopes.transform(op, genv); } } catch (FactoryException | TransformException e) { - throw new FeatureOperationException(Errors.formatInternational(Errors.Keys.CanNotTransformEnvelope), e); + throw new FeatureOperationException(Errors.format(Errors.Keys.CanNotTransformEnvelope), e); } /* * If there is only one geometry, we will return that geometry as-is even if its CRS is unknown. @@ -454,7 +454,7 @@ final class EnvelopeOperation extends AbstractOperation { if (envelope == null) { envelope = genv; } else if (hasUnknownCRS) { - throw new FeatureOperationException(Errors.formatInternational(Errors.Keys.UnspecifiedCRS)); + throw new FeatureOperationException(Errors.format(Errors.Keys.UnspecifiedCRS)); } else if (targetCRS != null) { envelope.add(genv); } else { @@ -470,7 +470,7 @@ final class EnvelopeOperation extends AbstractOperation { } else try { return Envelopes.union(deferred); } catch (TransformException e) { - throw new FeatureOperationException(Errors.formatInternational(Errors.Keys.CanNotTransformEnvelope), e); + throw new FeatureOperationException(Errors.format(Errors.Keys.CanNotTransformEnvelope), e); } } } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java index dabb75dd2d..b37deb01d7 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/FeatureOperationException.java @@ -16,58 +16,48 @@ */ package org.apache.sis.feature; -import org.opengis.util.InternationalString; -import org.apache.sis.util.LocalizedException; - /** * Thrown when a property value cannot be computed. * This exception may occur during a call to {@link AbstractAttribute#getValue()} on an attribute * instance which computes its value dynamically instead of returning a stored value. - * It may be for example the attributes produced by {@link FeatureOperations}. + * It may be, for example, the attributes produced by {@link FeatureOperations}. * * @author Martin Desruisseaux (Geomatys) + * @version 1.8 + * @since 1.8 */ -final class FeatureOperationException extends IllegalStateException implements LocalizedException { +public class FeatureOperationException extends IllegalStateException { /** * For cross-version compatibility. */ - private static final long serialVersionUID = -7281160433831489357L; - - /** - * A description of the computation error. - */ - @SuppressWarnings("serial") // Most SIS implementations are serializable. - private final InternationalString message; + private static final long serialVersionUID = 6381299496396235246L; /** - * Creates a new exception with the given explanation message. + * Creates an exception with the specified details message. * - * @param message a description of the computation error. + * @param message the detail message in the default locale. */ - FeatureOperationException(final InternationalString message) { - super(message.toString()); - this.message = message; + public FeatureOperationException(String message) { + super(message); } /** - * Creates a new exception with the given explanation message and cause. + * Creates an exception with the specified cause and no details message. * - * @param message a description of the computation error. - * @param cause the cause of the error. + * @param cause the cause for this exception. */ - FeatureOperationException(final InternationalString message, final Exception cause) { - super(message.toString(), cause); - this.message = message; + public FeatureOperationException(Throwable cause) { + super(cause); } /** - * Returns the message in various locales. + * Creates an exception with the specified details message and cause. * - * @return the exception message. + * @param message the detail message in the default locale. + * @param cause the cause for this exception. */ - @Override - public InternationalString getInternationalMessage() { - return message; + public FeatureOperationException(String message, Throwable cause) { + super(message, cause); } } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java index 6aeff94a2a..4910141115 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/InvalidFeatureException.java @@ -17,7 +17,6 @@ package org.apache.sis.feature; import org.opengis.util.InternationalString; -import org.apache.sis.util.LocalizedException; // Specific to the geoapi-3.1 and geoapi-4.0 branches: import org.opengis.feature.Feature; @@ -27,25 +26,20 @@ import org.opengis.feature.InvalidPropertyValueException; /** * Thrown when a feature fails at least one conformance test. * - * <h2>API design note</h2> - * This exception extends {@link InvalidPropertyValueException} because an Apache SIS feature - * can be invalid only if a property is invalid. + * <p><b>API design note:</b> this exception extends {@link InvalidPropertyValueException} + * because an Apache <abbr>SIS</abbr> feature can be invalid only if a property is invalid.</p> * * @author Martin Desruisseaux (Geomatys) + * @version 1.8 + * @since 1.8 * * @see Features#validate(Feature) */ -final class InvalidFeatureException extends InvalidPropertyValueException implements LocalizedException { +public class InvalidFeatureException extends InvalidPropertyValueException { /** * For cross-version compatibility. */ - private static final long serialVersionUID = 7288810679876346027L; - - /** - * A description of the illegal feature. - */ - @SuppressWarnings("serial") // Most SIS implementations are serializable. - private final InternationalString message; + private static final long serialVersionUID = -8089121424988848183L; /** * Creates a new exception with the given explanation message. @@ -54,16 +48,24 @@ final class InvalidFeatureException extends InvalidPropertyValueException implem */ InvalidFeatureException(final InternationalString message) { super(message.toString()); - this.message = message; } /** - * Returns the message in various locales. + * Creates an exception with the specified details message. + * + * @param message the detail message in the default locale. + */ + public InvalidFeatureException(String message) { + super(message); + } + + /** + * Creates an exception with the specified details message and cause. * - * @return the exception message. + * @param message the detail message in the default locale. + * @param cause the cause for this exception. */ - @Override - public InternationalString getInternationalMessage() { - return message; + public InvalidFeatureException(String message, Throwable cause) { + super(message, cause); } } diff --git a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java index f10a0bf841..e8e9a140cf 100644 --- a/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java +++ b/endorsed/src/org.apache.sis.feature/main/org/apache/sis/feature/package-info.java @@ -93,7 +93,7 @@ * @author Travis L. Pinney * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 1.7 + * @version 1.8 * @since 0.5 */ package org.apache.sis.feature; diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java index 09ead057f7..085409e7a3 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/metadata/MetadataVisitorException.java @@ -16,8 +16,8 @@ */ package org.apache.sis.metadata; -import org.opengis.util.InternationalString; -import org.apache.sis.util.LocalizedException; +import java.util.Locale; +import org.apache.sis.util.Localized; import org.apache.sis.util.collection.BackingStoreException; import org.apache.sis.util.collection.Containers; import org.apache.sis.util.resources.Errors; @@ -25,10 +25,12 @@ import org.apache.sis.util.resources.Errors; /** * Thrown when a {@link MetadataVisitor#visit(Class, Object)} method failed. + * The details message is created only when requested. + * The context-sensitive locale is inherited from the cause. * * @author Martin Desruisseaux (Geomatys) */ -final class MetadataVisitorException extends BackingStoreException implements LocalizedException { +final class MetadataVisitorException extends BackingStoreException implements Localized { /** * For cross-version compatibility. */ @@ -53,17 +55,31 @@ final class MetadataVisitorException extends BackingStoreException implements Lo /** * Returns an error message giving the location of the failure together with the cause. + * + * @return the detail message in the default locale. */ @Override public String getMessage() { - return getInternationalMessage().toString(); + return getMessage(false); } /** - * Returns an error message giving the location of the failure together with the cause. + * Returns an error message in a context-dependent locale if available. + * + * @return the detail message in the context-dependent locale. */ @Override - public InternationalString getInternationalMessage() { + public String getLocalizedMessage() { + return getMessage(true); + } + + /** + * Returns an error message giving the location of the failure together with the cause. + * + * @param localized whether to use context-dependent locale. + * @return the detail message in the given locale. + */ + private String getMessage(final boolean localized) { short key = Errors.Keys.CanNotProcessProperty_2; int count = 2; String location = super.getMessage(); @@ -76,15 +92,9 @@ final class MetadataVisitorException extends BackingStoreException implements Lo } } final Throwable cause = getCause(); - Object message = null; - if (cause instanceof LocalizedException) { - message = ((LocalizedException) cause).getInternationalMessage(); - } + Object message = localized ? cause.getLocalizedMessage() : cause.getMessage(); if (message == null) { - message = cause.getLocalizedMessage(); - if (message == null) { - message = cause.getClass(); - } + message = cause.getClass(); } final var arguments = new Object[count]; arguments[--count] = message; @@ -92,6 +102,18 @@ final class MetadataVisitorException extends BackingStoreException implements Lo if (count != 0) { arguments[0] = String.join(".", Containers.viewAsUnmodifiableList(propertyPath, 0, pathLength)); } - return Errors.formatInternational(key, arguments); + return Errors.forLocale(getLocale()).getString(key, arguments); + } + + /** + * Returns the locale of the localized exception message, or {@code null} if unspecified. + * If non-null, this is the effective language of the string returned by {@link #getLocalizedMessage()}. + * + * @return the locale of the localized message, or {@code null} if not explicitly defined. + */ + @Override + public Locale getLocale() { + final Throwable cause = getCause(); + return (cause instanceof Localized) ? ((Localized) cause).getLocale() : null; } } diff --git a/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java b/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java index d597cf0335..345eed443b 100644 --- a/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java +++ b/endorsed/src/org.apache.sis.openoffice/main/org/apache/sis/openoffice/CalcAddins.java @@ -25,6 +25,7 @@ import com.sun.star.lang.XServiceInfo; import com.sun.star.lang.XServiceName; import com.sun.star.uno.XComponentContext; import com.sun.star.lib.uno.helper.WeakBase; +import org.apache.sis.pending.jdk.JDK19; import org.apache.sis.util.Classes; import org.apache.sis.util.Exceptions; import org.apache.sis.util.resources.Vocabulary; @@ -133,7 +134,7 @@ public abstract class CalcAddins extends WeakBase implements XServiceName, XServ String language = locale.Language; if (language == null) language = ""; String country = locale.Country; if (country == null) country = ""; String variant = locale.Variant; if (variant == null) variant = ""; - javaLocale = new java.util.Locale(language, country, variant); + javaLocale = JDK19.localeOf(language, country, variant); } else { javaLocale = java.util.Locale.getDefault(); } @@ -150,20 +151,6 @@ public abstract class CalcAddins extends WeakBase implements XServiceName, XServ return Vocabulary.forLocale(getJavaLocale()).getString(Vocabulary.Keys.NotKnown); } - /** - * Returns the minimal length of the specified arrays. In the special case where one array - * has a length of 1, we assume that this single element will be repeated for all elements - * in the other array. - */ - static int getMinimalLength(final Object[] array1, final Object[] array2) { - if (array1 == null || array2 == null) { - return 0; - } - if (array1.length == 1) return array2.length; - if (array2.length == 1) return array1.length; - return Math.min(array1.length, array2.length); - } - /** * Returns the localized message from the specified exception. If no message is available, * returns a default string. This method never return a null value. @@ -187,8 +174,9 @@ public abstract class CalcAddins extends WeakBase implements XServiceName, XServ * @param exception the exception. */ final void reportException(final String method, final Exception exception) { + @SuppressWarnings("LocalVariableHidesMemberVariable") final Logger logger = getLogger(); - final LogRecord record = new LogRecord(Level.WARNING, getLocalizedMessage(exception)); + final var record = new LogRecord(Level.WARNING, getLocalizedMessage(exception)); record.setLoggerName(logger.getName()); record.setSourceClassName(getClass().getCanonicalName()); record.setSourceMethodName(method); diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java index bf90aeae0c..971e019691 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/UnparsableObjectException.java @@ -18,15 +18,13 @@ package org.apache.sis.io.wkt; import java.util.Locale; import java.text.ParseException; -import org.opengis.util.InternationalString; -import org.apache.sis.util.LocalizedException; +import org.apache.sis.util.Localized; +import org.apache.sis.util.Workaround; import org.apache.sis.util.resources.Errors; /** - * Thrown when a <i>Well Known Text</i> (WKT) cannot be parsed. - * - * <h2>Localization</h2> + * Thrown when a <i>Well Known Text</i> (<abbr>WKT</abbr>) cannot be parsed. * This exception may contain the error message in two languages: * * <ul> @@ -38,15 +36,25 @@ import org.apache.sis.util.resources.Errors; * </ul> * * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.8 * @since 0.8 */ -public class UnparsableObjectException extends ParseException implements LocalizedException { +public class UnparsableObjectException extends ParseException implements Localized { /** * For cross-version compatibility. */ private static final long serialVersionUID = 5949195205739826024L; + /** + * The effective locale of the localized message, or {@code null} if unspecified. + * This is the locale of the message returned by {@link #getLocalizedMessage()}. + * It is specified at construction time, then eventually replaced by the locale + * of the resource used for building the message. + * + * @see #getLocale() + */ + private Locale locale; + /** * The resources key as one of the {@link Errors.Keys} constant, or 0 if none. * @@ -80,9 +88,18 @@ public class UnparsableObjectException extends ParseException implements Localiz * @param errorOffset the position where the error is found while parsing. */ UnparsableObjectException(final Locale locale, final short key, final Object[] parameters, final int errorOffset) { - super(Errors.forLocale(locale).getString(key, parameters), errorOffset); - this.parameters = parameters; + this(Errors.forLocale(locale), key, parameters, errorOffset); + } + + /** + * Workaround while waiting for JEP 513: Flexible Constructor Bodies. + */ + @Workaround(library="JDK", version="11", fixed="25") + private UnparsableObjectException(final Errors resources, final short key, final Object[] parameters, final int errorOffset) { + super(resources.getString(key, parameters), errorOffset); + this.locale = resources.getLocale(); this.key = key; + this.parameters = parameters; } /** @@ -110,14 +127,18 @@ public class UnparsableObjectException extends ParseException implements Localiz } /** - * If this exception is capable to return the message in various locales, returns that message. - * Otherwise returns {@code null}. + * Returns the locale of the localized exception message, or {@code null} if unspecified. + * If non-null, this is the effective language of the string returned by {@link #getLocalizedMessage()}. + * This locale depends on the {@linkplain WKTFormat#getLocale() locale configured on the WKT parser} and + * the resources available in Apache <abbr>SIS</abbr>. + * + * @return the locale of the localized message, or {@code null} if not explicitly defined. * - * @return the exception message, or {@code null} if this exception cannot produce international message. + * @since 1.8 */ @Override - public InternationalString getInternationalMessage() { - return (key != 0) ? Errors.formatInternational(key, parameters) : null; + public Locale getLocale() { + return locale; } /** diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java index e53edbfd09..f6dcb9bb84 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/io/wkt/package-info.java @@ -82,7 +82,7 @@ * @author Martin Desruisseaux (IRD, Geomatys) * @author Rémi Eve (IRD) * @author Rueben Schulz (UBC) - * @version 1.7 + * @version 1.8 * @since 0.4 */ package org.apache.sis.io.wkt; diff --git a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java index ad301679ed..d4f5686c7d 100644 --- a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java +++ b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/DataStoreException.java @@ -17,8 +17,7 @@ package org.apache.sis.storage; import java.util.Locale; -import org.opengis.util.InternationalString; -import org.apache.sis.util.LocalizedException; +import org.apache.sis.util.Localized; import org.apache.sis.util.Workaround; import org.apache.sis.storage.internal.Resources; import org.apache.sis.io.stream.IOUtilities; @@ -27,26 +26,35 @@ import org.apache.sis.io.stream.IOUtilities; /** * Thrown when a {@link DataStore} cannot complete a read or write operation. * - * <h2>Localization</h2> - * The {@link #getMessage()} and {@link #getLocalizedMessage()} methods return the same message, - * but sometimes in different languages. The general policy is that {@link #getMessage()} returns - * the message in the JVM {@linkplain Locale#getDefault() default locale} while {@link #getLocalizedMessage()} - * returns the message in the locale specified by the last call to {@link DataStore#setLocale(Locale)}. + * <p><b>Localization:</b> + * The exception {@linkplain #getMessage() message} is usually in a language + * determined by the <abbr>JVM</abbr>-wide {@linkplain Locale#getDefault() default locale}. + * In addition, a {@linkplain #getLocalizedMessage() localized message} may also be available in a + * language determined by the {@linkplain DataStore#getLocale() locale configured on the data store}. * In a client-server architecture, the former is typically the locale of the system administrator - * while the latter is presumably the locale of the client connected to the server. - * However, this policy is applied on a <em>best-effort</em> basis only. + * while the latter should be the locale of the client connected to the server.</p> * * @author Johann Sorel (Geomatys) * @author Martin Desruisseaux (Geomatys) - * @version 0.8 + * @version 1.8 * @since 0.3 */ -public class DataStoreException extends Exception implements LocalizedException { +public class DataStoreException extends Exception implements Localized { /** * For cross-version compatibility. */ private static final long serialVersionUID = -1778987176103191950L; + /** + * The effective locale of the localized message, or {@code null} if unspecified. + * This is the locale of the message returned by {@link #getLocalizedMessage()}. + * It is specified at construction time, then eventually replaced by the locale + * of the resource used for building the message. + * + * @see #getLocale() + */ + private Locale locale; + /** * The resources key as one of the {@link Resources.Keys} constant, or 0 if none. * @@ -137,7 +145,16 @@ public class DataStoreException extends Exception implements LocalizedException * @param parameters parameters to use for formatting the messages. */ DataStoreException(final Locale locale, final short key, final Object... parameters) { - super(Resources.forLocale(locale).getString(key, parameters)); + this(Resources.forLocale(locale), key, parameters); + } + + /** + * Workaround while waiting for JEP 513: Flexible Constructor Bodies. + */ + @Workaround(library="JDK", version="11", fixed="25") + private DataStoreException(final Resources resources, final short key, final Object[] parameters) { + super(resources.getString(key, parameters)); + this.locale = resources.getLocale(); this.key = key; this.parameters = parameters; } @@ -179,16 +196,18 @@ public class DataStoreException extends Exception implements LocalizedException } /** - * If this exception is capable to return the message in various locales, returns that message. - * Otherwise returns {@code null}. + * Returns the locale of the localized exception message, or {@code null} if unspecified. + * If non-null, this is the effective language of the string returned by {@link #getLocalizedMessage()}. + * This locale depends on the {@linkplain DataStore#getLocale() locale configured on the data store} and + * the resources available in Apache <abbr>SIS</abbr>. * - * @return the exception message, or {@code null} if this exception cannot produce international message. + * @return the locale of the localized message, or {@code null} if not explicitly defined. * - * @since 0.8 + * @since 1.8 */ @Override - public InternationalString getInternationalMessage() { - return (key != 0) ? Resources.formatInternational(key, parameters) : null; + public Locale getLocale() { + return locale; } /** diff --git a/endorsed/src/org.apache.sis.util/main/module-info.java b/endorsed/src/org.apache.sis.util/main/module-info.java index aee6c12b11..f69aa636f4 100644 --- a/endorsed/src/org.apache.sis.util/main/module-info.java +++ b/endorsed/src/org.apache.sis.util/main/module-info.java @@ -22,7 +22,7 @@ * * @author Martin Desruisseaux (MPO, IRD, Geomatys) * @author Alexis Manin (Geomatys) - * @version 1.7 + * @version 1.8 * @since 0.3 */ module org.apache.sis.util { @@ -178,6 +178,7 @@ module org.apache.sis.util { org.apache.sis.storage.netcdf, org.apache.sis.storage.geoheif, org.apache.sis.storage.geotiff, + org.apache.sis.openoffice, org.apache.sis.console, org.apache.sis.portrayal, org.apache.sis.gui; // In the "optional" sub-project. diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java index e0826556a6..d792d9fd04 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/Exceptions.java @@ -25,7 +25,6 @@ import java.io.UncheckedIOException; import java.nio.file.DirectoryIteratorException; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.ExecutionException; -import org.opengis.util.InternationalString; import org.apache.sis.util.resources.Vocabulary; import org.apache.sis.util.collection.BackingStoreException; @@ -51,7 +50,7 @@ import org.apache.sis.util.collection.BackingStoreException; * This allows system administrator to analyze the issue without the need to understand client's language.</p> * * @author Martin Desruisseaux (IRD, Geomatys) - * @version 1.7 + * @version 1.8 * @since 0.3 */ public final class Exceptions { @@ -62,47 +61,36 @@ public final class Exceptions { } /** - * Returns the message of the given exception, localized in the given locale if possible. - * Some exceptions created by SIS can format a message in different locales. This method - * returns such localized message if possible, or fallback on the standard JDK methods otherwise. - * More specifically: + * Returns the message of the given exception with a preference for the given locale. + * The heuristic rules applied by this method may change between different versions of + * Apache <abbr>SIS</abbr>. The current rules are: * * <ul> - * <li>If the given {@code exception} is null, then this method returns {@code null}.</li> - * <li>Otherwise if the given {@code locale} is null, then this method returns {@link Exception#getMessage()}. - * This is consistent with the {@link Localized} policy saying that null locale stands for "unlocalized" - * message (usually in English) or message in the JVM {@linkplain Locale#getDefault() default locale}.</li> - * <li>Otherwise if the given {@code exception} is an instance of {@link LocalizedException} providing - * a non-null {@linkplain LocalizedException#getInternationalMessage() international message}, - * then this method returns the result of {@link InternationalString#toString(Locale)}.</li> - * <li>Otherwise this method returns {@link Exception#getLocalizedMessage()}.</li> + * <li>If the given {@code exception} is null, returns {@code null}.</li> + * <li>If the given {@code locale} is null, returns {@link Exception#getMessage()}.</li> + * <li>If the given {@code exception} does <em>not</em> implement {@link Localized}, + * returns {@link Exception#getLocalizedMessage()}.</li> + * <li>Otherwise, this method compares {@link Localized#getLocale()} with the given locale + * for choosing between {@code getMessage()} and {@code getLocalizedMessage()}.</li> * </ul> * * @param exception the exception from which to get the localize message, or {@code null}. - * @param locale the preferred locale for the message, or {@code null} for the JVM default locale. + * @param locale the preferred locale for the message, or {@code null} if unspecified. * This locale is honored on a <em>best effort</em> basis only. * @return the message in the given locale if possible, or {@code null} if the {@code exception} * argument was {@code null} or if the exception does not contain a message. - * - * @see LocalizedException#getLocalizedMessage() - * - * @deprecated Depends on {@link LocalizedException}, which has been deprecated. */ - @Deprecated(since = "1.7", forRemoval = true) public static String getLocalizedMessage(final Throwable exception, final Locale locale) { if (exception == null) { return null; } if (locale == null) { - return exception.getMessage(); // See the policy documented in LocalizedException.getMessage() + return exception.getMessage(); } - if (exception instanceof LocalizedException) { - final InternationalString i18n = ((LocalizedException) exception).getInternationalMessage(); - if (i18n != null) { - final String message = i18n.toString(locale); - if (message != null) { - return message; - } + if (exception instanceof Localized) { + final Locale actual = ((Localized) exception).getLocale(); + if (actual != null && !locale.getLanguage().equalsIgnoreCase(actual.getLanguage())) { + return exception.getMessage(); } } return exception.getLocalizedMessage(); diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/LocalizedException.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/LocalizedException.java deleted file mode 100644 index 1f5c1a35cb..0000000000 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/LocalizedException.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.sis.util; - -import java.util.Locale; -import org.opengis.util.InternationalString; - - -/** - * An exception which can produce an error message in the client locale. - * Exceptions implementing this interface apply the following policy: - * - * <ul> - * <li>{@link #getMessage()} returns the message in the {@linkplain Locale#getDefault() default locale}. - * In a client-server architecture, this is often the locale on the server side.</li> - * <li>{@link #getLocalizedMessage()} returns the message in a locale that depends on the context - * in which the exception has been thrown. This is often the locale used by a {@link java.text.Format} - * or {@link org.apache.sis.storage.DataStore} instance, - * and can be presumed to be the locale on the client side.</li> - * <li>{@link #getInternationalMessage()} may return the message in arbitrary locale (optional operation). - * This method is specific to Apache SIS.</li> - * </ul> - * - * <h2>Example</h2> - * If an error occurred while a Japanese client connected to an European server, the localized message may be sent - * to the client in Japanese language while the same error may be logged on the server side in the French language. - * This allows system administrator to analyze the issue without the need to understand client's language. - * - * The above policy is applied on a <em>best-effort</em> basis only. For example, exceptions that - * do not implement {@code LocalizedException} may use any locale (not necessarily the default one), - * and {@code LocalizedException} used as {@linkplain Exception#Exception(Throwable) wrappers} around - * other exception usually lost their localization capability. - * - * @author Martin Desruisseaux (Geomatys) - * @version 1.7 - * - * @see Exceptions#getLocalizedMessage(Throwable, Locale) - * @see org.apache.sis.storage.DataStore#setLocale(Locale) - * - * @since 0.8 - * - * @deprecated Rarely used in practice and support is unequal. - */ -@Deprecated(since = "1.7", forRemoval = true) -public interface LocalizedException { - /** - * Returns the message in the {@linkplain Locale#getDefault() default locale}. - * In a client-server architecture, this is usually the locale on the server side. - * This is the recommended language for logging messages to be read by system administrators. - * - * @return the exception message in the JVM {@linkplain Locale#getDefault() default locale}. - */ - String getMessage(); - - /** - * Returns the message in the locale that depends on the context in which this exception has been thrown. - * For example, it may be the local of a client application connected to a distant server. - * This is the recommended language to show in widgets. - * - * @return the exception message in the locale of a service configured for a particular client. - */ - String getLocalizedMessage(); - - /** - * If this exception is capable to return the message in various locales, returns that message. - * Otherwise returns {@code null}. - * - * @return the exception message, or {@code null} if this exception cannot produce international message. - */ - InternationalString getInternationalMessage(); -} diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java index 7f7cc74cc0..9eea5a2057 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/internal/shared/LocalizedParseException.java @@ -19,10 +19,9 @@ package org.apache.sis.util.internal.shared; import java.util.Locale; import java.text.ParsePosition; import java.text.ParseException; -import org.opengis.util.InternationalString; import org.apache.sis.util.Workaround; import org.apache.sis.util.CharSequences; -import org.apache.sis.util.LocalizedException; +import org.apache.sis.util.Localized; import org.apache.sis.util.resources.Errors; @@ -41,12 +40,22 @@ import org.apache.sis.util.resources.Errors; * * @author Martin Desruisseaux (Geomatys) */ -public final class LocalizedParseException extends ParseException implements LocalizedException { +public final class LocalizedParseException extends ParseException implements Localized { /** * For cross-version compatibility. */ private static final long serialVersionUID = -1467571540435486742L; + /** + * The effective locale of the localized message, or {@code null} if unspecified. + * This is the locale of the message returned by {@link #getLocalizedMessage()}. + * It is specified at construction time, then eventually replaced by the locale + * of the resource used for building the message. + * + * @see #getLocale() + */ + private final Locale locale; + /** * The resources key as one of the {@link Errors.Keys} constant, or 0 if none. * @@ -71,7 +80,16 @@ public final class LocalizedParseException extends ParseException implements Loc * @param errorOffset the position where the error is found while parsing. */ public LocalizedParseException(final Locale locale, final short key, final Object[] parameters, final int errorOffset) { - super(Errors.forLocale(locale).getString(key, parameters), errorOffset); + this(Errors.forLocale(locale), key, parameters, errorOffset); + } + + /** + * Workaround while waiting for JEP 513: Flexible Constructor Bodies. + */ + @Workaround(library="JDK", version="11", fixed="25") + private LocalizedParseException(final Errors resources, final short key, final Object[] parameters, final int errorOffset) { + super(resources.getString(key, parameters), errorOffset); + this.locale = resources.getLocale(); this.parameters = parameters; this.key = key; } @@ -168,14 +186,16 @@ public final class LocalizedParseException extends ParseException implements Loc } /** - * If this exception is capable to return the message in various locales, returns that message. - * Otherwise returns {@code null}. + * Returns the locale of the localized exception message, or {@code null} if unspecified. + * If non-null, this is the effective language of the string returned by {@link #getLocalizedMessage()}. + * + * @return the locale of the localized message, or {@code null} if not explicitly defined. * - * @return the exception message, or {@code null} if this exception cannot produce international message. + * @since 1.8 */ @Override - public InternationalString getInternationalMessage() { - return (key != 0) ? Errors.formatInternational(key, parameters) : null; + public Locale getLocale() { + return locale; } /** diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java index f9e9d5f6f1..9ef85b274d 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/logging/Logging.java @@ -269,9 +269,9 @@ public final class Logging { /* * The message is fetched using Exception.getMessage() instead of getLocalizedMessage() * because in a client-server architecture, we want the locale on the server-side instead - * than the locale on the client side. See LocalizedException policy. + * than the locale on the client side. See the policy documented in the `Exceptions` class. */ - final StringBuilder buffer = new StringBuilder(256).append(Classes.getShortClassName(error)); + final var buffer = new StringBuilder(256).append(Classes.getShortClassName(error)); String message = error.getMessage(); // Targeted to system administrators (see above). if (message != null) { buffer.append(": ").append(message); diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java index 28291f7284..a0e0b8af13 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/package-info.java @@ -39,7 +39,7 @@ * * @author Martin Desruisseaux (Geomatys) * @author Alexis Manin (Geomatys) - * @version 1.7 + * @version 1.8 * @since 0.3 */ package org.apache.sis.util; diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java index 998e711792..106a6cfa8e 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/resources/IndexedResourceBundle.java @@ -294,7 +294,7 @@ public abstract class IndexedResourceBundle extends ResourceBundle implements Lo /* * Loads resources from the UTF file. */ - try (DataInputStream input = new DataInputStream(new BufferedInputStream(resources))) { + try (var input = new DataInputStream(new BufferedInputStream(resources))) { values = new String[input.readInt()]; for (int i=0; i<values.length; i++) { values[i] = input.readUTF(); @@ -307,9 +307,11 @@ public abstract class IndexedResourceBundle extends ResourceBundle implements Lo record.setMessage(exception.getMessage()); // For administrator, use system locale. record.setThrown (exception); Logging.completeAndLog(LOGGER, IndexedResourceBundle.class, methodName, record); - throw (MissingResourceException) new MissingResourceException( + var e = new MissingResourceException( Exceptions.getLocalizedMessage(exception, locale), // For users, use requested locale. - baseName, key).initCause(exception); + baseName, key); + e.initCause(exception); + throw e; } /* * Now, logs the message. This message is provided only in English. diff --git a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java index 32ae104b0a..3ba1de9a6d 100644 --- a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java +++ b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/internal/shared/LocalizedParseExceptionTest.java @@ -50,16 +50,18 @@ public final class LocalizedParseExceptionTest extends TestCase { final var pos = new ParsePosition(0); pos.setErrorIndex(5); final var e = new LocalizedParseException(Locale.CANADA, Angle.class, "Some text to parse", pos); - String message = e.getLocalizedMessage(); + final String message = e.getLocalizedMessage(); assertTrue(message.contains("Some text to parse"), message); assertTrue(message.contains("cannot be parsed"), message); assertTrue(message.contains("Angle"), message); assertEquals(message, Exceptions.getLocalizedMessage(e, Locale.CANADA)); - message = Exceptions.getLocalizedMessage(e, Locale.FRANCE); - assertTrue(message.contains("Some text to parse"), message); - assertTrue(message.contains("n’est pas reconnu"), message); - assertTrue(message.contains("Angle"), message); + final String localized = Exceptions.getLocalizedMessage(e, Locale.FRANCE); + if (!localized.equals(message)) { // Locale-dependent test. + assertTrue(localized.contains("Some text to parse"), localized); + assertTrue(localized.contains("n’est pas reconnu"), localized); + assertTrue(localized.contains("Angle"), localized); + } } /** diff --git a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java index 98cd70a217..49d650150a 100644 --- a/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java +++ b/optional/src/org.apache.sis.gui/main/org/apache/sis/gui/referencing/WKTPane.java @@ -72,6 +72,7 @@ final class WKTPane extends StringConverter<Convention> implements ChangeListene /** * Creates a new pane for showing CRS Well Known Text. */ + @SuppressWarnings("LeakingThisInConstructor") WKTPane(final Locale locale) { final Convention[] sc = { // Selected conventions in the order we want them to appear. Convention.WKT2_SIMPLIFIED, @@ -110,11 +111,11 @@ final class WKTPane extends StringConverter<Convention> implements ChangeListene case WKT1_COMMON_UNITS: version = "GDAL 1-2"; break; default: return c.name(); } - String text = vocabulary.getString(Vocabulary.Keys.Version_2, "WKT (Well Known Text)", version); + String label = vocabulary.getString(Vocabulary.Keys.Version_2, "WKT (Well Known Text)", version); if (simplified) { - text += " — " + vocabulary.getString(Vocabulary.Keys.Simplified); + label += " — " + vocabulary.getString(Vocabulary.Keys.Simplified); } - return text; + return label; } /**
