JDK9Method.java revision 12748:fbb9c8026495
1169695Skan/*
2169695Skan * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3169695Skan * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4169695Skan *
5169695Skan * This code is free software; you can redistribute it and/or modify it
6169695Skan * under the terms of the GNU General Public License version 2 only, as
7169695Skan * published by the Free Software Foundation.
8169695Skan *
9169695Skan * This code is distributed in the hope that it will be useful, but WITHOUT
10169695Skan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11169695Skan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12169695Skan * version 2 for more details (a copy is included in the LICENSE file that
13169695Skan * accompanied this code).
14169695Skan *
15169695Skan * You should have received a copy of the GNU General Public License version
16169695Skan * 2 along with this work; if not, write to the Free Software Foundation,
17169695Skan * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18169695Skan *
19169695Skan * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20169695Skan * or visit www.oracle.com if you need additional information or have any
21169695Skan * questions.
22169695Skan */
23169695Skanpackage org.graalvm.compiler.serviceprovider;
24169695Skan
25169695Skanimport java.lang.reflect.InvocationTargetException;
26169695Skanimport java.lang.reflect.Method;
27169695Skanimport java.lang.reflect.Modifier;
28169695Skan
29169695Skan/**
30169695Skan * Reflection based access to API introduced by JDK 9. This allows the API to be used in code that
31169695Skan * must be compiled on a JDK prior to 9.
32169695Skan */
33169695Skanpublic final class JDK9Method {
34169695Skan
35169695Skan    private static int getJavaSpecificationVersion() {
36169695Skan        String value = System.getProperty("java.specification.version");
37169695Skan        if (value.startsWith("1.")) {
38169695Skan            value = value.substring(2);
39169695Skan        }
40169695Skan        return Integer.parseInt(value);
41169695Skan    }
42169695Skan
43169695Skan    /**
44169695Skan     * The integer value corresponding to the value of the {@code java.specification.version} system
45169695Skan     * property after any leading {@code "1."} has been stripped.
46169695Skan     */
47169695Skan    public static final int JAVA_SPECIFICATION_VERSION = getJavaSpecificationVersion();
48169695Skan
49169695Skan    public JDK9Method(Class<?> declaringClass, String name, Class<?>... parameterTypes) {
50169695Skan        try {
51169695Skan            this.method = declaringClass.getMethod(name, parameterTypes);
52169695Skan        } catch (Exception e) {
53169695Skan            throw new InternalError(e);
54169695Skan        }
55169695Skan    }
56169695Skan
57169695Skan    /**
58169695Skan     * Determines if the Java runtime is version 8 or earlier.
59169695Skan     */
60169695Skan    public static final boolean Java8OrEarlier = JAVA_SPECIFICATION_VERSION <= 8;
61169695Skan
62169695Skan    public final Method method;
63169695Skan
64169695Skan    public Class<?> getReturnType() {
65169695Skan        return method.getReturnType();
66169695Skan    }
67169695Skan
68169695Skan    /**
69     * {@code Class.getModule()}.
70     */
71    public static final JDK9Method getModule;
72
73    /**
74     * {@code java.lang.Module.getPackages()}.
75     */
76    public static final JDK9Method getPackages;
77
78    /**
79     * {@code java.lang.Module.getResourceAsStream(String)}.
80     */
81    public static final JDK9Method getResourceAsStream;
82
83    /**
84     * {@code java.lang.Module.addOpens(String, Module)}.
85     */
86    public static final JDK9Method addOpens;
87
88    /**
89     * {@code java.lang.Module.isOpen(String, Module)}.
90     */
91    public static final JDK9Method isOpenTo;
92
93    /**
94     * Invokes the static Module API method represented by this object.
95     */
96    @SuppressWarnings("unchecked")
97    public <T> T invokeStatic(Object... args) {
98        checkAvailability();
99        assert Modifier.isStatic(method.getModifiers());
100        try {
101            return (T) method.invoke(null, args);
102        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
103            throw new InternalError(e);
104        }
105    }
106
107    /**
108     * Invokes the non-static Module API method represented by this object.
109     */
110    @SuppressWarnings("unchecked")
111    public <T> T invoke(Object receiver, Object... args) {
112        checkAvailability();
113        assert !Modifier.isStatic(method.getModifiers());
114        try {
115            return (T) method.invoke(receiver, args);
116        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
117            throw new InternalError(e);
118        }
119    }
120
121    private void checkAvailability() throws InternalError {
122        if (method == null) {
123            throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
124        }
125    }
126
127    static {
128        if (JAVA_SPECIFICATION_VERSION >= 9) {
129            getModule = new JDK9Method(Class.class, "getModule");
130            Class<?> moduleClass = getModule.getReturnType();
131            getPackages = new JDK9Method(moduleClass, "getPackages");
132            addOpens = new JDK9Method(moduleClass, "addOpens", String.class, moduleClass);
133            getResourceAsStream = new JDK9Method(moduleClass, "getResourceAsStream", String.class);
134            isOpenTo = new JDK9Method(moduleClass, "isOpen", String.class, moduleClass);
135        } else {
136            JDK9Method unavailable = new JDK9Method();
137            getModule = unavailable;
138            getPackages = unavailable;
139            addOpens = unavailable;
140            getResourceAsStream = unavailable;
141            isOpenTo = unavailable;
142        }
143    }
144
145    private JDK9Method() {
146        method = null;
147    }
148}
149