src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/JLModule.java
branchJEP-349-branch
changeset 58343 ca19b94eac7a
parent 58271 e47423f1318b
parent 58341 21a03fa2f6b6
child 58357 fe78b5a87287
equal deleted inserted replaced
58271:e47423f1318b 58343:ca19b94eac7a
     1 /*
       
     2  * Copyright (c) 2016, 2018, 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.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 
       
    25 package org.graalvm.compiler.test;
       
    26 
       
    27 import java.lang.reflect.AccessibleObject;
       
    28 import java.lang.reflect.Method;
       
    29 import java.util.Set;
       
    30 
       
    31 import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
       
    32 
       
    33 /**
       
    34  * Facade for the {@code java.lang.Module} class introduced in JDK9 that allows tests to be
       
    35  * developed against JDK8 but use module logic if deployed on JDK9.
       
    36  */
       
    37 public class JLModule {
       
    38 
       
    39     static {
       
    40         if (JavaVersionUtil.JAVA_SPEC <= 8) {
       
    41             throw new AssertionError("Use of " + JLModule.class + " only allowed if " + GraalTest.class.getName() + ".JDK8OrEarlier is false");
       
    42         }
       
    43     }
       
    44 
       
    45     private final Object realModule;
       
    46 
       
    47     public JLModule(Object module) {
       
    48         this.realModule = module;
       
    49     }
       
    50 
       
    51     private static final Class<?> moduleClass;
       
    52     private static final Method getModuleMethod;
       
    53     private static final Method getUnnamedModuleMethod;
       
    54     private static final Method getPackagesMethod;
       
    55     private static final Method isExportedMethod;
       
    56     private static final Method isExported2Method;
       
    57     private static final Method addExportsMethod;
       
    58     /**
       
    59      * {@code jdk.internal.module.Modules.addExports(Module, String, Module)}.
       
    60      */
       
    61     private static final Method modulesAddExportsMethod;
       
    62 
       
    63     /**
       
    64      * {@code jdk.internal.module.Modules.addOpens(Module, String, Module)}.
       
    65      */
       
    66     private static final Method modulesAddOpensMethod;
       
    67 
       
    68     static {
       
    69         try {
       
    70             moduleClass = Class.forName("java.lang.Module");
       
    71             Class<?> modulesClass = Class.forName("jdk.internal.module.Modules");
       
    72             getModuleMethod = Class.class.getMethod("getModule");
       
    73             getUnnamedModuleMethod = ClassLoader.class.getMethod("getUnnamedModule");
       
    74             getPackagesMethod = moduleClass.getMethod("getPackages");
       
    75             isExportedMethod = moduleClass.getMethod("isExported", String.class);
       
    76             isExported2Method = moduleClass.getMethod("isExported", String.class, moduleClass);
       
    77             addExportsMethod = moduleClass.getMethod("addExports", String.class, moduleClass);
       
    78             modulesAddExportsMethod = modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass);
       
    79             modulesAddOpensMethod = modulesClass.getDeclaredMethod("addOpens", moduleClass, String.class, moduleClass);
       
    80         } catch (Exception e) {
       
    81             throw new AssertionError(e);
       
    82         }
       
    83     }
       
    84 
       
    85     public static JLModule fromClass(Class<?> cls) {
       
    86         try {
       
    87             return new JLModule(getModuleMethod.invoke(cls));
       
    88         } catch (Exception e) {
       
    89             throw new AssertionError(e);
       
    90         }
       
    91     }
       
    92 
       
    93     public static JLModule getUnnamedModuleFor(ClassLoader cl) {
       
    94         try {
       
    95             return new JLModule(getUnnamedModuleMethod.invoke(cl));
       
    96         } catch (Exception e) {
       
    97             throw new AssertionError(e);
       
    98         }
       
    99     }
       
   100 
       
   101     /**
       
   102      * Exports all packages in this module to a given module.
       
   103      */
       
   104     public void exportAllPackagesTo(JLModule module) {
       
   105         if (this != module) {
       
   106             for (String pkg : getPackages()) {
       
   107                 // Export all JVMCI packages dynamically instead
       
   108                 // of requiring a long list of -XaddExports
       
   109                 // options on the JVM command line.
       
   110                 if (!isExported(pkg, module)) {
       
   111                     addExports(pkg, module);
       
   112                 }
       
   113             }
       
   114         }
       
   115     }
       
   116 
       
   117     @SuppressWarnings("unchecked")
       
   118     public Set<String> getPackages() {
       
   119         try {
       
   120             return (Set<String>) getPackagesMethod.invoke(realModule);
       
   121         } catch (Exception e) {
       
   122             throw new AssertionError(e);
       
   123         }
       
   124     }
       
   125 
       
   126     public boolean isExported(String pn) {
       
   127         try {
       
   128             return (Boolean) isExportedMethod.invoke(realModule, pn);
       
   129         } catch (Exception e) {
       
   130             throw new AssertionError(e);
       
   131         }
       
   132     }
       
   133 
       
   134     public boolean isExported(String pn, JLModule other) {
       
   135         try {
       
   136             return (Boolean) isExported2Method.invoke(realModule, pn, other.realModule);
       
   137         } catch (Exception e) {
       
   138             throw new AssertionError(e);
       
   139         }
       
   140     }
       
   141 
       
   142     public void addExports(String pn, JLModule other) {
       
   143         try {
       
   144             addExportsMethod.invoke(realModule, pn, other.realModule);
       
   145         } catch (Exception e) {
       
   146             throw new AssertionError(e);
       
   147         }
       
   148     }
       
   149 
       
   150     private static Object unbox(Object obj) {
       
   151         if (obj instanceof JLModule) {
       
   152             return ((JLModule) obj).realModule;
       
   153         }
       
   154         return obj;
       
   155     }
       
   156 
       
   157     /**
       
   158      * Updates module m1 to export a package to module m2. Same as m1.addExports(pn, m2) but without
       
   159      * a caller check
       
   160      */
       
   161     public static void uncheckedAddExports(Object m1, String pn, Object m2) {
       
   162         try {
       
   163             modulesAddExportsMethod.invoke(null, unbox(m1), pn, unbox(m2));
       
   164         } catch (Exception e) {
       
   165             throw new AssertionError(e);
       
   166         }
       
   167     }
       
   168 
       
   169     /**
       
   170      * Opens all packages in {@code moduleMember}'s module for deep reflection (i.e., allow
       
   171      * {@link AccessibleObject#setAccessible(boolean)} to be called for any class/method/field) by
       
   172      * {@code requestor}'s module.
       
   173      */
       
   174     public static void openAllPackagesForReflectionTo(Class<?> moduleMember, Class<?> requestor) {
       
   175         try {
       
   176             Object moduleToOpen = getModuleMethod.invoke(moduleMember);
       
   177             Object requestorModule = getModuleMethod.invoke(requestor);
       
   178             if (moduleToOpen != requestorModule) {
       
   179                 String[] packages = (String[]) getPackagesMethod.invoke(moduleToOpen);
       
   180                 for (String pkg : packages) {
       
   181                     modulesAddOpensMethod.invoke(moduleToOpen, pkg, requestorModule);
       
   182                 }
       
   183             }
       
   184         } catch (Exception e) {
       
   185             throw new AssertionError(e);
       
   186         }
       
   187     }
       
   188 
       
   189     /**
       
   190      * Opens {@code declaringClass}'s package to allow a method declared in {@code accessor} to call
       
   191      * {@link AccessibleObject#setAccessible(boolean)} on an {@link AccessibleObject} representing a
       
   192      * field or method declared by {@code declaringClass}.
       
   193      */
       
   194     public static void openForReflectionTo(Class<?> declaringClass, Class<?> accessor) {
       
   195         try {
       
   196             Object moduleToOpen = getModuleMethod.invoke(declaringClass);
       
   197             Object accessorModule = getModuleMethod.invoke(accessor);
       
   198             if (moduleToOpen != accessorModule) {
       
   199                 modulesAddOpensMethod.invoke(null, moduleToOpen, declaringClass.getPackage().getName(), accessorModule);
       
   200             }
       
   201         } catch (Exception e) {
       
   202             throw new AssertionError(e);
       
   203         }
       
   204     }
       
   205 
       
   206     /**
       
   207      * Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
       
   208      * {@code requestor}'s module.
       
   209      */
       
   210     public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
       
   211         try {
       
   212             Object moduleToExport = getModuleMethod.invoke(moduleMember);
       
   213             Object requestorModule = getModuleMethod.invoke(requestor);
       
   214             if (moduleToExport != requestorModule) {
       
   215                 modulesAddExportsMethod.invoke(null, moduleToExport, packageName, requestorModule);
       
   216             }
       
   217         } catch (Exception e) {
       
   218             throw new AssertionError(e);
       
   219         }
       
   220     }
       
   221 }