# HG changeset patch # User mchung # Date 1513898329 28800 # Node ID b6fc9a193661c7273e4edb5d9b79c209bc6e695f # Parent b95b08f3e1a83fc8f7b56a2e6f65f9948732c8a2 8193767: Improve javadoc in ResourceBundle working with modules Reviewed-by: alanb, naoto diff -r b95b08f3e1a8 -r b6fc9a193661 src/java.base/share/classes/java/util/ResourceBundle.java --- a/src/java.base/share/classes/java/util/ResourceBundle.java Sat Jan 13 16:47:11 2018 +0000 +++ b/src/java.base/share/classes/java/util/ResourceBundle.java Thu Dec 21 15:18:49 2017 -0800 @@ -204,58 +204,70 @@ * known concrete subclasses {@code ListResourceBundle} and * {@code PropertyResourceBundle} are thread-safe. * - *

Resource Bundles in Named Modules

+ *

Resource Bundles and Named Modules

+ * + * Resource bundles can be deployed in modules in the following ways: + * + *

Resource bundles together with an application

+ * + * Resource bundles can be deployed together with an application in the same + * module. In that case, the resource bundles are loaded + * by code in the module by calling the {@link #getBundle(String)} + * or {@link #getBundle(String, Locale)} method. + * + *

Resource bundles as service providers

* - * When resource bundles are deployed in named modules, the following - * module-specific requirements and restrictions are applied. + * Resource bundles can be deployed in one or more service provider modules + * and they can be located using {@link ServiceLoader}. + * A {@linkplain ResourceBundleProvider service} interface or class must be + * defined. The caller module declares that it uses the service, the service + * provider modules declare that they provide implementations of the service. + * Refer to {@link ResourceBundleProvider} for developing resource bundle + * services and deploying resource bundle providers. + * The module obtaining the resource bundle can be a resource bundle + * provider itself; in which case this module only locates the resource bundle + * via service provider mechanism. + * + *

A {@linkplain ResourceBundleProvider resource bundle provider} can + * provide resource bundles in any format such XML which replaces the need + * of {@link Control ResourceBundle.Control}. + * + *

Resource bundles in other modules and class path

* - * + * Resource bundles in a named module may be encapsulated so that + * it cannot be located by code in other modules. Resource bundles + * in unnamed modules and class path are open for any module to access. + * Resource bundle follows the resource encapsulation rules as specified + * in {@link Module#getResourceAsStream(String)}. + * + *

The {@code getBundle} factory methods with no {@code Control} parameter + * locate and load resource bundles from + * {@linkplain ResourceBundleProvider service providers}. + * It may continue the search as if calling {@link Module#getResourceAsStream(String)} + * to find the named resource from a given module and calling + * {@link ClassLoader#getResourceAsStream(String)}; refer to + * the specification of the {@code getBundle} method for details. + * Only non-encapsulated resource bundles of "{@code java.class}" + * or "{@code java.properties}" format are searched. * - *

ResourceBundleProvider Service Providers

+ *

If the caller module is a + * + * resource bundle provider, it does not fall back to the + * class loader search. + * + *

Resource bundles in automatic modules

* - * The {@code getBundle} factory methods load service providers of - * {@link ResourceBundleProvider}, if available, using {@link ServiceLoader}. - * The service type is designated by - * {@code + ".spi." + + "Provider"}. For - * example, if the base name is "{@code com.example.app.MyResources}", the service - * type is {@code com.example.app.spi.MyResourcesProvider}. - *

- * In named modules, the loaded service providers for the given base name are - * used to load resource bundles. If no service provider is available, or if - * none of the service providers returns a resource bundle and the caller module - * doesn't have its own service provider, the {@code getBundle} factory method - * searches for resource bundles that are local in the caller module and that - * are visible to the class loader of the caller module. The resource bundle - * formats for local module searching are "java.class" and "java.properties". + * A common format of resource bundles is in {@linkplain PropertyResourceBundle + * .properties} file format. Typically {@code .properties} resource bundles + * are packaged in a JAR file. Resource bundle only JAR file can be readily + * deployed as an + * automatic module. For example, if the JAR file contains the + * entry "{@code p/q/Foo_ja.properties}" and no {@code .class} entry, + * when resolved and defined as an automatic module, no package is derived + * for this module. This allows resource bundles in {@code .properties} + * format packaged in one or more JAR files that may contain entries + * in the same directory and can be resolved successfully as + * automatic modules. * *

ResourceBundle.Control

* @@ -268,6 +280,14 @@ * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle} * factory method for details. * + *

{@link ResourceBundle.Control} is designed for an application deployed + * in an unnamed module, for example to support resource bundles in + * non-standard formats or package localized resources in a non-traditional + * convention. {@link ResourceBundleProvider} is the replacement for + * {@code ResourceBundle.Control} when migrating to modules. + * {@code UnsupportedOperationException} will be thrown when a factory + * method that takes the {@code ResourceBundle.Control} parameter is called. + * *

For the {@code getBundle} factory * methods that take no {@link Control} instance, their default behavior of resource bundle loading @@ -815,14 +835,10 @@ /** * Gets a resource bundle using the specified base name, the default locale, - * and the caller's class loader. Calling this method is equivalent to calling + * and the caller module. Calling this method is equivalent to calling *

- * getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader()), + * getBundle(baseName, Locale.getDefault(), callerModule), *
- * except that getClassLoader() is run with the security - * privileges of ResourceBundle. - * See {@link #getBundle(String, Locale, ClassLoader) getBundle} - * for a complete description of the search and instantiation strategy. * * @param baseName the base name of the resource bundle, a fully qualified class name * @exception java.lang.NullPointerException @@ -830,6 +846,9 @@ * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and the default locale + * + * @see Resource Bundle Search and Loading Strategy + * @see Resource Bundles and Named Modules */ @CallerSensitive public static final ResourceBundle getBundle(String baseName) @@ -887,14 +906,10 @@ /** * Gets a resource bundle using the specified base name and locale, - * and the caller's class loader. Calling this method is equivalent to calling + * and the caller module. Calling this method is equivalent to calling *
- * getBundle(baseName, locale, this.getClass().getClassLoader()), + * getBundle(baseName, locale, callerModule), *
- * except that getClassLoader() is run with the security - * privileges of ResourceBundle. - * See {@link #getBundle(String, Locale, ClassLoader) getBundle} - * for a complete description of the search and instantiation strategy. * * @param baseName * the base name of the resource bundle, a fully qualified class name @@ -905,6 +920,9 @@ * @exception MissingResourceException * if no resource bundle for the specified base name can be found * @return a resource bundle for the given base name and locale + * + * @see Resource Bundle Search and Loading Strategy + * @see Resource Bundles and Named Modules */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, @@ -922,19 +940,6 @@ * getBundle(baseName, Locale.getDefault(), module) * * - *

Resource bundles in named modules may be encapsulated. When - * the resource bundle is loaded from a provider, the caller module - * must have an appropriate uses clause in its module descriptor - * to declare that the module uses implementations of - * {@code + ".spi." + + "Provider"}. - * Otherwise, it will load the resource bundles that are local in the - * given module or that are visible to the class loader of the given module - * (refer to the Resource Bundles in Named Modules - * section for details). - * When the resource bundle is loaded from the specified module, it is - * subject to the encapsulation rules specified by - * {@link Module#getResourceAsStream Module.getResourceAsStream}. - * * @param baseName the base name of the resource bundle, * a fully qualified class name * @param module the module for which the resource bundle is searched @@ -950,6 +955,8 @@ * @since 9 * @spec JPMS * @see ResourceBundleProvider + * @see Resource Bundle Search and Loading Strategy + * @see Resource Bundles and Named Modules */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Module module) { @@ -963,14 +970,15 @@ * on behalf of the specified module. * *

Resource bundles in named modules may be encapsulated. When - * the resource bundle is loaded from a provider, the caller module + * the resource bundle is loaded from a + * {@linkplain ResourceBundleProvider service provider}, the caller module * must have an appropriate uses clause in its module descriptor - * to declare that the module uses implementations of - * {@code + ".spi." + + "Provider"}. + * to declare that the module uses of {@link ResourceBundleProvider} + * for the named resource bundle. * Otherwise, it will load the resource bundles that are local in the - * given module or that are visible to the class loader of the given module - * (refer to the Resource Bundles in Named Modules - * section for details). + * given module as if calling {@link Module#getResourceAsStream(String)} + * or that are visible to the class loader of the given module + * as if calling {@link ClassLoader#getResourceAsStream(String)}. * When the resource bundle is loaded from the specified module, it is * subject to the encapsulation rules specified by * {@link Module#getResourceAsStream Module.getResourceAsStream}. @@ -1000,6 +1008,8 @@ * @return a resource bundle for the given base name and locale in the module * @since 9 * @spec JPMS + * @see Resource Bundle Search and Loading Strategy + * @see Resource Bundles and Named Modules */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) { @@ -1060,28 +1070,25 @@ * Gets a resource bundle using the specified base name, locale, and class * loader. * - *

This method behaves the same as calling - * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a - * default instance of {@link Control} unless another {@link Control} is - * provided with the {@link ResourceBundleControlProvider} SPI. Refer to the + *

When this method is called from a named module and the given + * loader is the class loader of the caller module, this is equivalent + * to calling: + *

+     * getBundle(baseName, targetLocale, callerModule)
+     * 
+ * + * otherwise, this is equivalent to calling: + *
+     * getBundle(baseName, targetLocale, loader, control)
+     * 
+ * where {@code control} is the default instance of {@link Control} unless + * a {@code Control} instance is provided by + * {@link ResourceBundleControlProvider} SPI. Refer to the * description of modifying the default - * behavior. - * - *

The following describes the default - * behavior. + * behavior. The following describes the default behavior. * *

- * Resource bundles in a named module are private to that module. If - * the caller is in a named module, this method will find resource bundles - * from the service providers of {@link java.util.spi.ResourceBundleProvider} - * if any. Otherwise, it will load the resource bundles that are visible to - * the given {@code loader} (refer to the - * Resource Bundles in Named Modules section - * for details). - * If the caller is in a named module and the given {@code loader} is - * different than the caller's class loader, or if the caller is not in - * a named module, this method will not find resource bundles from named - * modules. + * Resource Bundle Search and Loading Strategy * *

getBundle uses the base name, the specified locale, and * the default locale (obtained from {@link java.util.Locale#getDefault() @@ -1201,7 +1208,7 @@ * *

Note:The baseName argument should be a fully * qualified class name. However, for compatibility with earlier versions, - * Sun's Java SE Runtime Environments do not verify this, and so it is + * Java SE Runtime Environments do not verify this, and so it is * possible to access PropertyResourceBundles by specifying a * path name (using "/") instead of a fully qualified class name (using * "."). @@ -1248,7 +1255,7 @@ * * @apiNote If the caller module is a named module and the given * {@code loader} is the caller module's class loader, this method is - * equivalent to {@code getBundle(baseName, locale)}; otherwise, it will not + * equivalent to {@code getBundle(baseName, locale)}; otherwise, it may not * find resource bundles from named modules. * Use {@link #getBundle(String, Locale, Module)} to load resource bundles * on behalf on a specific module instead. @@ -1264,6 +1271,7 @@ * @since 1.2 * @revised 9 * @spec JPMS + * @see Resource Bundles and Named Modules */ @CallerSensitive public static ResourceBundle getBundle(String baseName, Locale locale, @@ -1278,9 +1286,9 @@ /** * Returns a resource bundle using the specified base name, target - * locale, class loader and control. Unlike the {@linkplain - * #getBundle(String, Locale, ClassLoader) getBundle - * factory methods with no control argument}, the given + * locale, class loader and control. Unlike the {@link + * #getBundle(String, Locale, ClassLoader) getBundle} + * factory methods with no {@code control} argument, the given * control specifies how to locate and instantiate resource * bundles. Conceptually, the bundle loading process with the given * control is performed in the following steps. @@ -2365,7 +2373,14 @@ * the callback methods provides the information necessary for the * factory methods to perform the default behavior. - * Note that this class is not supported in named modules. + * + *

{@link ResourceBundle.Control} is designed for an application deployed + * in an unnamed module, for example to support resource bundles in + * non-standard formats or package localized resources in a non-traditional + * convention. {@link ResourceBundleProvider} is the replacement for + * {@code ResourceBundle.Control} when migrating to modules. + * {@code UnsupportedOperationException} will be thrown when a factory + * method that takes the {@code ResourceBundle.Control} parameter is called. * *

In addition to the callback methods, the {@link * #toBundleName(String, Locale) toBundleName} and {@link @@ -2501,8 +2516,8 @@ * } * * - * @apiNote {@code ResourceBundle.Control} is not supported - * in named modules. If the {@code ResourceBundle.getBundle} method with + * @apiNote {@code ResourceBundle.Control} is not supported + * in named modules. If the {@code ResourceBundle.getBundle} method with * a {@code ResourceBundle.Control} is called in a named module, the method * will throw an {@link UnsupportedOperationException}. Any service providers * of {@link ResourceBundleControlProvider} are ignored in named modules. diff -r b95b08f3e1a8 -r b6fc9a193661 src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java --- a/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java Sat Jan 13 16:47:11 2018 +0000 +++ b/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java Thu Dec 21 15:18:49 2017 -0800 @@ -45,42 +45,46 @@ * *

* Resource bundles can be packaged in one or more - * named modules, bundle modules. The consumer of the + * named modules, service provider modules. The consumer of the * resource bundle is the one calling {@link ResourceBundle#getBundle(String)}. * In order for the consumer module to load a resource bundle * "{@code com.example.app.MyResources}" provided by another module, * it will use the {@linkplain java.util.ServiceLoader service loader} - * mechanism. A service interface named "{@code com.example.app.MyResourcesProvider}" - * must be defined and a bundle provider module will provide an - * implementation class of "{@code com.example.app.MyResourcesProvider}" + * mechanism. A service interface named "{@code com.example.app.spi.MyResourcesProvider}" + * must be defined and a service provider module will provide an + * implementation class of "{@code com.example.app.spi.MyResourcesProvider}" * as follows: * - *


- * import com.example.app.MyResourcesProvider;
+ * 
+ * {@code import com.example.app.spi.MyResourcesProvider;
  * class MyResourcesProviderImpl extends AbstractResourceBundleProvider
  *     implements MyResourcesProvider
  * {
+ *     public MyResourcesProviderImpl() {
+ *         super("java.properties");
+ *     }
+ *     // this provider maps the resource bundle to per-language package
  *     protected String toBundleName(String baseName, Locale locale) {
- *         // return the bundle name per the naming of the resource bundle
- *         :
+ *         return "p." + locale.getLanguage() + "." + baseName;
  *     }
  *
  *     public ResourceBundle getBundle(String baseName, Locale locale) {
- *         // this module only provides bundles in french
+ *         // this module only provides bundles in French
  *         if (locale.equals(Locale.FRENCH)) {
  *              return super.getBundle(baseName, locale);
  *         }
+ *         // otherwise return null
  *         return null;
  *     }
- * }
+ * }}
* - * @see - * Resource Bundles in Named Modules - * @see - * ResourceBundleProvider Service Providers + * Refer to {@link ResourceBundleProvider} for details. * + * @see + * Resource Bundles and Named Modules * @since 9 * @spec JPMS + */ public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider { private static final JavaUtilResourceBundleAccess RB_ACCESS = diff -r b95b08f3e1a8 -r b6fc9a193661 src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java --- a/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java Sat Jan 13 16:47:11 2018 +0000 +++ b/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java Thu Dec 21 15:18:49 2017 -0800 @@ -29,33 +29,117 @@ import java.util.ResourceBundle; /** - * {@code ResourceBundleProvider} is a provider interface that is used for - * loading resource bundles for named modules. Implementation classes of - * this interface are loaded with {@link java.util.ServiceLoader ServiceLoader} - * during a call to the - * {@link ResourceBundle#getBundle(String, Locale, ClassLoader) - * ResourceBundle.getBundle} method. The provider service type is determined by - * {@code + ".spi." + + "Provider"}. + * {@code ResourceBundleProvider} is a service provider interface for + * resource bundles. It is used by + * {@link ResourceBundle#getBundle(String) ResourceBundle.getBundle} + * factory methods to locate and load the service providers that are deployed as + * modules via {@link java.util.ServiceLoader ServiceLoader}. + * + *

Developing resource bundle services

* - *

- * For example, if the base name is "com.example.app.MyResources", - * {@code com.example.app.spi.MyResourcesProvider} will be the provider service type: - *

{@code
+ * A service for a resource bundle of a given {@code baseName} must have
+ * a fully-qualified class name of the form:
+ * 
+ * {@code + ".spi." + + "Provider"} + *
+ * + * The service type is in a {@code spi} subpackage as it may be packaged in + * a module separate from the resource bundle providers. + * For example, the service for a resource bundle named + * {@code com.example.app.MyResources} must be + * {@code com.example.app.spi.MyResourcesProvider}: + * + *
+ * {@code package com.example.app.spi;
  * public interface MyResourcesProvider extends ResourceBundleProvider {
  * }
- * }
+ * }
+ * + *

Deploying resource bundle service providers

+ * + * Resource bundles can be deployed in one or more service providers + * in modules. For example, a provider for a service + * named "{@code com.example.app.spi.MyResourcesProvider}" + * has the following implementation class: + * + *
+ * {@code import com.example.app.spi.MyResourcesProvider;
+ * class MyResourcesProviderImpl extends AbstractResourceBundleProvider
+ *     implements MyResourcesProvider
+ * {
+ *     public MyResourcesProviderImpl() {
+ *         super("java.properties");
+ *     }
+ *     // this provider maps the resource bundle to per-language package
+ *     protected String toBundleName(String baseName, Locale locale) {
+ *         return "p." + locale.getLanguage() + "." + baseName;
+ *     }
+ *
+ *     public ResourceBundle getBundle(String baseName, Locale locale) {
+ *         // this module only provides bundles in French
+ *         if (locale.equals(Locale.FRENCH)) {
+ *              return super.getBundle(baseName, locale);
+ *         }
+ *         // otherwise return null
+ *         return null;
+ *     }
+ * }}
+ * + * This example provides "{@code com.example.app.MyResources}" + * resource bundle of the French locale. Traditionally resource bundles of + * all locales are packaged in the same package as the resource bundle base name. + * When deploying resource bundles in more than one modules and two modules + * containing a package of the same name, split package, + * is not supported, resource bundles in each module can be packaged in + * a different package as shown in this example where this provider packages + * the resource bundles in per-language package, i.e. {@code com.example.app.fr} + * for French locale. * - *

- * This providers's {@link #getBundle(String, Locale) getBundle} method is called - * through the resource bundle loading process instead of {@link - * java.util.ResourceBundle.Control#newBundle(String, Locale, String, ClassLoader, boolean) - * ResourceBundle.Control.newBundle()}. Refer to {@link ResourceBundle} for - * details. + *

A provider can provide more than one services, each of which is a service + * for a resource bundle of a different base name. + * + *

{@link AbstractResourceBundleProvider} + * provides the basic implementation for {@code ResourceBundleProvider} + * and a subclass can override the {@link + * AbstractResourceBundleProvider#toBundleName(String, Locale) toBundleName} + * method to return a provider-specific location of the resource to be loaded, + * for example, per-language package. + * A provider can override {@link #getBundle ResourceBundleProvider.getBundle} + * method for example to only search the known supported locales or + * return resource bundles in other formats such as XML. + * + *

The module declaration of this provider module specifies the following + * directive: + *

+ *     provides com.example.app.spi.MyResourcesProvider with com.example.impl.MyResourcesProviderImpl;
+ * 
+ * + *

Obtaining resource bundles from providers

* - * @see - * Resource Bundles in Named Modules - * @see - * ResourceBundleProvider Service Providers + * The module declaration of the consumer module that calls one of the + * {@code ResourceBundle.getBundle} factory methods to obtain a resource + * bundle from service providers must specify the following directive: + *
+ *     uses com.example.app.spi.MyResourcesProvider;
+ * 
+ * + * {@link ResourceBundle#getBundle(String, Locale) + * ResourceBundle.getBundle("com.example.app.MyResource", locale)} + * locates and loads the providers for {@code com.example.app.spi.MyResourcesProvider} + * service and then invokes {@link #getBundle(String, Locale) + * ResourceBundleProvider.getBundle("com.example.app.MyResource", locale)} to + * find the resource bundle of the given base name and locale. + * If the consumer module is a resource bundle service provider for + * {@code com.example.app.spi.MyResourcesProvider}, {@code ResourceBundle.getBundle} + * will locate resource bundles only from service providers. + * Otherwise, {@code ResourceBundle.getBundle} may continue the search of + * the resource bundle in other modules and class path per the specification + * of the {@code ResourceBundle.getBundle} method being called. + * + * @see AbstractResourceBundleProvider + * @see + * Resource Bundles and Named Modules + * @see java.util.ServiceLoader * @since 9 * @spec JPMS */