--- a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java Tue Mar 15 13:48:30 2016 -0700
+++ b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java Thu Mar 17 19:04:28 2016 +0000
@@ -25,10 +25,11 @@
package javax.tools;
-import java.lang.ref.Reference;
-import java.lang.ref.WeakReference;
-import java.util.HashMap;
-import java.util.Map;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
/**
* Provides methods for locating tool providers, for example,
@@ -40,8 +41,8 @@
*/
public class ToolProvider {
- private static final String systemJavaCompilerName
- = "com.sun.tools.javac.api.JavacTool";
+ private static final String systemJavaCompilerModule = "jdk.compiler";
+ private static final String systemJavaCompilerName = "com.sun.tools.javac.api.JavacTool";
/**
* Returns the Java™ programming language compiler provided
@@ -52,13 +53,17 @@
* {@linkplain java.nio.file.FileSystem filesystem}.</p>
* @return the compiler provided with this platform or
* {@code null} if no compiler is provided
+ * @implNote This implementation returns the compiler provided
+ * by the {@code jdk.compiler} module if that module is available,
+ * and null otherwise.
*/
public static JavaCompiler getSystemJavaCompiler() {
- return instance().getSystemTool(JavaCompiler.class, systemJavaCompilerName);
+ return getSystemTool(JavaCompiler.class,
+ systemJavaCompilerModule, systemJavaCompilerName);
}
- private static final String systemDocumentationToolName
- = "jdk.javadoc.internal.api.JavadocTool";
+ private static final String systemDocumentationToolModule = "jdk.javadoc";
+ private static final String systemDocumentationToolName = "jdk.javadoc.internal.api.JavadocTool";
/**
* Returns the Java™ programming language documentation tool provided
@@ -69,9 +74,13 @@
* {@linkplain java.nio.file.FileSystem filesystem}.</p>
* @return the documentation tool provided with this platform or
* {@code null} if no documentation tool is provided
+ * @implNote This implementation returns the tool provided
+ * by the {@code jdk.javadoc} module if that module is available,
+ * and null otherwise.
*/
public static DocumentationTool getSystemDocumentationTool() {
- return instance().getSystemTool(DocumentationTool.class, systemDocumentationToolName);
+ return getSystemTool(DocumentationTool.class,
+ systemDocumentationToolModule, systemDocumentationToolName);
}
/**
@@ -87,41 +96,70 @@
return ClassLoader.getSystemClassLoader();
}
-
- private static ToolProvider instance;
+ private static final boolean useLegacy;
- private static synchronized ToolProvider instance() {
- if (instance == null)
- instance = new ToolProvider();
- return instance;
+ static {
+ Class<?> c = null;
+ try {
+ c = Class.forName("java.lang.reflect.Module");
+ } catch (Throwable t) {
+ }
+ useLegacy = (c == null);
}
- // Cache for tool classes.
- // Use weak references to avoid keeping classes around unnecessarily
- private final Map<String, Reference<Class<?>>> toolClasses = new HashMap<>();
-
- private ToolProvider() { }
+ /**
+ * Get an instance of a system tool using the service loader.
+ * @implNote By default, this returns the implementation in the specified module.
+ * For limited backward compatibility, if this code is run on an older version
+ * of the Java platform that does not support modules, this method will
+ * try and create an instance of the named class. Note that implies the
+ * class must be available on the system class path.
+ * @param <T> the interface of the tool
+ * @param clazz the interface of the tool
+ * @param moduleName the name of the module containing the desired implementation
+ * @param className the class name of the desired implementation
+ * @return the specified implementation of the tool
+ */
+ private static <T> T getSystemTool(Class<T> clazz, String moduleName, String className) {
+ if (useLegacy) {
+ try {
+ return Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance();
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }
- private <T> T getSystemTool(Class<T> clazz, String name) {
- Class<? extends T> c = getSystemToolClass(clazz, name);
try {
- return c.asSubclass(clazz).newInstance();
- } catch (InstantiationException | IllegalAccessException | RuntimeException | Error e) {
+ ServiceLoader<T> sl = ServiceLoader.load(clazz, ClassLoader.getSystemClassLoader());
+ for (Iterator<T> iter = sl.iterator(); iter.hasNext(); ) {
+ T tool = iter.next();
+ if (matches(tool, moduleName))
+ return tool;
+ }
+ } catch (ServiceConfigurationError e) {
throw new Error(e);
}
+ return null;
}
- private <T> Class<? extends T> getSystemToolClass(Class<T> clazz, String name) {
- Reference<Class<?>> refClass = toolClasses.get(name);
- Class<?> c = (refClass == null ? null : refClass.get());
- if (c == null) {
- try {
- c = Class.forName(name, false, ClassLoader.getSystemClassLoader());
- } catch (ClassNotFoundException | RuntimeException | Error e) {
- throw new Error(e);
- }
- toolClasses.put(name, new WeakReference<>(c));
+ /**
+ * Determine if this is tho desired tool instance.
+ * @param <T> the interface of the tool
+ * @param tool the instance of the tool
+ * @param moduleName the name of the module containing the desired implementation
+ * @return true if and only if the tool matches the specified criteria
+ */
+ private static <T> boolean matches(T tool, String moduleName) {
+ // for now, use reflection to implement
+ // return moduleName.equals(tool.getClass().getModule().getName());
+ try {
+ Method getModuleMethod = Class.class.getDeclaredMethod("getModule");
+ Object toolModule = getModuleMethod.invoke(tool.getClass());
+ Method getNameMethod = toolModule.getClass().getDeclaredMethod("getName");
+ String toolModuleName = (String) getNameMethod.invoke(toolModule);
+ return moduleName.equals(toolModuleName);
+ } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
+ return false;
}
- return c.asSubclass(clazz);
}
}