changeset 14211:cdaf9fbbbc81

First part of Module#addUses
author alanb
date Fri, 09 Oct 2015 11:09:55 +0100
parents 9e9452626802
children 75c194907490
files src/java.base/share/classes/java/lang/reflect/Module.java src/java.base/share/classes/java/util/ServiceLoader.java
diffstat 2 files changed, 90 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/reflect/Module.java	Fri Oct 09 11:06:54 2015 +0100
+++ b/src/java.base/share/classes/java/lang/reflect/Module.java	Fri Oct 09 11:09:55 2015 +0100
@@ -643,6 +643,92 @@
     }
 
 
+    // -- services --
+
+    // created lazily, additional service types that this module uses
+    private volatile WeakSet<Class<?>> transientUses;
+
+    /**
+     * If the caller's module is this module then update this module to add a
+     * service dependence on the given service type. This method is intended
+     * for use by frameworks that invoke {@link java.util.ServiceLoader
+     * ServiceLoader} on behalf of other modules or where the framework is
+     * passed a reference to the service type by other code.
+     *
+     * <p> This method does not trigger {@link java.lang.module.Configuration#bind
+     * service-binding}. </p>
+     *
+     * @apiNote As this method can only be used to update the caller's module
+     * then this method could be static and the IllegalStateException would
+     * not be needed.
+     *
+     * @return this module
+     *
+     * @throws IllegalStateException
+     *         If this is a named module and the caller is not this module
+     *
+     * @see #canUse(Class)
+     * @see ModuleDescriptor#uses()
+     */
+    @CallerSensitive
+    public Module addUses(Class<?> st) {
+        Objects.requireNonNull(st);
+
+        if (isNamed()) {
+
+            Module caller = Reflection.getCallerClass().getModule();
+            if (caller != this) {
+                throw new IllegalStateException(caller + " != " + this);
+            }
+
+            if (!canUse(st)) {
+                WeakSet<Class<?>> uses = this.transientUses;
+                if (uses == null) {
+                    synchronized (this) {
+                        uses = this.transientUses;
+                        if (uses == null) {
+                            uses = new WeakSet<>();
+                            this.transientUses = uses;
+                        }
+                    }
+                }
+                uses.add(st);
+            }
+
+        }
+
+        return this;
+    }
+
+    /**
+     * Indicates if this module has a service dependence on the given type.
+     *
+     * @return {@code true} if this module uses service type {@code st}
+     *
+     * @see #addUses(Class)
+     */
+    public boolean canUse(Class<?> st) {
+        Objects.requireNonNull(st);
+
+        if (!isNamed())
+            return true;
+
+        if (SharedSecrets.getJavaLangModuleAccess().isAutomatic(descriptor))
+            return true;
+
+        // uses was declared
+        if (descriptor.uses().contains(st.getName()))
+            return true;
+
+        // uses added via addUses
+        WeakSet<Class<?>> uses = this.transientUses;
+        if (uses != null && uses.contains(st))
+            return true;
+
+        return false;
+    }
+
+
 
     // -- packages --
 
--- a/src/java.base/share/classes/java/util/ServiceLoader.java	Fri Oct 09 11:06:54 2015 +0100
+++ b/src/java.base/share/classes/java/util/ServiceLoader.java	Fri Oct 09 11:09:55 2015 +0100
@@ -367,16 +367,10 @@
             fail(svc, "not accessible to " + module);
         }
 
-        // If the caller is in a named module then it must declare that it
-        // uses the service type
-        if (module.isNamed()) {
-            ModuleDescriptor descriptor = module.getDescriptor();
-            if (!SharedSecrets.getJavaLangModuleAccess().isAutomatic(descriptor)) {
-                String sn = svc.getName();
-                if (!module.getDescriptor().uses().contains(sn)) {
-                    fail(svc, "use not declared in " + module);
-                }
-            }
+        // If the caller is in a named module then it should "uses" the
+        // service type
+        if (!module.canUse(svc)) {
+            fail(svc, "use not declared in " + module);
         }
 
     }