1/* 2 * Copyright (c) 2005, 2013, 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 26package sun.reflect.misc; 27 28import java.io.EOFException; 29import java.security.AllPermission; 30import java.security.AccessController; 31import java.security.PermissionCollection; 32import java.security.SecureClassLoader; 33import java.security.PrivilegedExceptionAction; 34import java.security.CodeSource; 35import java.io.InputStream; 36import java.io.BufferedInputStream; 37import java.io.IOException; 38import java.net.URL; 39import java.net.URLConnection; 40import java.lang.reflect.Method; 41import java.lang.reflect.InvocationTargetException; 42import java.lang.reflect.Modifier; 43import java.util.Arrays; 44import java.util.HashMap; 45import java.util.Map; 46 47 48class Trampoline { 49 static { 50 if (Trampoline.class.getClassLoader() == null) { 51 throw new Error( 52 "Trampoline must not be defined by the bootstrap classloader"); 53 } 54 } 55 56 private static void ensureInvocableMethod(Method m) 57 throws InvocationTargetException 58 { 59 Class<?> clazz = m.getDeclaringClass(); 60 if (clazz.equals(AccessController.class) || 61 clazz.equals(Method.class) || 62 clazz.getName().startsWith("java.lang.invoke.")) 63 throw new InvocationTargetException( 64 new UnsupportedOperationException("invocation not supported")); 65 } 66 67 private static Object invoke(Method m, Object obj, Object[] params) 68 throws InvocationTargetException, IllegalAccessException 69 { 70 ensureInvocableMethod(m); 71 return m.invoke(obj, params); 72 } 73} 74 75/* 76 * Create a trampoline class. 77 */ 78public final class MethodUtil extends SecureClassLoader { 79 private static final String MISC_PKG = "sun.reflect.misc."; 80 private static final String TRAMPOLINE = MISC_PKG + "Trampoline"; 81 private static final Method bounce = getTrampoline(); 82 83 private MethodUtil() { 84 super(); 85 } 86 87 public static Method getMethod(Class<?> cls, String name, Class<?>[] args) 88 throws NoSuchMethodException { 89 ReflectUtil.checkPackageAccess(cls); 90 return cls.getMethod(name, args); 91 } 92 93 public static Method[] getMethods(Class<?> cls) { 94 ReflectUtil.checkPackageAccess(cls); 95 return cls.getMethods(); 96 } 97 98 /* 99 * Discover the public methods on public classes 100 * and interfaces accessible to any caller by calling 101 * Class.getMethods() and walking towards Object until 102 * we're done. 103 */ 104 public static Method[] getPublicMethods(Class<?> cls) { 105 // compatibility for update release 106 if (System.getSecurityManager() == null) { 107 return cls.getMethods(); 108 } 109 Map<Signature, Method> sigs = new HashMap<Signature, Method>(); 110 while (cls != null) { 111 boolean done = getInternalPublicMethods(cls, sigs); 112 if (done) { 113 break; 114 } 115 getInterfaceMethods(cls, sigs); 116 cls = cls.getSuperclass(); 117 } 118 return sigs.values().toArray(new Method[sigs.size()]); 119 } 120 121 /* 122 * Process the immediate interfaces of this class or interface. 123 */ 124 private static void getInterfaceMethods(Class<?> cls, 125 Map<Signature, Method> sigs) { 126 Class<?>[] intfs = cls.getInterfaces(); 127 for (int i=0; i < intfs.length; i++) { 128 Class<?> intf = intfs[i]; 129 boolean done = getInternalPublicMethods(intf, sigs); 130 if (!done) { 131 getInterfaceMethods(intf, sigs); 132 } 133 } 134 } 135 136 /* 137 * 138 * Process the methods in this class or interface 139 */ 140 private static boolean getInternalPublicMethods(Class<?> cls, 141 Map<Signature, Method> sigs) { 142 Method[] methods = null; 143 try { 144 /* 145 * This class or interface is non-public so we 146 * can't use any of it's methods. Go back and 147 * try again with a superclass or superinterface. 148 */ 149 if (!Modifier.isPublic(cls.getModifiers())) { 150 return false; 151 } 152 if (!ReflectUtil.isPackageAccessible(cls)) { 153 return false; 154 } 155 156 methods = cls.getMethods(); 157 } catch (SecurityException se) { 158 return false; 159 } 160 161 /* 162 * Check for inherited methods with non-public 163 * declaring classes. They might override and hide 164 * methods from their superclasses or 165 * superinterfaces. 166 */ 167 boolean done = true; 168 for (int i=0; i < methods.length; i++) { 169 Class<?> dc = methods[i].getDeclaringClass(); 170 if (!Modifier.isPublic(dc.getModifiers())) { 171 done = false; 172 break; 173 } 174 } 175 176 if (done) { 177 /* 178 * We're done. Spray all the methods into 179 * the list and then we're out of here. 180 */ 181 for (int i=0; i < methods.length; i++) { 182 addMethod(sigs, methods[i]); 183 } 184 } else { 185 /* 186 * Simulate cls.getDeclaredMethods() by 187 * stripping away inherited methods. 188 */ 189 for (int i=0; i < methods.length; i++) { 190 Class<?> dc = methods[i].getDeclaringClass(); 191 if (cls.equals(dc)) { 192 addMethod(sigs, methods[i]); 193 } 194 } 195 } 196 return done; 197 } 198 199 private static void addMethod(Map<Signature, Method> sigs, Method method) { 200 Signature signature = new Signature(method); 201 if (!sigs.containsKey(signature)) { 202 sigs.put(signature, method); 203 } else if (!method.getDeclaringClass().isInterface()){ 204 /* 205 * Superclasses beat interfaces. 206 */ 207 Method old = sigs.get(signature); 208 if (old.getDeclaringClass().isInterface()) { 209 sigs.put(signature, method); 210 } 211 } 212 } 213 214 /** 215 * A class that represents the unique elements of a method that will be a 216 * key in the method cache. 217 */ 218 private static class Signature { 219 private final String methodName; 220 private final Class<?>[] argClasses; 221 private final int hashCode; 222 223 Signature(Method m) { 224 this.methodName = m.getName(); 225 this.argClasses = m.getParameterTypes(); 226 this.hashCode = methodName.hashCode() + Arrays.hashCode(argClasses); 227 } 228 229 @Override public int hashCode() { 230 return hashCode; 231 } 232 233 @Override public boolean equals(Object o2) { 234 if (this == o2) { 235 return true; 236 } 237 Signature that = (Signature)o2; 238 if (!(methodName.equals(that.methodName))) { 239 return false; 240 } 241 if (argClasses.length != that.argClasses.length) { 242 return false; 243 } 244 for (int i = 0; i < argClasses.length; i++) { 245 if (!(argClasses[i] == that.argClasses[i])) { 246 return false; 247 } 248 } 249 return true; 250 } 251 } 252 253 254 /* 255 * Bounce through the trampoline. 256 */ 257 public static Object invoke(Method m, Object obj, Object[] params) 258 throws InvocationTargetException, IllegalAccessException { 259 try { 260 return bounce.invoke(null, new Object[] {m, obj, params}); 261 } catch (InvocationTargetException ie) { 262 Throwable t = ie.getCause(); 263 264 if (t instanceof InvocationTargetException) { 265 throw (InvocationTargetException)t; 266 } else if (t instanceof IllegalAccessException) { 267 throw (IllegalAccessException)t; 268 } else if (t instanceof RuntimeException) { 269 throw (RuntimeException)t; 270 } else if (t instanceof Error) { 271 throw (Error)t; 272 } else { 273 throw new Error("Unexpected invocation error", t); 274 } 275 } catch (IllegalAccessException iae) { 276 // this can't happen 277 throw new Error("Unexpected invocation error", iae); 278 } 279 } 280 281 private static Method getTrampoline() { 282 try { 283 return AccessController.doPrivileged( 284 new PrivilegedExceptionAction<Method>() { 285 public Method run() throws Exception { 286 Class<?> t = getTrampolineClass(); 287 Class<?>[] types = { 288 Method.class, Object.class, Object[].class 289 }; 290 Method b = t.getDeclaredMethod("invoke", types); 291 b.setAccessible(true); 292 return b; 293 } 294 }); 295 } catch (Exception e) { 296 throw new InternalError("bouncer cannot be found", e); 297 } 298 } 299 300 301 protected synchronized Class<?> loadClass(String name, boolean resolve) 302 throws ClassNotFoundException 303 { 304 // First, check if the class has already been loaded 305 ReflectUtil.checkPackageAccess(name); 306 Class<?> c = findLoadedClass(name); 307 if (c == null) { 308 try { 309 c = findClass(name); 310 } catch (ClassNotFoundException e) { 311 // Fall through ... 312 } 313 if (c == null) { 314 c = getParent().loadClass(name); 315 } 316 } 317 if (resolve) { 318 resolveClass(c); 319 } 320 return c; 321 } 322 323 324 protected Class<?> findClass(final String name) 325 throws ClassNotFoundException 326 { 327 if (!name.startsWith(MISC_PKG)) { 328 throw new ClassNotFoundException(name); 329 } 330 String path = name.replace('.', '/').concat(".class"); 331 try { 332 InputStream in = Object.class.getModule().getResourceAsStream(path); 333 if (in != null) { 334 try (in) { 335 byte[] b = in.readAllBytes(); 336 return defineClass(name, b); 337 } 338 } 339 } catch (IOException e) { 340 throw new ClassNotFoundException(name, e); 341 } 342 343 throw new ClassNotFoundException(name); 344 } 345 346 347 /* 348 * Define the proxy classes 349 */ 350 private Class<?> defineClass(String name, byte[] b) throws IOException { 351 CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null); 352 if (!name.equals(TRAMPOLINE)) { 353 throw new IOException("MethodUtil: bad name " + name); 354 } 355 return defineClass(name, b, 0, b.length, cs); 356 } 357 358 protected PermissionCollection getPermissions(CodeSource codesource) 359 { 360 PermissionCollection perms = super.getPermissions(codesource); 361 perms.add(new AllPermission()); 362 return perms; 363 } 364 365 private static Class<?> getTrampolineClass() { 366 try { 367 return Class.forName(TRAMPOLINE, true, new MethodUtil()); 368 } catch (ClassNotFoundException e) { 369 } 370 return null; 371 } 372 373} 374