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

commit 5e334c44a4da9649e772b1c0d615a2d9712c6b25
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Tue May 9 14:37:34 2023 +0200

    Remove usage of `ResourceBundle.Control` because it is not supported in the 
context of named modules.
    Move calls to `ResourceBundle.getBundle(…)` in the modules that provide the 
resources because `getBundle(…)` become caller-sensitive in JPMS context.
---
 .../org/apache/sis/internal/gui/Resources.java     |  39 ++++---
 .../org/apache/sis/internal/gui/Resources_en.java  |  30 ++++++
 .../org/apache/sis/internal/gui/Resources_fr.java  |  30 ++++++
 .../apache/sis/cloud/aws/internal/Resources.java   |  35 ++++--
 .../sis/cloud/aws/internal/Resources_en.java       |  30 ++++++
 .../sis/cloud/aws/internal/Resources_fr.java       |  30 ++++++
 .../org/apache/sis/internal/feature/Resources.java |  35 ++++--
 .../apache/sis/internal/feature/Resources_en.java  |  30 ++++++
 .../apache/sis/internal/feature/Resources_fr.java  |  30 ++++++
 .../apache/sis/internal/metadata/Resources.java    |  35 ++++--
 .../apache/sis/internal/metadata/Resources_en.java |  30 ++++++
 .../apache/sis/internal/metadata/Resources_fr.java |  30 ++++++
 .../apache/sis/internal/gazetteer/Resources.java   |  35 ++++--
 .../sis/internal/gazetteer/Resources_en.java       |  30 ++++++
 .../sis/internal/gazetteer/Resources_fr.java       |  30 ++++++
 .../apache/sis/internal/referencing/Resources.java |  35 ++++--
 .../sis/internal/referencing/Resources_en.java     |  30 ++++++
 .../sis/internal/referencing/Resources_fr.java     |  30 ++++++
 .../java/org/apache/sis/util/resources/Errors.java |  35 ++++--
 .../org/apache/sis/util/resources/Errors_en.java   |  30 ++++++
 .../org/apache/sis/util/resources/Errors_fr.java   |  30 ++++++
 .../sis/util/resources/IndexedResourceBundle.java  |  83 ++++++--------
 .../java/org/apache/sis/util/resources/Loader.java | 120 ---------------------
 .../org/apache/sis/util/resources/Messages.java    |  35 ++++--
 .../org/apache/sis/util/resources/Messages_en.java |  30 ++++++
 .../org/apache/sis/util/resources/Messages_fr.java |  30 ++++++
 .../org/apache/sis/util/resources/Vocabulary.java  |  35 ++++--
 .../apache/sis/util/resources/Vocabulary_en.java   |  30 ++++++
 .../apache/sis/util/resources/Vocabulary_fr.java   |  30 ++++++
 .../util/resources/IndexedResourceBundleTest.java  |  10 +-
 .../org/apache/sis/util/resources/LoaderTest.java  |  48 ---------
 .../org/apache/sis/internal/geotiff/Resources.java |  35 ++++--
 .../apache/sis/internal/geotiff/Resources_en.java  |  30 ++++++
 .../apache/sis/internal/geotiff/Resources_fr.java  |  30 ++++++
 .../org/apache/sis/internal/netcdf/Resources.java  |  35 ++++--
 .../apache/sis/internal/netcdf/Resources_en.java   |  30 ++++++
 .../apache/sis/internal/netcdf/Resources_fr.java   |  30 ++++++
 .../apache/sis/internal/sql/feature/Resources.java |  35 ++++--
 .../sis/internal/sql/feature/Resources_en.java     |  30 ++++++
 .../sis/internal/sql/feature/Resources_fr.java     |  30 ++++++
 .../org/apache/sis/internal/storage/Resources.java |  35 ++++--
 .../apache/sis/internal/storage/Resources_en.java  |  30 ++++++
 .../apache/sis/internal/storage/Resources_fr.java  |  30 ++++++
 43 files changed, 1132 insertions(+), 368 deletions(-)

diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
index 8e448e367c..b65b4ca7e2 100644
--- 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.gui;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import javafx.event.ActionEvent;
@@ -34,10 +34,10 @@ import org.apache.sis.util.resources.IndexedResourceBundle;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Johann Sorel (Geomatys)
- * @version 1.3
+ * @version 1.4
  * @since   1.1
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -440,13 +440,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -466,8 +474,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
@@ -476,8 +489,8 @@ public final class Resources extends IndexedResourceBundle {
      * @return resources in the default locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources getInstance() throws MissingResourceException {
-        return getBundle(Resources.class, null);
+    public static Resources getInstance() {
+        return (Resources) getBundle(Resources.class.getName());
     }
 
     /**
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_en.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_en.java
new file mode 100644
index 0000000000..3a334ae837
--- /dev/null
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.gui;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.java
 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.java
new file mode 100644
index 0000000000..261d4af678
--- /dev/null
+++ 
b/application/sis-javafx/src/main/java/org/apache/sis/internal/gui/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.gui;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
 
b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
index 5880d564c4..871b6feb90 100644
--- 
a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
+++ 
b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.cloud.aws.internal;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.apache.sis.util.resources.KeyConstants;
@@ -29,10 +29,10 @@ import org.apache.sis.util.resources.IndexedResourceBundle;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.2
+ * @version 1.4
  * @since   1.2
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -96,13 +96,21 @@ public final class Resources extends IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there is no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -122,8 +130,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_en.java
 
b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_en.java
new file mode 100644
index 0000000000..2d7cfff79a
--- /dev/null
+++ 
b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cloud.aws.internal;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.java
 
b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.java
new file mode 100644
index 0000000000..09e7c77750
--- /dev/null
+++ 
b/cloud/sis-cloud-aws/src/main/java/org/apache/sis/cloud/aws/internal/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.cloud.aws.internal;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java 
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
index 1c89d38a7d..4102278c5e 100644
--- 
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.feature;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Map;
 import java.util.Locale;
 import java.util.MissingResourceException;
@@ -32,10 +32,10 @@ import org.apache.sis.util.resources.IndexedResourceBundle;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.8
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -505,13 +505,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -531,8 +539,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_en.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_en.java
new file mode 100644
index 0000000000..29d264c41f
--- /dev/null
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.feature;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.java
 
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.java
new file mode 100644
index 0000000000..252e7c2a4e
--- /dev/null
+++ 
b/core/sis-feature/src/main/java/org/apache/sis/internal/feature/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.feature;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
index 9dfde583cb..7c1c5497fd 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.metadata;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.opengis.util.InternationalString;
@@ -31,10 +31,10 @@ import 
org.apache.sis.util.resources.ResourceInternationalString;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.4
  * @since   1.0
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -103,13 +103,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -129,8 +137,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_en.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_en.java
new file mode 100644
index 0000000000..79f536473b
--- /dev/null
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.metadata;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.java
 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.java
new file mode 100644
index 0000000000..8dd3119b57
--- /dev/null
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.metadata;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources.java
 
b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources.java
index d9ab7cfa95..84f0a61480 100644
--- 
a/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources.java
+++ 
b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.gazetteer;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
@@ -32,10 +32,10 @@ import 
org.apache.sis.util.resources.ResourceInternationalString;
  * in the Apache SIS project, see {@link org.apache.sis.util.resources} 
package.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.4
  * @since   0.8
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -140,13 +140,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -166,8 +174,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources_en.java
 
b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources_en.java
new file mode 100644
index 0000000000..d8c7b5e73c
--- /dev/null
+++ 
b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.gazetteer;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources_fr.java
 
b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources_fr.java
new file mode 100644
index 0000000000..1c0575f0d0
--- /dev/null
+++ 
b/core/sis-referencing-by-identifiers/src/main/java/org/apache/sis/internal/gazetteer/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.gazetteer;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
index a053f3f733..45440ff4a3 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.referencing;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.Map;
 import java.util.MissingResourceException;
@@ -32,10 +32,10 @@ import 
org.apache.sis.util.resources.ResourceInternationalString;
  * by all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.8
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -597,13 +597,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -623,8 +631,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_en.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_en.java
new file mode 100644
index 0000000000..6234e01430
--- /dev/null
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.referencing;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.java
new file mode 100644
index 0000000000..25aa0c32f7
--- /dev/null
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/internal/referencing/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.referencing;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
index c9e8ec53db..2c6347cfb3 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.util.resources;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Map;
 import java.util.Locale;
 import java.util.MissingResourceException;
@@ -35,10 +35,10 @@ import org.opengis.util.InternationalString;
  * as they want.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.3
  */
-public final class Errors extends IndexedResourceBundle {
+public class Errors extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -1072,13 +1072,21 @@ public final class Errors extends IndexedResourceBundle 
{
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    Errors(final URL resources) {
-        super(resources);
+    public Errors() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -1098,8 +1106,13 @@ public final class Errors extends IndexedResourceBundle {
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Errors getResources(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Errors.class, locale);
+    public static Errors getResources(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Errors) getBundle(Errors.class.getName(), nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_en.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_en.java
new file mode 100644
index 0000000000..10e600d54b
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.resources;
+
+
+/**
+ * Resources in English language.
+ */
+public class Errors_en extends Errors {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Errors_en() {
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.java
new file mode 100644
index 0000000000..afae99982b
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.resources;
+
+
+/**
+ * Resources in French language.
+ */
+public class Errors_fr extends Errors {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Errors_fr() {
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
index c1b6b76694..bcad4f1944 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/IndexedResourceBundle.java
@@ -17,10 +17,10 @@
 package org.apache.sis.util.resources;
 
 import java.net.URI;
-import java.net.URL;
 import java.io.BufferedInputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.Map;
@@ -83,7 +83,7 @@ import org.apache.sis.measure.Range;
  * @version 1.4
  * @since   0.3
  */
-public class IndexedResourceBundle extends ResourceBundle implements Localized 
{
+public abstract class IndexedResourceBundle extends ResourceBundle implements 
Localized {
     /**
      * The logger for localization events.
      */
@@ -114,18 +114,13 @@ public class IndexedResourceBundle extends ResourceBundle 
implements Localized {
     static final int FIRST = 1;
 
     /**
-     * The path of the binary file containing resources, or {@code null} if 
there are no resources
-     * or if the resources have already been loaded. The resources may be a 
file or an entry in a
-     * JAR file.
-     */
-    private URL resources;
-
-    /**
-     * The array of resources. Keys are an array index plus {@value #FIRST}. 
For example, the value for key "14" is
-     * {@code values[13]}. This array will be loaded only when first needed. 
We should not load it at construction
-     * time, because some {@code ResourceBundle} objects will never ask for 
values.  This is particularly the case
-     * for parent resources of {@code Resources_fr_CA}, {@code Resources_en}, 
{@code Resources_de}, etc. which will
-     * only be used if a key has not been found in the child resources.
+     * The array of resources. Keys are an array index plus {@value #FIRST}.
+     * For example, the value for key "14" is {@code values[13]}.
+     *
+     * This array will be loaded only when first needed. We should not load it 
at construction time,
+     * because some {@code ResourceBundle} instances will never ask for 
values. In particular, parent
+     * of {@code Resources_en}, {@code Resources_fr}, <i>etc.</i> which will 
only be queries if a key
+     * has not been found in the child resources.
      *
      * @see #ensureLoaded(String)
      */
@@ -146,53 +141,43 @@ public class IndexedResourceBundle extends ResourceBundle 
implements Localized {
     private transient short lastKey;
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
+     * Constructs a new resource bundle loading data from a UTF file derived 
from the class name.
+     */
+    protected IndexedResourceBundle() {
+    }
+
+    /**
+     * Returns the given locale if non-null, or the default locale otherwise.
      *
-     * @param  resources  the path of the binary file containing resources, or 
{@code null} if
-     *         there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * @param  locale  the user-specified locale.
+     * @return the locale to use for fetching a resource bundle.
      */
-    protected IndexedResourceBundle(final URL resources) {
-        this.resources = resources;
+    protected static Locale nonNull(final Locale locale) {
+        return (locale != null) ? locale : Locale.getDefault();
     }
 
     /**
-     * Returns a resource bundle of the specified class.
+     * Opens the binary file containing the localized resources to load.
+     * Subclasses shall implement this method as below:
      *
-     * @param  <T>      the resource bundle class.
-     * @param  base     the resource bundle class.
-     * @param  locale   the locale, or {@code null} for the default locale.
-     * @return resources in the given locale.
-     * @throws MissingResourceException if resources cannot be found.
+     * {@snippet lang="java" :
+     *     return getClass().getResourceAsStream(name);
+     *     }
+     *
+     * Above implementation needs to be provided by subclasses because the
+     * call to {@link Class#getResourceAsStream(String)} is caller-sensitive.
      *
-     * @see Vocabulary#getResources(Locale)
-     * @see Errors#getResources(Locale)
+     * @param  name  name of the UTF file to open.
+     * @return a stream opened on the given file.
      */
-    protected static <T extends IndexedResourceBundle> T getBundle(Class<T> 
base, Locale locale)
-            throws MissingResourceException
-    {
-        if (locale == null) {
-            locale = Locale.getDefault();
-        }
-        // No caching; we rely on the one implemented in ResourceBundle.
-        return base.cast(getBundle(base.getName(), locale, 
base.getClassLoader(), Loader.INSTANCE));
-    }
+    protected abstract InputStream getResourceAsStream(String name);
 
     /**
      * Returns a handler for the constants declared in the inner {@code Keys} 
class.
-     * Subclasses should override this method for efficiency, but this is not 
mandatory.
      *
      * @return a handler for the constants declared in the inner {@code Keys} 
class.
      */
-    protected KeyConstants getKeyConstants() {
-        Class<?> keysClass = KeyConstants.class;
-        for (final Class<?> inner : getClass().getClasses()) {
-            if ("Keys".equals(inner.getSimpleName())) {
-                keysClass = inner;
-                break;
-            }
-        }
-        return new KeyConstants(keysClass);
-    }
+    protected abstract KeyConstants getKeyConstants();
 
     /**
      * Returns an enumeration of the keys.
@@ -290,6 +275,7 @@ public class IndexedResourceBundle extends ResourceBundle 
implements Localized {
         if (values == null) synchronized (this) {
             values = this.values;
             if (values == null) {
+                final InputStream resources = 
getResourceAsStream(getClass().getSimpleName() + ".utf");
                 /*
                  * If there are no explicit resources for this instance, 
inherit the resources
                  * from the parent. Note that this IndexedResourceBundle 
instance may still
@@ -315,7 +301,7 @@ public class IndexedResourceBundle extends ResourceBundle 
implements Localized {
                     /*
                      * Loads resources from the UTF file.
                      */
-                    try (DataInputStream input = new DataInputStream(new 
BufferedInputStream(resources.openStream()))) {
+                    try (DataInputStream input = new DataInputStream(new 
BufferedInputStream(resources))) {
                         values = new String[input.readInt()];
                         for (int i=0; i<values.length; i++) {
                             values[i] = input.readUTF();
@@ -347,7 +333,6 @@ public class IndexedResourceBundle extends ResourceBundle 
implements Localized {
                     }
                     record.setParameters(new String[] {language, baseName});
                     Logging.completeAndLog(LOGGER, 
IndexedResourceBundle.class, methodName, record);
-                    resources = null;                                          
 // Not needed anymore, let GC do its job.
                 }
                 this.values = values;
             }
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java
deleted file mode 100644
index a16ad01d06..0000000000
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Loader.java
+++ /dev/null
@@ -1,120 +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.resources;
-
-import java.net.URL;
-import java.util.List;
-import java.util.Locale;
-import java.util.ResourceBundle;
-import java.lang.reflect.InvocationTargetException;
-import java.io.IOException;
-
-
-/**
- * Controls the resource bundle loading. This class looks for {@code .utf} 
files rather than
- * the Java default {@code .class} or {@code .properties} files.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
- * @since   0.3
- */
-final class Loader extends ResourceBundle.Control {
-    /**
-     * The filename extension of resource files, without leading dot.
-     */
-    private static final String EXTENSION = "utf";
-
-    /**
-     * The formats supported by this loader.
-     */
-    private static final List<String> FORMATS = List.of("apache-sis." + 
EXTENSION);
-
-    /**
-     * The singleton instance of the {@link Loader} class.
-     */
-    public static final Loader INSTANCE = new Loader();
-
-    /**
-     * Creates the unique instance of the SIS resource bundle loader.
-     */
-    private Loader() {
-    }
-
-    /**
-     * Returns the formats supported by this loader.
-     * The only supported format is {@code "apache-sis.utf"}.
-     *
-     * @param  baseName  ignored.
-     * @return the supported formats.
-     */
-    @Override
-    public List<String> getFormats(String baseName) {
-        return FORMATS;
-    }
-
-    /**
-     * Returns {@code false} in all cases, since our implementation never 
needs reload.
-     */
-    @Override
-    public boolean needsReload(final String baseName, final Locale locale, 
final String format,
-            final ClassLoader loader, final ResourceBundle bundle, long 
loadTime)
-    {
-        return false;
-    }
-
-    /**
-     * Instantiates a new resource bundle.
-     *
-     * @param  baseName  the fully qualified name of the base resource bundle.
-     * @param  locale    the locale for which the resource bundle should be 
instantiated.
-     * @param  format    ignored since this loader supports only one format.
-     * @param  loader    the class loader to use.
-     * @param  reload    ignored since this loader does not support resource 
expiration.
-     * @return the resource bundle instance, or null if none could be found.
-     */
-    @Override
-    public ResourceBundle newBundle(final String baseName, final Locale locale,
-            final String format, final ClassLoader loader, final boolean 
reload)
-            throws IllegalAccessException, InstantiationException, IOException
-    {
-        final Class<?> classe;
-        try {
-            classe = Class.forName(baseName, true, loader);
-        } catch (ClassNotFoundException e) {
-            return null;        // This is the expected behavior as of 
Control.newBundle contract.
-        }
-        /*
-         * Gets the filename relative to the class we created, since we 
assumes that UTF files
-         * are in the same package. Then check for file existence and 
instantiate the resource
-         * bundle only if the file is found.
-         */
-        final String classname = classe.getSimpleName();
-        final URL resources = 
classe.getResource(toResourceName(toBundleName(classname, locale), EXTENSION));
-        /*
-         * Instantiate now the resource bundle. The resources URL may be null, 
in which case the
-         * bundle will inherit the strings from the parent bundle. In every 
cases, the strings
-         * will be loaded only when first needed.
-         *
-         * Note: Do not call Constructor.setAccessible(true) - this is not 
allowed in Applet.
-         */
-        try {
-            return (ResourceBundle) 
classe.getDeclaredConstructor(URL.class).newInstance(resources);
-        } catch (NoSuchMethodException | InvocationTargetException e) {
-            throw (InstantiationException) new 
InstantiationException(e.toString()).initCause(e);
-        }
-    }
-}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
index 3f288af075..23947427a1 100644
--- a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
+++ b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.util.resources;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.opengis.util.InternationalString;
@@ -26,10 +26,10 @@ import org.opengis.util.InternationalString;
  * Locale-dependent resources for miscellaneous (often logging) messages.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.4
  * @since   0.3
  */
-public final class Messages extends IndexedResourceBundle {
+public class Messages extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -232,13 +232,21 @@ public final class Messages extends IndexedResourceBundle 
{
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    Messages(final URL resources) {
-        super(resources);
+    public Messages() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -258,8 +266,13 @@ public final class Messages extends IndexedResourceBundle {
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Messages getResources(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Messages.class, locale);
+    public static Messages getResources(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Messages) getBundle(Messages.class.getName(), nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_en.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_en.java
new file mode 100644
index 0000000000..fde522e973
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.resources;
+
+
+/**
+ * Resources in English language.
+ */
+public class Messages_en extends Messages {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Messages_en() {
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.java
new file mode 100644
index 0000000000..05fedb1b99
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Messages_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.resources;
+
+
+/**
+ * Resources in French language.
+ */
+public class Messages_fr extends Messages {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Messages_fr() {
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
index 3a28c61828..223f270f75 100644
--- 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.util.resources;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Map;
 import java.util.Locale;
 import java.util.MissingResourceException;
@@ -27,10 +27,10 @@ import org.opengis.util.InternationalString;
  * Locale-dependent resources for single words or short sentences.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.1
+ * @version 1.4
  * @since   0.3
  */
-public final class Vocabulary extends IndexedResourceBundle {
+public class Vocabulary extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -1414,13 +1414,21 @@ public final class Vocabulary extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    Vocabulary(final URL resources) {
-        super(resources);
+    public Vocabulary() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -1440,8 +1448,13 @@ public final class Vocabulary extends 
IndexedResourceBundle {
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Vocabulary getResources(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Vocabulary.class, locale);
+    public static Vocabulary getResources(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Vocabulary) getBundle(Vocabulary.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_en.java
 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_en.java
new file mode 100644
index 0000000000..f0171c01f3
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.resources;
+
+
+/**
+ * Resource in English language.
+ */
+public class Vocabulary_en extends Vocabulary {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Vocabulary_en() {
+    }
+}
diff --git 
a/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.java
 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.java
new file mode 100644
index 0000000000..902a38207d
--- /dev/null
+++ 
b/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.resources;
+
+
+/**
+ * Messages in French language.
+ */
+public class Vocabulary_fr extends Vocabulary {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Vocabulary_fr() {
+    }
+}
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
 
b/core/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
index c1f1c34312..2851ee6382 100644
--- 
a/core/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
+++ 
b/core/sis-utility/src/test/java/org/apache/sis/util/resources/IndexedResourceBundleTest.java
@@ -25,7 +25,6 @@ import java.util.logging.SimpleFormatter;
 import org.opengis.metadata.maintenance.ScopeCode;
 import org.opengis.util.InternationalString;
 import org.apache.sis.test.DependsOnMethod;
-import org.apache.sis.test.DependsOn;
 import org.apache.sis.test.TestCase;
 import org.junit.Test;
 import org.junit.After;
@@ -49,7 +48,6 @@ import static 
org.apache.sis.test.Assertions.assertSerializedEquals;
  * @version 0.4
  * @since   0.3
  */
-@DependsOn(LoaderTest.class)
 public final class IndexedResourceBundleTest extends TestCase {
     /**
      * The resource bundle in process of being tested. Shall be reset to 
{@code null} after every
@@ -67,11 +65,11 @@ public final class IndexedResourceBundleTest extends 
TestCase {
         final Errors french  = Errors.getResources(Locale.FRENCH);
         final Errors canada  = Errors.getResources(Locale.CANADA);
         final Errors quebec  = Errors.getResources(Locale.CANADA_FRENCH);
-        assertNotSame(english, Errors.getResources(Locale.US));
-        assertNotSame(english, Errors.getResources(Locale.UK));
+        assertSame   (english, Errors.getResources(Locale.US));
+        assertSame   (english, Errors.getResources(Locale.UK));
         assertNotSame(english, french);
-        assertNotSame(english, canada);
-        assertNotSame(french,  quebec);
+        assertSame   (english, canada);
+        assertSame   (french,  quebec);
 
         assertSame(english, Errors.getResources(Locale.ENGLISH));
         assertSame(canada,  Errors.getResources(Locale.CANADA));
diff --git 
a/core/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java 
b/core/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
deleted file mode 100644
index 28b681dfb4..0000000000
--- 
a/core/sis-utility/src/test/java/org/apache/sis/util/resources/LoaderTest.java
+++ /dev/null
@@ -1,48 +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.resources;
-
-import java.util.Locale;
-import java.util.List;
-import org.apache.sis.test.TestCase;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-
-/**
- * Tests the {@link Loader} class.
- *
- * @author  Martin Desruisseaux (Geomatys)
- * @version 0.3
- * @since   0.3
- */
-public final class LoaderTest extends TestCase {
-    /**
-     * Tests the {@link Loader#getCandidateLocales(String, Locale)} method
-     * for {@link Locale#US}.
-     */
-    @Test
-    public void testCandidateLocalesForUS() {
-        final List<Locale> locales = Loader.INSTANCE.getCandidateLocales(
-                "org.apache.sis.util.resources.Vocabulary", Locale.US);
-        assertEquals("locales.size()", 3,          locales.size());
-        assertEquals("locales[0]", Locale.US,      locales.get(0));
-        assertEquals("locales[1]", Locale.ENGLISH, locales.get(1));
-        assertEquals("locales[2]", Locale.ROOT,    locales.get(2));
-    }
-}
diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
index ac6264953b..e2e9be6349 100644
--- 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.geotiff;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.opengis.util.InternationalString;
@@ -31,10 +31,10 @@ import 
org.apache.sis.util.resources.ResourceInternationalString;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.4
  * @since   0.8
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -224,13 +224,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -250,8 +258,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_en.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_en.java
new file mode 100644
index 0000000000..d464ed53b6
--- /dev/null
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.geotiff;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.java
 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.java
new file mode 100644
index 0000000000..50af0f3621
--- /dev/null
+++ 
b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/geotiff/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.geotiff;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java
index 8072d6e859..70dbeddcb1 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.netcdf;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.apache.sis.util.resources.KeyConstants;
@@ -29,10 +29,10 @@ import org.apache.sis.util.resources.IndexedResourceBundle;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 0.8
+ * @version 1.4
  * @since   0.8
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -195,13 +195,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -221,8 +229,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_en.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_en.java
new file mode 100644
index 0000000000..7e5367f040
--- /dev/null
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.netcdf;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.java
 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.java
new file mode 100644
index 0000000000..708cad6ac7
--- /dev/null
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.netcdf;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java
 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java
index cad681bd6a..f25d2ec4c4 100644
--- 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java
+++ 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.sql.feature;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.opengis.util.InternationalString;
@@ -31,10 +31,10 @@ import 
org.apache.sis.util.resources.ResourceInternationalString;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (Geomatys)
- * @version 1.0
+ * @version 1.4
  * @since   1.0
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -133,13 +133,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -159,8 +167,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_en.java
 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_en.java
new file mode 100644
index 0000000000..1c7e4fcedd
--- /dev/null
+++ 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.sql.feature;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.java
 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.java
new file mode 100644
index 0000000000..8f60f11d01
--- /dev/null
+++ 
b/storage/sis-sqlstore/src/main/java/org/apache/sis/internal/sql/feature/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.sql.feature;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
index d6662be5af..b859d71fbd 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources.java
@@ -16,7 +16,7 @@
  */
 package org.apache.sis.internal.storage;
 
-import java.net.URL;
+import java.io.InputStream;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import org.opengis.util.InternationalString;
@@ -31,10 +31,10 @@ import 
org.apache.sis.util.resources.ResourceInternationalString;
  * all modules in the Apache SIS project, see {@link 
org.apache.sis.util.resources} package.
  *
  * @author  Martin Desruisseaux (IRD, Geomatys)
- * @version 1.0
+ * @version 1.4
  * @since   0.8
  */
-public final class Resources extends IndexedResourceBundle {
+public class Resources extends IndexedResourceBundle {
     /**
      * Resource keys. This class is used when compiling sources, but no 
dependencies to
      * {@code Keys} should appear in any resulting class files. Since the Java 
compiler
@@ -457,13 +457,21 @@ public final class Resources extends 
IndexedResourceBundle {
     }
 
     /**
-     * Constructs a new resource bundle loading data from the given UTF file.
-     *
-     * @param resources  the path of the binary file containing resources, or 
{@code null} if
-     *        there are no resources. The resources may be a file or an entry 
in a JAR file.
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
      */
-    public Resources(final URL resources) {
-        super(resources);
+    public Resources() {
+    }
+
+    /**
+     * Opens the binary file containing the localized resources to load.
+     * This method delegates to {@link Class#getResourceAsStream(String)},
+     * but this delegation must be done from the same module than the one
+     * that provides the binary file.
+     */
+    @Override
+    protected InputStream getResourceAsStream(final String name) {
+        return getClass().getResourceAsStream(name);
     }
 
     /**
@@ -483,8 +491,13 @@ public final class Resources extends IndexedResourceBundle 
{
      * @return resources in the given locale.
      * @throws MissingResourceException if resources cannot be found.
      */
-    public static Resources forLocale(final Locale locale) throws 
MissingResourceException {
-        return getBundle(Resources.class, locale);
+    public static Resources forLocale(final Locale locale) {
+        /*
+         * We cannot factorize this method into the parent class, because we 
need to call
+         * `ResourceBundle.getBundle(String)` from the module that provides 
the resources.
+         * We do not cache the result because `ResourceBundle` already 
provides a cache.
+         */
+        return (Resources) getBundle(Resources.class.getName(), 
nonNull(locale));
     }
 
     /**
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_en.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_en.java
new file mode 100644
index 0000000000..32deddb9eb
--- /dev/null
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_en.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.storage;
+
+
+/**
+ * Resource in English language.
+ */
+public class Resources_en extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_en() {
+    }
+}
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.java
new file mode 100644
index 0000000000..a606dbc0c5
--- /dev/null
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/Resources_fr.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.storage;
+
+
+/**
+ * Messages in French language.
+ */
+public class Resources_fr extends Resources {
+    /**
+     * Constructs a new resource bundle loading data from
+     * the resource file of the same name than this class.
+     */
+    public Resources_fr() {
+    }
+}

Reply via email to