changeset 15569:47488e198f22

Improve post-resolution checks to include uses/provides
author alanb
date Tue, 08 Mar 2016 12:39:39 +0000
parents a9f1485296c7
children a562e16994cc
files src/java.base/share/classes/java/lang/module/Configuration.java src/java.base/share/classes/java/lang/module/Resolver.java test/jdk/jigsaw/module/ConfigurationTest.java
diffstat 3 files changed, 176 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/module/Configuration.java	Tue Mar 08 11:19:55 2016 +0000
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Tue Mar 08 12:39:39 2016 +0000
@@ -223,8 +223,12 @@
      *
      *     <li><p> Two or more modules in the configuration export the same
      *     package to a module that reads both. This includes the case where a
-     *     module {@code M} containing package {@code P} reads another module
-     *     that exports {@code P} to {@code M}. </p></li>
+     *     module {@code M} containing package {@code p} reads another module
+     *     that exports {@code p} to {@code M}. </p></li>
+     *
+     *     <li><p> A module {@code M} declares that it "{@code uses p.S}" or
+     *     "{@code provides p.S}" but does not read a module that exports
+     *     package {@code p} to {@code M}. </p></li>
      *
      *     <li><p> Two or more modules in the configuration are specific to
      *     different {@link ModuleDescriptor#osName() operating systems},
--- a/src/java.base/share/classes/java/lang/module/Resolver.java	Tue Mar 08 11:19:55 2016 +0000
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Tue Mar 08 12:39:39 2016 +0000
@@ -825,6 +825,8 @@
      * Checks the readability graph to ensure that no two modules export the
      * same package to a module. This includes the case where module M has
      * a local package P and M reads another module that exports P to M.
+     * Also checks the uses/provides of module M to ensure that it reads a
+     * module that exports the package of the service type to M.
      */
     private void checkExportSuppliers(Map<ReadDependence, Set<ReadDependence>> graph) {
 
@@ -854,7 +856,7 @@
                     // source is exported to descriptor2
                     String source = export.source();
                     ModuleDescriptor other
-                            = packageToExporter.put(source, descriptor2);
+                        = packageToExporter.put(source, descriptor2);
 
                     if (other != null && other != descriptor2) {
                         // package might be local to descriptor1
@@ -878,6 +880,26 @@
                 }
             }
 
+            // uses S
+            for (String service : descriptor1.uses()) {
+                int index = service.lastIndexOf(".");
+                String pn = service.substring(0, index);
+                if (!packageToExporter.containsKey(pn)) {
+                    fail("Module %s does not read a module that exports %s",
+                            descriptor1.name(), pn);
+                }
+            }
+
+            // provides S
+            for (String service : descriptor1.provides().keySet()) {
+                int index = service.lastIndexOf(".");
+                String pn = service.substring(0, index);
+                if (!packageToExporter.containsKey(pn)) {
+                    fail("Module %s does not read a module that exports %s",
+                            descriptor1.name(), pn);
+                }
+            }
+
         }
 
     }
--- a/test/jdk/jigsaw/module/ConfigurationTest.java	Tue Mar 08 11:19:55 2016 +0000
+++ b/test/jdk/jigsaw/module/ConfigurationTest.java	Tue Mar 08 12:39:39 2016 +0000
@@ -441,11 +441,13 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service")
                 .build();
 
         ModuleDescriptor descriptor2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
 
@@ -491,17 +493,20 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service1")
                 .build();
 
         ModuleDescriptor descriptor2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .uses("p.Service2")
                 .provides("p.Service1", "q.Service1Impl")
                 .build();
 
         ModuleDescriptor descriptor3
             = new ModuleDescriptor.Builder("m3")
+                .requires("m1")
                 .provides("p.Service2", "q.Service2Impl")
                 .build();
 
@@ -548,6 +553,7 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service")
                 .build();
 
@@ -561,6 +567,7 @@
 
         ModuleDescriptor descriptor2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
 
@@ -595,12 +602,14 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service")
                 .provides("p.Service", "m1.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .provides("p.Service", "m2.ServiceImpl")
                 .build();
 
@@ -628,11 +637,13 @@
 
         ModuleDescriptor descriptor3
             = new ModuleDescriptor.Builder("m3")
+                .requires("m1")
                 .provides("p.Service", "m3.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor4
             = new ModuleDescriptor.Builder("m4")
+                .requires("m1")
                 .provides("p.Service", "m4.ServiceImpl")
                 .build();
 
@@ -665,13 +676,19 @@
      */
     public void testServiceBindingWithConfigurations3() {
 
+        ModuleDescriptor service
+            = new ModuleDescriptor.Builder("s")
+                .exports("p")
+                .build();
+
         ModuleDescriptor provider_v1
             = new ModuleDescriptor.Builder("p")
                 .version("1.0")
+                .requires("s")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
 
-        ModuleFinder finder1 = ModuleUtils.finderOf(provider_v1);
+        ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1);
 
         Configuration cf1
             = Configuration.resolve(finder1,
@@ -679,19 +696,22 @@
                                     ModuleFinder.empty(),
                                     "p");
 
-        assertTrue(cf1.descriptors().size() == 1);
+        assertTrue(cf1.descriptors().size() == 2);
+        assertTrue(cf1.descriptors().contains(service));
         assertTrue(cf1.descriptors().contains(provider_v1));
         assertTrue(cf1.provides("p.Service").contains(provider_v1));
 
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .requires("s")
                 .uses("p.Service")
                 .build();
 
         ModuleDescriptor provider_v2
             = new ModuleDescriptor.Builder("p")
                 .version("2.0")
+                .requires("s")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
 
@@ -774,16 +794,19 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service")
                 .build();
 
         ModuleDescriptor descriptor2_v1
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
 
         ModuleDescriptor descriptor2_v2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
 
@@ -1009,11 +1032,13 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service")
                 .build();
 
         ModuleDescriptor descriptor2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .requires("m3")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
@@ -1059,10 +1084,12 @@
 
         ModuleDescriptor descriptor1
             = new ModuleDescriptor.Builder("m1")
+                .exports("p")
                 .uses("p.Service")
                 .build();
         ModuleDescriptor descriptor2
             = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
                 .requires("m3")
                 .provides("p.Service", "q.ServiceImpl")
                 .build();
@@ -1196,6 +1223,124 @@
 
 
     /**
+     * Test "uses p.S" where p is a concealed package in the same module.
+     */
+    public void testConcealedService1() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf
+            = Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m1");
+
+        assertTrue(cf.descriptors().size() == 1);
+        assertTrue(cf.descriptors().contains(descriptor1));
+    }
+
+
+    /**
+     * Test "uses p.S" where p is a concealed package in a different module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testConcealedService2() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m2");
+    }
+
+
+    /**
+     * Test "provides p.S" where p is a concealed package in the same module.
+     */
+    public void testConcealedService3() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .provides("p.S", "q.S1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration cf
+            = Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m1");
+
+        assertTrue(cf.descriptors().size() == 1);
+        assertTrue(cf.descriptors().contains(descriptor1));
+        assertTrue(cf.provides("p.S").size() == 1);
+        assertTrue(cf.provides("p.S").contains(descriptor1));
+    }
+
+
+    /**
+     * Test "provides p.S" where p is a concealed package in a different module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testConcealedService4() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .conceals("p")
+                .build();
+
+        ModuleDescriptor descriptor2
+            = new ModuleDescriptor.Builder("m2")
+                .requires("m1")
+                .provides("p.S", "q.S1")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+
+        Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m2");
+    }
+
+
+    /**
+     * Test "uses p.S" where p is not exported to the module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testServiceTypePackageNotExported1() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .uses("p.S")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m1");
+    }
+
+
+    /**
+     * Test "provides p.S" where p is not exported to the module.
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testServiceTypePackageNotExported2() {
+        ModuleDescriptor descriptor1
+            = new ModuleDescriptor.Builder("m1")
+                .provides("p.S", "q.ServiceImpl")
+                .build();
+
+        ModuleFinder finder = ModuleUtils.finderOf(descriptor1);
+
+        Configuration.resolve(finder, empty(), ModuleFinder.empty(), "m1");
+    }
+
+
+    /**
      * Test the empty configuration.
      */
     public void testEmptyConfiguration() {