JDK9Wrappers.java revision 3653:dd56c243c199
1/*
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package com.sun.tools.javac.util;
27
28import java.lang.reflect.InvocationTargetException;
29import java.lang.reflect.Method;
30import java.nio.file.Path;
31import java.util.Collection;
32import java.util.ServiceLoader;
33
34/**
35 *  This class provides wrappers for classes and methods that are new in JDK 9, and which are not
36 *  available on older versions of the platform on which javac may be compiled and run.
37 *  In future releases, when javac is always compiled on JDK 9 or later, the use of these wrappers
38 *  can be replaced by use of the real underlying classes.
39 *
40 *  <p>Wrapper classes provide a subset of the API of the wrapped classes, as needed for use
41 *  in javac. Wrapper objects contain an {@code Object} reference to the underlying runtime object,
42 *  and {@code Class} and {@code Method} objects for obtaining or using such instances via
43 *  runtime reflection.  The {@code Class} and {@code Method} objects are set up on a per-class
44 *  basis, by an {@code init} method, which is called from static methods on the wrapper class,
45 *  or in the constructor, when instances are created.
46 *  <p>
47 *
48 *  <p><b>This is NOT part of any supported API.
49 *  If you write code that depends on this, you do so at your own risk.
50 *  This code and its internal interfaces are subject to change or
51 *  deletion without notice.</b>
52 */
53public class JDK9Wrappers {
54
55    /**
56     * Helper class for new method in java.util.ServiceLoader.
57     */
58    public static final class ServiceLoaderHelper {
59        @SuppressWarnings("unchecked")
60        public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
61            try {
62                init();
63                Object result = loadMethod.invoke(null, layer.theRealLayer, service);
64                return (ServiceLoader<S>)result;
65            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
66                    | SecurityException ex) {
67                throw new Abort(ex);
68            }
69        }
70
71        // -----------------------------------------------------------------------------------------
72
73        private static Method loadMethod = null;
74
75        private static void init() {
76            if (loadMethod == null) {
77                try {
78                    Class<?> layerClass = Layer.layerClass;
79                    loadMethod = ServiceLoader.class.getDeclaredMethod("load", layerClass, Class.class);
80                } catch (NoSuchMethodException | SecurityException ex) {
81                    throw new Abort(ex);
82                }
83            }
84        }
85    }
86
87    /**
88     * Wrapper class for java.lang.module.ModuleFinder.
89     */
90    public static class ModuleFinder {
91        private final Object theRealModuleFinder;
92
93        private ModuleFinder(Object moduleFinder) {
94            this.theRealModuleFinder = moduleFinder;
95            init();
96        }
97
98        public static ModuleFinder of(Path... dirs) {
99            try {
100                init();
101                Object result = ofMethod.invoke(null, (Object)dirs);
102                ModuleFinder mFinder = new ModuleFinder(result);
103                return mFinder;
104            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
105                    | SecurityException ex) {
106                throw new Abort(ex);
107            }
108        }
109
110        // -----------------------------------------------------------------------------------------
111
112        private static Class<?> moduleFinderClass = null;
113        private static Method ofMethod;
114
115        static final Class<?> getModuleFinderClass() {
116            init();
117            return moduleFinderClass;
118        }
119
120        private static void init() {
121            if (moduleFinderClass == null) {
122                try {
123                    moduleFinderClass = Class.forName("java.lang.module.ModuleFinder", false, null);
124                    ofMethod = moduleFinderClass.getDeclaredMethod("of", Path[].class);
125                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
126                    throw new Abort(ex);
127                }
128            }
129        }
130    }
131
132    /**
133     * Wrapper class for java.lang.reflect.Module. To materialize a handle use the static factory
134     * methods Module#getModule(Class<?>) or Module#getUnnamedModule(ClassLoader).
135     */
136    public static class Module {
137
138        private final Object theRealModule;
139
140        private Module(Object module) {
141            this.theRealModule = module;
142            init();
143        }
144
145        public static Module getModule(Class<?> clazz) {
146            try {
147                init();
148                Object result = getModuleMethod.invoke(clazz, new Object[0]);
149                return new Module(result);
150            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
151                    | SecurityException ex) {
152                throw new Abort(ex);
153            }
154        }
155
156        public static Module getUnnamedModule(ClassLoader classLoader) {
157            try {
158                init();
159                Object result = getUnnamedModuleMethod.invoke(classLoader, new Object[0]);
160                return new Module(result);
161            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
162                    | SecurityException ex) {
163                throw new Abort(ex);
164            }
165        }
166
167        public Module addExports(String pn, Module other) {
168            try {
169                addExportsMethod.invoke(theRealModule, new Object[] { pn, other.theRealModule});
170            } catch (IllegalAccessException | InvocationTargetException ex) {
171                throw new Abort(ex);
172            }
173            return this;
174        }
175
176        public Module addUses(Class<?> st) {
177            try {
178                addUsesMethod.invoke(theRealModule, new Object[] { st });
179            } catch (IllegalAccessException | InvocationTargetException ex) {
180                throw new Abort(ex);
181            }
182            return this;
183        }
184
185        // -----------------------------------------------------------------------------------------
186        // on java.lang.reflect.Module
187        private static Method addExportsMethod = null;
188        // on java.lang.reflect.Module
189        private static Method addUsesMethod = null;
190        // on java.lang.Class
191        private static Method getModuleMethod;
192        // on java.lang.ClassLoader
193        private static Method getUnnamedModuleMethod;
194
195        private static void init() {
196            if (addExportsMethod == null) {
197                try {
198                    Class<?> moduleClass = Class.forName("java.lang.reflect.Module", false, null);
199                    addUsesMethod = moduleClass.getDeclaredMethod("addUses", new Class<?>[] { Class.class });
200                    addExportsMethod = moduleClass.getDeclaredMethod("addExports",
201                                                        new Class<?>[] { String.class, moduleClass });
202                    getModuleMethod = Class.class.getDeclaredMethod("getModule", new Class<?>[0]);
203                    getUnnamedModuleMethod = ClassLoader.class.getDeclaredMethod("getUnnamedModule", new Class<?>[0]);
204                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
205                    throw new Abort(ex);
206                }
207            }
208        }
209    }
210
211    /**
212     * Wrapper class for java.lang.module.Configuration.
213     */
214    public static final class Configuration {
215        private final Object theRealConfiguration;
216
217        private Configuration(Object configuration) {
218            this.theRealConfiguration = configuration;
219            init();
220        }
221
222        public Configuration resolveRequiresAndUses(
223                ModuleFinder beforeFinder,
224                ModuleFinder afterFinder,
225                Collection<String> roots) {
226            try {
227                Object result = resolveRequiresAndUsesMethod.invoke(theRealConfiguration,
228                                    beforeFinder.theRealModuleFinder,
229                                    afterFinder.theRealModuleFinder,
230                                    roots
231                                );
232                Configuration configuration = new Configuration(result);
233                return configuration;
234            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
235                    | SecurityException ex) {
236                throw new Abort(ex);
237            }
238        }
239
240        // -----------------------------------------------------------------------------------------
241
242        private static Class<?> configurationClass = null;
243        private static Method resolveRequiresAndUsesMethod;
244
245        static final Class<?> getConfigurationClass() {
246            init();
247            return configurationClass;
248        }
249
250        private static void init() {
251            if (configurationClass == null) {
252                try {
253                    configurationClass = Class.forName("java.lang.module.Configuration", false, null);
254                    Class<?> moduleFinderInterface = ModuleFinder.getModuleFinderClass();
255                    resolveRequiresAndUsesMethod = configurationClass.getDeclaredMethod("resolveRequiresAndUses",
256                                moduleFinderInterface,
257                                moduleFinderInterface,
258                                Collection.class
259                    );
260                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
261                    throw new Abort(ex);
262                }
263            }
264        }
265    }
266
267    /**
268     * Wrapper class for java.lang.module.Layer.
269     */
270    public static final class Layer {
271        private final Object theRealLayer;
272
273        private Layer(Object layer) {
274            this.theRealLayer = layer;
275        }
276
277        public static Layer boot() {
278            try {
279                init();
280                Object result = bootMethod.invoke(null);
281                Layer layer = new Layer(result);
282                return layer;
283            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
284                    | SecurityException ex) {
285                throw new Abort(ex);
286            }
287        }
288
289        public Configuration configuration() {
290            try {
291                Object result = configurationMethod.invoke(theRealLayer);
292                Configuration configuration = new Configuration(result);
293                return configuration;
294            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
295                    | SecurityException ex) {
296                throw new Abort(ex);
297            }
298        }
299
300        public Layer defineModulesWithOneLoader(Configuration configuration, ClassLoader parentClassLoader) {
301            try {
302                Object result = defineModulesWithOneLoaderMethod.invoke(
303                        theRealLayer, configuration.theRealConfiguration, parentClassLoader);
304                Layer layer = new Layer(result);
305                return layer;
306            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
307                    | SecurityException ex) {
308                throw new Abort(ex);
309            }
310        }
311
312        // -----------------------------------------------------------------------------------------
313
314        private static Class<?> layerClass = null;
315        private static Method bootMethod;
316        private static Method defineModulesWithOneLoaderMethod;
317        private static Method configurationMethod;
318
319        private static void init() {
320            if (layerClass == null) {
321                try {
322                    layerClass = Class.forName("java.lang.reflect.Layer", false, null);
323                    bootMethod = layerClass.getDeclaredMethod("boot");
324                    defineModulesWithOneLoaderMethod = layerClass.getDeclaredMethod("defineModulesWithOneLoader",
325                                Configuration.getConfigurationClass(),
326                                ClassLoader.class);
327                    configurationMethod = layerClass.getDeclaredMethod("configuration");
328                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
329                    throw new Abort(ex);
330                }
331            }
332        }
333    }
334
335
336    /**
337     * Helper class for new method in jdk.internal.misc.VM.
338     */
339    public static final class VMHelper {
340        public static final String VM_CLASSNAME = "jdk.internal.misc.VM";
341
342        @SuppressWarnings("unchecked")
343        public static String[] getRuntimeArguments() {
344            try {
345                init();
346                Object result = getRuntimeArgumentsMethod.invoke(null);
347                return (String[])result;
348            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
349                    | SecurityException ex) {
350                throw new Abort(ex);
351            }
352        }
353
354        // -----------------------------------------------------------------------------------------
355
356        private static Class<?> vmClass = null;
357        private static Method getRuntimeArgumentsMethod = null;
358
359        private static void init() {
360            if (vmClass == null) {
361                try {
362                    vmClass = Class.forName(VM_CLASSNAME, false, null);
363                    getRuntimeArgumentsMethod = vmClass.getDeclaredMethod("getRuntimeArguments");
364                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
365                    throw new Abort(ex);
366                }
367            }
368        }
369    }
370}
371