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 }