JDK9Wrappers.java revision 3422:cf4046825175
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.module.Configuration.
134     */
135    public static final class Configuration {
136        private final Object theRealConfiguration;
137
138        private Configuration(Object configuration) {
139            this.theRealConfiguration = configuration;
140            init();
141        }
142
143        public Configuration resolveRequiresAndUses(
144                ModuleFinder beforeFinder,
145                ModuleFinder afterFinder,
146                Collection<String> roots) {
147            try {
148                Object result = resolveRequiresAndUsesMethod.invoke(theRealConfiguration,
149                                    beforeFinder.theRealModuleFinder,
150                                    afterFinder.theRealModuleFinder,
151                                    roots
152                                );
153                Configuration configuration = new Configuration(result);
154                return configuration;
155            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
156                    | SecurityException ex) {
157                throw new Abort(ex);
158            }
159        }
160
161        // -----------------------------------------------------------------------------------------
162
163        private static Class<?> configurationClass = null;
164        private static Method resolveRequiresAndUsesMethod;
165
166        static final Class<?> getConfigurationClass() {
167            init();
168            return configurationClass;
169        }
170
171        private static void init() {
172            if (configurationClass == null) {
173                try {
174                    configurationClass = Class.forName("java.lang.module.Configuration", false, null);
175                    Class<?> moduleFinderInterface = ModuleFinder.getModuleFinderClass();
176                    resolveRequiresAndUsesMethod = configurationClass.getDeclaredMethod("resolveRequiresAndUses",
177                                moduleFinderInterface,
178                                moduleFinderInterface,
179                                Collection.class
180                    );
181                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
182                    throw new Abort(ex);
183                }
184            }
185        }
186    }
187
188    /**
189     * Wrapper class for java.lang.module.Layer.
190     */
191    public static final class Layer {
192        private final Object theRealLayer;
193
194        private Layer(Object layer) {
195            this.theRealLayer = layer;
196        }
197
198        public static Layer boot() {
199            try {
200                init();
201                Object result = bootMethod.invoke(null);
202                Layer layer = new Layer(result);
203                return layer;
204            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
205                    | SecurityException ex) {
206                throw new Abort(ex);
207            }
208        }
209
210        public Configuration configuration() {
211            try {
212                Object result = configurationMethod.invoke(theRealLayer);
213                Configuration configuration = new Configuration(result);
214                return configuration;
215            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
216                    | SecurityException ex) {
217                throw new Abort(ex);
218            }
219        }
220
221        public Layer defineModulesWithOneLoader(Configuration configuration, ClassLoader parentClassLoader) {
222            try {
223                Object result = defineModulesWithOneLoaderMethod.invoke(
224                        theRealLayer, configuration.theRealConfiguration, parentClassLoader);
225                Layer layer = new Layer(result);
226                return layer;
227            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
228                    | SecurityException ex) {
229                throw new Abort(ex);
230            }
231        }
232
233        // -----------------------------------------------------------------------------------------
234
235        private static Class<?> layerClass = null;
236        private static Method bootMethod;
237        private static Method defineModulesWithOneLoaderMethod;
238        private static Method configurationMethod;
239
240        private static void init() {
241            if (layerClass == null) {
242                try {
243                    layerClass = Class.forName("java.lang.reflect.Layer", false, null);
244                    bootMethod = layerClass.getDeclaredMethod("boot");
245                    defineModulesWithOneLoaderMethod = layerClass.getDeclaredMethod("defineModulesWithOneLoader",
246                                Configuration.getConfigurationClass(),
247                                ClassLoader.class);
248                    configurationMethod = layerClass.getDeclaredMethod("configuration");
249                } catch (ClassNotFoundException | NoSuchMethodException | SecurityException ex) {
250                    throw new Abort(ex);
251                }
252            }
253        }
254    }
255}
256