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 26 package com.sun.tools.javac.util; 27 28 import java.io.IOException; 29 import java.lang.reflect.InvocationTargetException; 30 import java.lang.reflect.Method; 31 import java.nio.file.Path; 32 import java.util.Collection; 33 import 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 */ 54 public 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 }