Path: blob/master/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java
41159 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.reflect.misc;2627import java.io.EOFException;28import java.security.AllPermission;29import java.security.AccessController;30import java.security.PermissionCollection;31import java.security.SecureClassLoader;32import java.security.PrivilegedExceptionAction;33import java.security.CodeSource;34import java.io.InputStream;35import java.io.BufferedInputStream;36import java.io.IOException;37import java.net.URL;38import java.net.URLConnection;39import java.lang.reflect.Method;40import java.lang.reflect.InvocationTargetException;41import java.lang.reflect.Modifier;42import java.util.Arrays;43import java.util.HashMap;44import java.util.Map;454647class Trampoline {48static {49if (Trampoline.class.getClassLoader() == null) {50throw new Error(51"Trampoline must not be defined by the bootstrap classloader");52}53}5455@SuppressWarnings("removal")56private static void ensureInvocableMethod(Method m)57throws InvocationTargetException58{59Class<?> clazz = m.getDeclaringClass();60if (clazz.equals(AccessController.class) ||61clazz.equals(Method.class) ||62clazz.getName().startsWith("java.lang.invoke."))63throw new InvocationTargetException(64new UnsupportedOperationException("invocation not supported"));65}6667private static Object invoke(Method m, Object obj, Object[] params)68throws InvocationTargetException, IllegalAccessException69{70ensureInvocableMethod(m);71return m.invoke(obj, params);72}73}7475/*76* Create a trampoline class.77*/78public final class MethodUtil extends SecureClassLoader {79private static final String MISC_PKG = "sun.reflect.misc.";80private static final String TRAMPOLINE = MISC_PKG + "Trampoline";81private static final Method bounce = getTrampoline();8283private MethodUtil() {84super();85}8687public static Method getMethod(Class<?> cls, String name, Class<?>[] args)88throws NoSuchMethodException {89ReflectUtil.checkPackageAccess(cls);90return cls.getMethod(name, args);91}9293public static Method[] getMethods(Class<?> cls) {94ReflectUtil.checkPackageAccess(cls);95return cls.getMethods();96}9798/*99* Discover the public methods on public classes100* and interfaces accessible to any caller by calling101* Class.getMethods() and walking towards Object until102* we're done.103*/104@SuppressWarnings("removal")105public static Method[] getPublicMethods(Class<?> cls) {106// compatibility for update release107if (System.getSecurityManager() == null) {108return cls.getMethods();109}110Map<Signature, Method> sigs = new HashMap<Signature, Method>();111while (cls != null) {112boolean done = getInternalPublicMethods(cls, sigs);113if (done) {114break;115}116getInterfaceMethods(cls, sigs);117cls = cls.getSuperclass();118}119return sigs.values().toArray(new Method[sigs.size()]);120}121122/*123* Process the immediate interfaces of this class or interface.124*/125private static void getInterfaceMethods(Class<?> cls,126Map<Signature, Method> sigs) {127Class<?>[] intfs = cls.getInterfaces();128for (int i=0; i < intfs.length; i++) {129Class<?> intf = intfs[i];130boolean done = getInternalPublicMethods(intf, sigs);131if (!done) {132getInterfaceMethods(intf, sigs);133}134}135}136137/*138*139* Process the methods in this class or interface140*/141private static boolean getInternalPublicMethods(Class<?> cls,142Map<Signature, Method> sigs) {143Method[] methods = null;144try {145/*146* This class or interface is non-public so we147* can't use any of it's methods. Go back and148* try again with a superclass or superinterface.149*/150if (!Modifier.isPublic(cls.getModifiers())) {151return false;152}153if (!ReflectUtil.isPackageAccessible(cls)) {154return false;155}156157methods = cls.getMethods();158} catch (SecurityException se) {159return false;160}161162/*163* Check for inherited methods with non-public164* declaring classes. They might override and hide165* methods from their superclasses or166* superinterfaces.167*/168boolean done = true;169for (int i=0; i < methods.length; i++) {170Class<?> dc = methods[i].getDeclaringClass();171if (!Modifier.isPublic(dc.getModifiers())) {172done = false;173break;174}175}176177if (done) {178/*179* We're done. Spray all the methods into180* the list and then we're out of here.181*/182for (int i=0; i < methods.length; i++) {183addMethod(sigs, methods[i]);184}185} else {186/*187* Simulate cls.getDeclaredMethods() by188* stripping away inherited methods.189*/190for (int i=0; i < methods.length; i++) {191Class<?> dc = methods[i].getDeclaringClass();192if (cls.equals(dc)) {193addMethod(sigs, methods[i]);194}195}196}197return done;198}199200private static void addMethod(Map<Signature, Method> sigs, Method method) {201Signature signature = new Signature(method);202if (!sigs.containsKey(signature)) {203sigs.put(signature, method);204} else if (!method.getDeclaringClass().isInterface()){205/*206* Superclasses beat interfaces.207*/208Method old = sigs.get(signature);209if (old.getDeclaringClass().isInterface()) {210sigs.put(signature, method);211}212}213}214215/**216* A class that represents the unique elements of a method that will be a217* key in the method cache.218*/219private static class Signature {220private final String methodName;221private final Class<?>[] argClasses;222private final int hashCode;223224Signature(Method m) {225this.methodName = m.getName();226this.argClasses = m.getParameterTypes();227this.hashCode = methodName.hashCode() + Arrays.hashCode(argClasses);228}229230@Override public int hashCode() {231return hashCode;232}233234@Override public boolean equals(Object o2) {235if (this == o2) {236return true;237}238Signature that = (Signature)o2;239if (!(methodName.equals(that.methodName))) {240return false;241}242if (argClasses.length != that.argClasses.length) {243return false;244}245for (int i = 0; i < argClasses.length; i++) {246if (!(argClasses[i] == that.argClasses[i])) {247return false;248}249}250return true;251}252}253254255/*256* Bounce through the trampoline.257*/258public static Object invoke(Method m, Object obj, Object[] params)259throws InvocationTargetException, IllegalAccessException {260try {261return bounce.invoke(null, new Object[] {m, obj, params});262} catch (InvocationTargetException ie) {263Throwable t = ie.getCause();264265if (t instanceof InvocationTargetException) {266throw (InvocationTargetException)t;267} else if (t instanceof IllegalAccessException) {268throw (IllegalAccessException)t;269} else if (t instanceof RuntimeException) {270throw (RuntimeException)t;271} else if (t instanceof Error) {272throw (Error)t;273} else {274throw new Error("Unexpected invocation error", t);275}276} catch (IllegalAccessException iae) {277// this can't happen278throw new Error("Unexpected invocation error", iae);279}280}281282@SuppressWarnings("removal")283private static Method getTrampoline() {284try {285return AccessController.doPrivileged(286new PrivilegedExceptionAction<Method>() {287public Method run() throws Exception {288Class<?> t = getTrampolineClass();289Class<?>[] types = {290Method.class, Object.class, Object[].class291};292Method b = t.getDeclaredMethod("invoke", types);293b.setAccessible(true);294return b;295}296});297} catch (Exception e) {298throw new InternalError("bouncer cannot be found", e);299}300}301302303protected synchronized Class<?> loadClass(String name, boolean resolve)304throws ClassNotFoundException305{306// First, check if the class has already been loaded307ReflectUtil.checkPackageAccess(name);308Class<?> c = findLoadedClass(name);309if (c == null) {310try {311c = findClass(name);312} catch (ClassNotFoundException e) {313// Fall through ...314}315if (c == null) {316c = getParent().loadClass(name);317}318}319if (resolve) {320resolveClass(c);321}322return c;323}324325326protected Class<?> findClass(final String name)327throws ClassNotFoundException328{329if (!name.startsWith(MISC_PKG)) {330throw new ClassNotFoundException(name);331}332String path = name.replace('.', '/').concat(".class");333try {334InputStream in = Object.class.getModule().getResourceAsStream(path);335if (in != null) {336try (in) {337byte[] b = in.readAllBytes();338return defineClass(name, b);339}340}341} catch (IOException e) {342throw new ClassNotFoundException(name, e);343}344345throw new ClassNotFoundException(name);346}347348349/*350* Define the proxy classes351*/352private Class<?> defineClass(String name, byte[] b) throws IOException {353CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null);354if (!name.equals(TRAMPOLINE)) {355throw new IOException("MethodUtil: bad name " + name);356}357return defineClass(name, b, 0, b.length, cs);358}359360protected PermissionCollection getPermissions(CodeSource codesource)361{362PermissionCollection perms = super.getPermissions(codesource);363perms.add(new AllPermission());364return perms;365}366367private static Class<?> getTrampolineClass() {368try {369return Class.forName(TRAMPOLINE, true, new MethodUtil());370} catch (ClassNotFoundException e) {371}372return null;373}374375}376377378