8164742: ServiceConfigurationError on invoke of getServiceLoader method of StandardJavaFileManager
authorsadayapalam
Mon, 19 Sep 2016 05:31:53 +0530
changeset 41033 49af2ecba616
parent 41032 32be25e34c38
child 41034 f1a27e852c25
8164742: ServiceConfigurationError on invoke of getServiceLoader method of StandardJavaFileManager Reviewed-by: jlahoda
langtools/make/tools/crules/MutableFieldsAnalyzer.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java
langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java
langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java
langtools/test/tools/javac/modules/FileManagerGetServiceLoaderTest.java
--- a/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Fri Sep 16 12:17:44 2016 -0700
+++ b/langtools/make/tools/crules/MutableFieldsAnalyzer.java	Mon Sep 19 05:31:53 2016 +0530
@@ -105,12 +105,12 @@
                 "configurationClass", "resolveRequiresAndUsesMethod");
         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Layer",
                 "layerClass", "bootMethod", "defineModulesWithOneLoaderMethod", "configurationMethod");
+        ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$Module",
+                "addExportsMethod", "addUsesMethod", "getModuleMethod", "getUnnamedModuleMethod");
         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$ServiceLoaderHelper",
                 "loadMethod");
         ignoreFields("com.sun.tools.javac.util.JDK9Wrappers$VMHelper",
                 "vmClass", "getRuntimeArgumentsMethod");
-        ignoreFields("com.sun.tools.javac.util.ModuleHelper",
-                "addExportsMethod", "getUnnamedModuleMethod", "getModuleMethod");
     }
 
 }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Fri Sep 16 12:17:44 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java	Mon Sep 19 05:31:53 2016 +0530
@@ -78,6 +78,7 @@
 import com.sun.tools.javac.util.JDK9Wrappers.Configuration;
 import com.sun.tools.javac.util.JDK9Wrappers.Layer;
 import com.sun.tools.javac.util.JDK9Wrappers.ModuleFinder;
+import com.sun.tools.javac.util.JDK9Wrappers.Module;
 import com.sun.tools.javac.util.JDK9Wrappers.ServiceLoaderHelper;
 
 import static java.nio.file.FileVisitOption.FOLLOW_LINKS;
@@ -957,6 +958,7 @@
     public <S> ServiceLoader<S> getServiceLoader(Location location, Class<S> service) throws IOException {
         nullCheck(location);
         nullCheck(service);
+        Module.getModule(getClass()).addUses(service);
         if (location.isModuleLocation()) {
             Collection<Path> paths = locations.getLocation(location);
             ModuleFinder finder = ModuleFinder.of(paths.toArray(new Path[paths.size()]));
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Fri Sep 16 12:17:44 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Mon Sep 19 05:31:53 2016 +0530
@@ -79,6 +79,7 @@
 import com.sun.tools.javac.util.DefinedBy.Api;
 import com.sun.tools.javac.util.Iterators;
 import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.JDK9Wrappers.Module;
 import com.sun.tools.javac.util.JavacMessages;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.Log;
@@ -119,7 +120,6 @@
     private final JavacTypes typeUtils;
     private final JavaCompiler compiler;
     private final Modules modules;
-    private final ModuleHelper moduleHelper;
     private final Types types;
 
     /**
@@ -227,7 +227,6 @@
         enter = Enter.instance(context);
         initialCompleter = ClassFinder.instance(context).getCompleter();
         chk = Check.instance(context);
-        moduleHelper = ModuleHelper.instance(context);
         initProcessorLoader();
 
         defaultModule = source.allowModules() && options.isUnset("noModules")
@@ -265,7 +264,8 @@
                     ? fileManager.getClassLoader(ANNOTATION_PROCESSOR_PATH)
                     : fileManager.getClassLoader(CLASS_PATH);
 
-                moduleHelper.addExports(processorClassLoader);
+                if (options.isSet("accessInternalAPI"))
+                    ModuleHelper.addExports(Module.getModule(getClass()), Module.getUnnamedModule(processorClassLoader));
 
                 if (processorClassLoader != null && processorClassLoader instanceof Closeable) {
                     compiler.closeables = compiler.closeables.prepend((Closeable) processorClassLoader);
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Fri Sep 16 12:17:44 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java	Mon Sep 19 05:31:53 2016 +0530
@@ -130,6 +130,85 @@
     }
 
     /**
+     * Wrapper class for java.lang.reflect.Module. To materialize a handle use the static factory
+     * methods Module#getModule(Class<?>) or Module#getUnnamedModule(ClassLoader).
+     */
+    public static class Module {
+
+        private final Object theRealModule;
+
+        private Module(Object module) {
+            this.theRealModule = module;
+            init();
+        }
+
+        public static Module getModule(Class<?> clazz) {
+            try {
+                init();
+                Object result = getModuleMethod.invoke(clazz, new Object[0]);
+                return new Module(result);
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        public static Module getUnnamedModule(ClassLoader classLoader) {
+            try {
+                init();
+                Object result = getUnnamedModuleMethod.invoke(classLoader, new Object[0]);
+                return new Module(result);
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
+                    | SecurityException ex) {
+                throw new Abort(ex);
+            }
+        }
+
+        public Module addExports(String pn, Module other) {
+            try {
+                addExportsMethod.invoke(theRealModule, new Object[] { pn, other.theRealModule});
+            } catch (IllegalAccessException | InvocationTargetException ex) {
+                throw new Abort(ex);
+            }
+            return this;
+        }
+
+        public Module addUses(Class<?> st) {
+            try {
+                addUsesMethod.invoke(theRealModule, new Object[] { st });
+            } catch (IllegalAccessException | InvocationTargetException ex) {
+                throw new Abort(ex);
+            }
+            return this;
+        }
+
+        // -----------------------------------------------------------------------------------------
+        // on java.lang.reflect.Module
+        private static Method addExportsMethod = null;
+        // on java.lang.reflect.Module
+        private static Method addUsesMethod = null;
+        // on java.lang.Class
+        private static Method getModuleMethod;
+        // on java.lang.ClassLoader
+        private static Method getUnnamedModuleMethod;
+
+        private static void init() {
+            if (addExportsMethod == null) {
+                try {
+                    Class<?> moduleClass = Class.forName("java.lang.reflect.Module", false, null);
+                    addUsesMethod = moduleClass.getDeclaredMethod("addUses", new Class<?>[] { Class.class });
+                    addExportsMethod = moduleClass.getDeclaredMethod("addExports",
+                                                        new Class<?>[] { String.class, moduleClass });
+                    getModuleMethod = Class.class.getDeclaredMethod("getModule", new Class<?>[0]);
+                    getUnnamedModuleMethod = ClassLoader.class.getDeclaredMethod("getUnnamedModule", new Class<?>[0]);
+                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
+                    throw new Abort(ex);
+                }
+            }
+        }
+    }
+
+    /**
      * Wrapper class for java.lang.module.Configuration.
      */
     public static final class Configuration {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java	Fri Sep 16 12:17:44 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java	Mon Sep 19 05:31:53 2016 +0530
@@ -25,88 +25,30 @@
 
 package com.sun.tools.javac.util;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import com.sun.tools.javac.util.JDK9Wrappers.Module;
 
 public class ModuleHelper {
-    /** The context key for the module helper. */
-    protected static final Context.Key<ModuleHelper> moduleHelperKey = new Context.Key<>();
-
-    /** Get the JavaCompiler instance for this context. */
-    public static ModuleHelper instance(Context context) {
-        ModuleHelper instance = context.get(moduleHelperKey);
-        if (instance == null)
-            instance = new ModuleHelper(context);
-        return instance;
-    }
-
-    public ModuleHelper(Context context) {
-        context.put(moduleHelperKey, this);
-        Options options = Options.instance(context);
-        allowAccessToInternalAPI = options.isSet("accessInternalAPI");
-    }
-
-    final boolean allowAccessToInternalAPI;
 
-    private void exportPackageToModule(String packageName, Object target)
-            throws ClassNotFoundException, NoSuchMethodException, IllegalArgumentException,
-                   InvocationTargetException, IllegalAccessException {
-        if (addExportsMethod == null) {
-            Class<?> moduleClass = Class.forName("java.lang.reflect.Module");
-            addExportsMethod = moduleClass.getDeclaredMethod("addExports",
-                    new Class<?>[] { String.class, moduleClass });
-        }
-        addExportsMethod.invoke(from, new Object[] { packageName, target });
-    }
+    private static final String[] javacInternalPackages = new String[] {
+            "com.sun.tools.javac.api",
+            "com.sun.tools.javac.code",
+            "com.sun.tools.javac.comp",
+            "com.sun.tools.javac.file",
+            "com.sun.tools.javac.jvm",
+            "com.sun.tools.javac.main",
+            "com.sun.tools.javac.model",
+            "com.sun.tools.javac.parser",
+            "com.sun.tools.javac.platform",
+            "com.sun.tools.javac.processing",
+            "com.sun.tools.javac.tree",
+            "com.sun.tools.javac.util",
 
-    static final String[] javacInternalPackages = new String[] {
-        "com.sun.tools.javac.api",
-        "com.sun.tools.javac.code",
-        "com.sun.tools.javac.comp",
-        "com.sun.tools.javac.file",
-        "com.sun.tools.javac.jvm",
-        "com.sun.tools.javac.main",
-        "com.sun.tools.javac.model",
-        "com.sun.tools.javac.parser",
-        "com.sun.tools.javac.platform",
-        "com.sun.tools.javac.processing",
-        "com.sun.tools.javac.tree",
-        "com.sun.tools.javac.util",
-
-        "com.sun.tools.doclint",
+            "com.sun.tools.doclint",
     };
 
-    public void addExports(ClassLoader classLoader) {
-        try {
-            if (allowAccessToInternalAPI) {
-                if (from == null) {
-                    if (getModuleMethod == null) {
-                        getModuleMethod = Class.class.getDeclaredMethod("getModule", new Class<?>[0]);
-                    }
-                    from = getModuleMethod.invoke(getClass(), new Object[0]);
-                }
-                if (getUnnamedModuleMethod == null) {
-                    getUnnamedModuleMethod = ClassLoader.class.getDeclaredMethod("getUnnamedModule", new Class<?>[0]);
-                }
-                Object target = getUnnamedModuleMethod.invoke(classLoader, new Object[0]);
-                for (String pack: javacInternalPackages) {
-                    exportPackageToModule(pack, target);
-                }
-            }
-        } catch (Exception e) {
-            // do nothing
+    public static void addExports(Module from, Module to) {
+        for (String pack: javacInternalPackages) {
+            from.addExports(pack, to);
         }
     }
-
-    // a module instance
-    private Object from = null;
-
-    // on java.lang.reflect.Module
-    private static Method addExportsMethod = null;
-
-    // on java.lang.ClassLoader
-    private static Method getUnnamedModuleMethod = null;
-
-    // on java.lang.Class
-    private static Method getModuleMethod = null;
-}
+}
\ No newline at end of file
--- a/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java	Fri Sep 16 12:17:44 2016 -0700
+++ b/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java	Mon Sep 19 05:31:53 2016 +0530
@@ -106,12 +106,12 @@
         // The following static fields are used for caches of information obtained
         // by reflective lookup, to avoid explicit references that are not available
         // when running javac on JDK 8.
-        ignore("com/sun/tools/javac/util/ModuleHelper",
-                "addExportsMethod", "getModuleMethod", "getUnnamedModuleMethod");
         ignore("com/sun/tools/javac/util/JDK9Wrappers$Configuration",
                 "resolveRequiresAndUsesMethod", "configurationClass");
         ignore("com/sun/tools/javac/util/JDK9Wrappers$Layer",
                 "bootMethod", "defineModulesWithOneLoaderMethod", "configurationMethod", "layerClass");
+        ignore("com/sun/tools/javac/util/JDK9Wrappers$Module",
+                "addExportsMethod", "addUsesMethod", "getModuleMethod", "getUnnamedModuleMethod");
         ignore("com/sun/tools/javac/util/JDK9Wrappers$ModuleFinder",
                 "moduleFinderClass", "ofMethod");
         ignore("com/sun/tools/javac/util/JDK9Wrappers$ServiceLoaderHelper",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/modules/FileManagerGetServiceLoaderTest.java	Mon Sep 19 05:31:53 2016 +0530
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8164742
+ * @summary Test that jdk.compiler can materialize a service loader for arbitrary services
+ * @run main FileManagerGetServiceLoaderTest
+ */
+
+import javax.tools.*;
+
+public class FileManagerGetServiceLoaderTest {
+
+    public static void main(String... args) throws Exception {
+
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);
+
+        /* FileManagerGetServiceLoaderTest.class is not really a service, but that is
+           immaterial to the test which just verifies addUses would have been called
+           so module boundary is not an issue for a class outside of jdk.compiler
+        */
+        java.util.ServiceLoader<?> loader = fm.getServiceLoader(StandardLocation.CLASS_PATH,
+                                     FileManagerGetServiceLoaderTest.class);
+        if (loader == null) {
+            throw new AssertionError("Could not obtain service loader");
+        }
+    }
+}