JDK9Wrappers.java revision 4104:4012b3f11f0d
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.io.IOException;
29import java.lang.reflect.InvocationTargetException;
30import java.lang.reflect.Method;
31import java.nio.file.Path;
32import java.util.Collection;
33import java.util.ServiceLoader;
34
35/**
36 *  This class provides wrappers for classes and methods that are new in JDK 9, and which are not
37 *  available on older versions of the platform on which javac may be compiled and run.
38 *  In future releases, when javac is always compiled on JDK 9 or later, the use of these wrappers
39 *  can be replaced by use of the real underlying classes.
40 *
41 *  <p>Wrapper classes provide a subset of the API of the wrapped classes, as needed for use
42 *  in javac. Wrapper objects contain an {@code Object} reference to the underlying runtime object,
43 *  and {@code Class} and {@code Method} objects for obtaining or using such instances via
44 *  runtime reflection.  The {@code Class} and {@code Method} objects are set up on a per-class
45 *  basis, by an {@code init} method, which is called from static methods on the wrapper class,
46 *  or in the constructor, when instances are created.
47 *  <p>
48 *
49 *  <p><b>This is NOT part of any supported API.
50 *  If you write code that depends on this, you do so at your own risk.
51 *  This code and its internal interfaces are subject to change or
52 *  deletion without notice.</b>
53 */
54public class JDK9Wrappers {
55
56    /**
57     * Helper class for new method in java.util.ServiceLoader.
58     */
59    public static final class ServiceLoaderHelper {
60        @SuppressWarnings("unchecked")
61        public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
62            try {
63                init();
64                Object result = loadMethod.invoke(null, layer.theRealLayer, service);
65                return (ServiceLoader<S>)result;
66            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
67                    | SecurityException ex) {
68                throw new Abort(ex);
69            }
70        }
71
72        // -----------------------------------------------------------------------------------------
73
74        private static Method loadMethod = null;
75
76        private static void init() {
77            if (loadMethod == null) {
78                try {
79                    Class<?> layerClass = Layer.layerClass;
80                    loadMethod = ServiceLoader.class.getDeclaredMethod("load", layerClass, Class.class);
81                } catch (NoSuchMethodException | SecurityException ex) {
82                    throw new Abort(ex);
83                }
84            }
85        }
86    }
87
88    /**
89     * Wrapper class for java.lang.module.ModuleDescriptor and ModuleDescriptor.Version.
90     */
91    public static class ModuleDescriptor {
92        public static class Version {
93            public static final String CLASSNAME = "java.lang.module.ModuleDescriptor$Version";
94            private final Object theRealVersion;
95
96            private Version(Object version) {
97                this.theRealVersion = version;
98            }
99
100            public static Version parse(String v) {
101                try {
102                    init();
103                    Object result = parseMethod.invoke(null, v);
104                    Version version = new Version(result);
105                    return version;
106                } catch (InvocationTargetException ex) {
107                    if (ex.getCause() instanceof IllegalArgumentException) {
108                        throw (IllegalArgumentException) ex.getCause();
109                    } else {
110                        throw new Abort(ex);
111                    }
112                } catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
113                    throw new Abort(ex);
114                }
115            }
116
117            @Override
118            public String toString() {
119                return theRealVersion.toString();
120            }
121
122            // -----------------------------------------------------------------------------------------
123
124            private static Class<?> versionClass = null;
125            private static Method parseMethod = null;
126
127            private static void init() {
128                if (versionClass == null) {
129                    try {
130                        versionClass = Class.forName(CLASSNAME, false, null);
131                        parseMethod = versionClass.getDeclaredMethod("parse", String.class);
132                    } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
133                        throw new Abort(ex);
134                    }
135                }
136            }
137        }
138    }
139
140    /**
141     * Wrapper class for java.lang.module.ModuleFinder.
142     */
143    public static class ModuleFinder {
144        private final Object theRealModuleFinder;
145
146        private ModuleFinder(Object moduleFinder) {
147            this.theRealModuleFinder = moduleFinder;
148            init();
149        }
150
151        public static ModuleFinder of(Path... dirs) {
152            try {
153                init();
154                Object result = ofMethod.invoke(null, (Object)dirs);
155                ModuleFinder mFinder = new ModuleFinder(result);
156                return mFinder;
157            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
158                    | SecurityException ex) {
159                throw new Abort(ex);
160            }
161        }
162
163        // -----------------------------------------------------------------------------------------
164
165        private static Class<?> moduleFinderClass = null;
166        private static Method ofMethod;
167
168        static final Class<?> getModuleFinderClass() {
169            init();
170            return moduleFinderClass;
171        }
172
173        private static void init() {
174            if (moduleFinderClass == null) {
175                try {
176                    moduleFinderClass = Class.forName("java.lang.module.ModuleFinder", false, null);
177                    ofMethod = moduleFinderClass.getDeclaredMethod("of", Path[].class);
178                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
179                    throw new Abort(ex);
180                }
181            }
182        }
183    }
184
185    /**
186     * Wrapper class for java.lang.Module. To materialize a handle use the static factory
187     * methods Module#getModule(Class<?>) or Module#getUnnamedModule(ClassLoader).
188     */
189    public static class Module {
190
191        private final Object theRealModule;
192
193        private Module(Object module) {
194            this.theRealModule = module;
195            init();
196        }
197
198        public static Module getModule(Class<?> clazz) {
199            try {
200                init();
201                Object result = getModuleMethod.invoke(clazz, new Object[0]);
202                return new Module(result);
203            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
204                    | SecurityException ex) {
205                throw new Abort(ex);
206            }
207        }
208
209        public static Module getUnnamedModule(ClassLoader classLoader) {
210            try {
211                init();
212                Object result = getUnnamedModuleMethod.invoke(classLoader, new Object[0]);
213                return new Module(result);
214            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
215                    | SecurityException ex) {
216                throw new Abort(ex);
217            }
218        }
219
220        public Module addExports(String pn, Module other) {
221            try {
222                addExportsMethod.invoke(theRealModule, new Object[] { pn, other.theRealModule});
223            } catch (IllegalAccessException | InvocationTargetException ex) {
224                throw new Abort(ex);
225            }
226            return this;
227        }
228
229        public Module addUses(Class<?> st) {
230            try {
231                addUsesMethod.invoke(theRealModule, new Object[] { st });
232            } catch (IllegalAccessException | InvocationTargetException ex) {
233                throw new Abort(ex);
234            }
235            return this;
236        }
237
238        // -----------------------------------------------------------------------------------------
239        // on java.lang.Module
240        private static Method addExportsMethod = null;
241        // on java.lang.Module
242        private static Method addUsesMethod = null;
243        // on java.lang.Class
244        private static Method getModuleMethod;
245        // on java.lang.ClassLoader
246        private static Method getUnnamedModuleMethod;
247
248        private static void init() {
249            if (addExportsMethod == null) {
250                try {
251                    Class<?> moduleClass = Class.forName("java.lang.Module", false, null);
252                    addUsesMethod = moduleClass.getDeclaredMethod("addUses", new Class<?>[] { Class.class });
253                    addExportsMethod = moduleClass.getDeclaredMethod("addExports",
254                                                        new Class<?>[] { String.class, moduleClass });
255                    getModuleMethod = Class.class.getDeclaredMethod("getModule", new Class<?>[0]);
256                    getUnnamedModuleMethod = ClassLoader.class.getDeclaredMethod("getUnnamedModule", new Class<?>[0]);
257                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
258                    throw new Abort(ex);
259                }
260            }
261        }
262    }
263
264    /**
265     * Wrapper class for java.lang.module.Configuration.
266     */
267    public static final class Configuration {
268        private final Object theRealConfiguration;
269
270        private Configuration(Object configuration) {
271            this.theRealConfiguration = configuration;
272            init();
273        }
274
275        public Configuration resolveAndBind(
276                ModuleFinder beforeFinder,
277                ModuleFinder afterFinder,
278                Collection<String> roots) {
279            try {
280                Object result = resolveAndBindMethod.invoke(theRealConfiguration,
281                                    beforeFinder.theRealModuleFinder,
282                                    afterFinder.theRealModuleFinder,
283                                    roots
284                                );
285                Configuration configuration = new Configuration(result);
286                return configuration;
287            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
288                    | SecurityException ex) {
289                throw new Abort(ex);
290            }
291        }
292
293        // -----------------------------------------------------------------------------------------
294
295        private static Class<?> configurationClass = null;
296        private static Method resolveAndBindMethod;
297
298        static final Class<?> getConfigurationClass() {
299            init();
300            return configurationClass;
301        }
302
303        private static void init() {
304            if (configurationClass == null) {
305                try {
306                    configurationClass = Class.forName("java.lang.module.Configuration", false, null);
307                    Class<?> moduleFinderInterface = ModuleFinder.getModuleFinderClass();
308                    resolveAndBindMethod = configurationClass.getDeclaredMethod("resolveAndBind",
309                                moduleFinderInterface,
310                                moduleFinderInterface,
311                                Collection.class
312                    );
313                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
314                    throw new Abort(ex);
315                }
316            }
317        }
318    }
319
320    /**
321     * Wrapper class for java.lang.ModuleLayer.
322     */
323    public static final class Layer {
324        private final Object theRealLayer;
325
326        private Layer(Object layer) {
327            this.theRealLayer = layer;
328        }
329
330        public static Layer boot() {
331            try {
332                init();
333                Object result = bootMethod.invoke(null);
334                Layer layer = new Layer(result);
335                return layer;
336            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
337                    | SecurityException ex) {
338                throw new Abort(ex);
339            }
340        }
341
342        public Configuration configuration() {
343            try {
344                Object result = configurationMethod.invoke(theRealLayer);
345                Configuration configuration = new Configuration(result);
346                return configuration;
347            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
348                    | SecurityException ex) {
349                throw new Abort(ex);
350            }
351        }
352
353        public Layer defineModulesWithOneLoader(Configuration configuration, ClassLoader parentClassLoader) {
354            try {
355                Object result = defineModulesWithOneLoaderMethod.invoke(
356                        theRealLayer, configuration.theRealConfiguration, parentClassLoader);
357                Layer layer = new Layer(result);
358                return layer;
359            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
360                    | SecurityException ex) {
361                throw new Abort(ex);
362            }
363        }
364
365        // -----------------------------------------------------------------------------------------
366
367        private static Class<?> layerClass = null;
368        private static Method bootMethod;
369        private static Method defineModulesWithOneLoaderMethod;
370        private static Method configurationMethod;
371
372        private static void init() {
373            if (layerClass == null) {
374                try {
375                    layerClass = Class.forName("java.lang.ModuleLayer", false, null);
376                    bootMethod = layerClass.getDeclaredMethod("boot");
377                    defineModulesWithOneLoaderMethod = layerClass.getDeclaredMethod("defineModulesWithOneLoader",
378                                Configuration.getConfigurationClass(),
379                                ClassLoader.class);
380                    configurationMethod = layerClass.getDeclaredMethod("configuration");
381                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
382                    throw new Abort(ex);
383                }
384            }
385        }
386    }
387
388
389    /**
390     * Helper class for new method in jdk.internal.misc.VM.
391     */
392    public static final class VMHelper {
393        public static final String CLASSNAME = "jdk.internal.misc.VM";
394
395        @SuppressWarnings("unchecked")
396        public static String[] getRuntimeArguments() {
397            try {
398                init();
399                Object result = getRuntimeArgumentsMethod.invoke(null);
400                return (String[])result;
401            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
402                    | SecurityException ex) {
403                throw new Abort(ex);
404            }
405        }
406
407        // -----------------------------------------------------------------------------------------
408
409        private static Class<?> vmClass = null;
410        private static Method getRuntimeArgumentsMethod = null;
411
412        private static void init() {
413            if (vmClass == null) {
414                try {
415                    vmClass = Class.forName(CLASSNAME, false, null);
416                    getRuntimeArgumentsMethod = vmClass.getDeclaredMethod("getRuntimeArguments");
417                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
418                    throw new Abort(ex);
419                }
420            }
421        }
422    }
423
424    /**
425     * Helper class for new method in jdk.internal.jmod.JmodFile
426     */
427    public static final class JmodFile {
428        public static final String JMOD_FILE_CLASSNAME = "jdk.internal.jmod.JmodFile";
429
430        public static void checkMagic(Path file) throws IOException {
431            try {
432                init();
433                checkMagicMethod.invoke(null, file);
434            } catch (InvocationTargetException ex) {
435                if (ex.getCause() instanceof IOException) {
436                    throw IOException.class.cast(ex.getCause());
437                }
438                throw new Abort(ex);
439            } catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
440                throw new Abort(ex);
441            }
442        }
443
444        // -----------------------------------------------------------------------------------------
445
446        private static Class<?> jmodFileClass = null;
447        private static Method checkMagicMethod = null;
448
449        private static void init() {
450            if (jmodFileClass == null) {
451                try {
452                    jmodFileClass = Class.forName(JMOD_FILE_CLASSNAME, false, null);
453                    checkMagicMethod = jmodFileClass.getDeclaredMethod("checkMagic", Path.class);
454                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
455                    throw new Abort(ex);
456                }
457            }
458        }
459    }
460}
461