diff --git a/langtools/make/tools/crules/MutableFieldsAnalyzer.java b/langtools/make/tools/crules/MutableFieldsAnalyzer.java index 538f7827dfa..0b082aca0ba 100644 --- a/langtools/make/tools/crules/MutableFieldsAnalyzer.java +++ b/langtools/make/tools/crules/MutableFieldsAnalyzer.java @@ -105,12 +105,12 @@ public class MutableFieldsAnalyzer extends AbstractCodingRulesAnalyzer { "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"); } } diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java index 4e3f4d78126..6a667bc7f3d 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/JavacFileManager.java @@ -78,6 +78,7 @@ import com.sun.tools.javac.util.ListBuffer; 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 class JavacFileManager extends BaseFileManager implements StandardJavaFil public ServiceLoader getServiceLoader(Location location, Class service) throws IOException { nullCheck(location); nullCheck(service); + Module.getModule(getClass()).addUses(service); if (location.isModuleLocation()) { Collection paths = locations.getLocation(location); ModuleFinder finder = ModuleFinder.of(paths.toArray(new Path[paths.size()])); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 431d5b09ec6..ce066f83a39 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -79,6 +79,7 @@ import com.sun.tools.javac.util.DefinedBy; 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea private final JavacTypes typeUtils; private final JavaCompiler compiler; private final Modules modules; - private final ModuleHelper moduleHelper; private final Types types; /** @@ -227,7 +227,6 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea 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 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea ? 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); diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java index b933ee4b33a..8f3875ae63c 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JDK9Wrappers.java @@ -129,6 +129,85 @@ public class JDK9Wrappers { } } + /** + * 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. */ diff --git a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java index 2b34d095d02..dd0315e837c 100644 --- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java +++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/util/ModuleHelper.java @@ -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 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; - } + 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", - 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 }); - } - - 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 diff --git a/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java b/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java index a80877ed10d..82cff7badab 100644 --- a/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java +++ b/langtools/test/tools/javac/T8003967/DetectMutableStaticFields.java @@ -106,12 +106,12 @@ public class DetectMutableStaticFields { // 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", diff --git a/langtools/test/tools/javac/modules/FileManagerGetServiceLoaderTest.java b/langtools/test/tools/javac/modules/FileManagerGetServiceLoaderTest.java new file mode 100644 index 00000000000..83288987f27 --- /dev/null +++ b/langtools/test/tools/javac/modules/FileManagerGetServiceLoaderTest.java @@ -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"); + } + } +}